diff --git a/.gitignore b/.gitignore index 37682841d..c6762b15b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ tags TAGS cscope.* *.patch +*.orig # Object files and libraries *.[oa] diff --git a/AStatement.cc b/AStatement.cc index 3cd9b0c4a..10edca65f 100644 --- a/AStatement.cc +++ b/AStatement.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/AStatement.h b/AStatement.h index a02e6d099..ebff58e8d 100644 --- a/AStatement.h +++ b/AStatement.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/Attrib.cc b/Attrib.cc index b2565dfe5..9e3f76cdc 100644 --- a/Attrib.cc +++ b/Attrib.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/Attrib.h b/Attrib.h index 63691ecc5..55548ec7b 100644 --- a/Attrib.h +++ b/Attrib.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "StringHeap.h" diff --git a/COPYING b/COPYING index 916d1f0f2..bdf2192ea 100644 --- a/COPYING +++ b/COPYING @@ -2,7 +2,8 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -305,7 +306,7 @@ the "copyright" line and a pointer to where the full notice is found. 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 + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Also add information on how to contact you by electronic and paper mail. diff --git a/HName.cc b/HName.cc index 15fdcc774..709528489 100644 --- a/HName.cc +++ b/HName.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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -31,21 +31,19 @@ hname_t::hname_t() } hname_t::hname_t(perm_string text) +: name_(text) { - name_ = text; number_ = INT_MIN; } hname_t::hname_t(perm_string text, int num) +: name_(text), number_(num) { - name_ = text; - number_ = num; } hname_t::hname_t(const hname_t&that) +: name_(that.name_), number_(that.number_) { - name_ = that.name_; - number_ = that.number_; } hname_t& hname_t::operator = (const hname_t&that) diff --git a/HName.h b/HName.h index 2409a356a..ce561f8f0 100644 --- a/HName.h +++ b/HName.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/Makefile.in b/Makefile.in index 7bd62d4f1..d231f2669 100644 --- a/Makefile.in +++ b/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh @@ -87,7 +86,7 @@ GIT = @GIT@ ifeq (@srcdir@,.) INCLUDE_PATH = -I. -Ilibmisc else -INCLUDE_PATH = -I. -Ilibmisc -I$(srcdir) -I$(srcdir)/libmisc +INCLUDE_PATH = -I. -I$(srcdir) -I$(srcdir)/libmisc endif CPPFLAGS = @DEFS@ $(INCLUDE_PATH) @CPPFLAGS@ @@ -95,6 +94,7 @@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ PICFLAGS = @PICFLAG@ LDFLAGS = @rdynamic@ @LDFLAGS@ +CTARGETFLAGS = @CTARGETFLAGS@ # Source files in the libmisc directory M = LineInfo.o StringHeap.o @@ -104,17 +104,20 @@ FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ elab_expr.o elaborate_analog.o elab_lval.o elab_net.o \ - elab_scope.o elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \ + elab_scope.o elab_sig.o elab_sig_analog.o elab_type.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 netstruct.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ + load_module.o netlist.o netmisc.o nettypes.o net_analog.o net_assign.o \ + net_design.o netclass.o netdarray.o \ + netenum.o netparray.o netstruct.o netvector.o net_event.o net_expr.o net_func.o \ + net_func_eval.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_pclass.o pform_struct_type.o \ - pform_types.o \ + pform_disciplines.o pform_dump.o pform_package.o pform_pclass.o \ + pform_class_type.o pform_string_type.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 PClass.o PDelays.o PEvent.o PExpr.o PGate.o \ - PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \ + PGenerate.o PPackage.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \ Statement.o AStatement.o $M $(FF) $(TT) all: dep config.h _pli_types.h version_tag.h ivl@EXEEXT@ version.exe iverilog-vpi.man @@ -170,8 +173,8 @@ endif rm -rf autom4te.cache cppcheck: $(O:.o=.cc) $(srcdir)/dosify.c $(srcdir)/version.c - cppcheck --enable=all -f --suppressions $(srcdir)/cppcheck.sup \ - $(INCLUDE_PATH) $^ + cppcheck --enable=all -f --suppressions-list=$(srcdir)/cppcheck.sup \ + --relative-paths=$(srcdir) $(INCLUDE_PATH) $^ cppcheck-all: $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) cppcheck && ) true @@ -226,6 +229,7 @@ iverilog-vpi: $(srcdir)/iverilog-vpi.sh Makefile -e 's;@IVCXX@;$(CXX);' \ -e 's;@IVCFLAGS@;$(CFLAGS);' \ -e 's;@IVCXXFLAGS@;$(CXXFLAGS);' \ + -e 's;@IVCTARGETFLAGS@;$(CTARGETFLAGS);' \ -e 's;@INCLUDEDIR@;$(includedir);' \ -e 's;@LIBDIR@;@libdir@;' $< > $@ chmod +x $@ @@ -377,7 +381,7 @@ uninstall: do rm -f "$(DESTDIR)$(bindir)/$$f"; done for f in ivl_target.h vpi_user.h _pli_types.h sv_vpi_user.h acc_user.h veriuser.h; \ do rm -f "$(DESTDIR)$(includedir)/$$f"; done - -test X$(suffix) = X || rmdir "$(DESTDIR)/$(includedir)" + -test X$(suffix) = X || rmdir "$(DESTDIR)$(includedir)" rm -f "$(DESTDIR)$(mandir)/man1/iverilog-vpi$(suffix).1" "$(DESTDIR)$(prefix)/iverilog-vpi$(suffix).pdf" diff --git a/Module.cc b/Module.cc index 66efe26b0..7c69204c8 100644 --- a/Module.cc +++ b/Module.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -27,11 +27,12 @@ list Module::user_defparms; /* n is a permallocated string. */ -Module::Module(perm_string n) -: PScopeExtra(n) +Module::Module(LexicalScope*parent, perm_string n) +: PScopeExtra(n, parent) { library_flag = false; is_cell = false; + program_block = false; uc_drive = UCD_NONE; timescale_warn_done = false; time_unit = 0; @@ -89,6 +90,22 @@ unsigned Module::find_port(const char*name) const return ports.size(); } +perm_string Module::get_port_name(unsigned idx) const +{ + + assert(idx < ports.size()); + if (ports[idx] == 0) { + /* It is possible to have undeclared ports. These + are ports that are skipped in the declaration, + for example like so: module foo(x ,, y); The + port between x and y is unnamed and thus + inaccessible to binding by name. */ + return perm_string::literal(""); + } + return ports[idx]->name; +} + + PGate* Module::get_gate(perm_string name) { diff --git a/Module.h b/Module.h index a791a6be2..2a53f3690 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ #ifndef __Module_H #define __Module_H /* - * Copyright (c) 1998-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -65,7 +65,7 @@ class Module : public PScopeExtra, public LineInfo { public: /* The name passed here is the module name, not the instance name. This make must be a permallocated string. */ - explicit Module(perm_string name); + explicit Module(LexicalScope*parent, perm_string name); ~Module(); /* Initially false. This is set to true if the module has been @@ -76,13 +76,18 @@ class Module : public PScopeExtra, public LineInfo { bool is_cell; + /* This is true if the module represents a program block + instead of a module/cell. Program blocks have content + restrictions and slightly modify scheduling semantics. */ + bool program_block; + enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 }; UCDriveType uc_drive; - /* specparams are simpler than other params, in that they have - no type information. They are merely constant - expressions. */ - mapspecparams; + /* specparams are simpler than other parameters, in that they + can have a range, but not an explicit type. The restrictions + are enforced by the parser. */ + mapspecparams; /* The module also has defparam assignments which don't create new parameters within the module, but may be used to set @@ -116,6 +121,10 @@ class Module : public PScopeExtra, public LineInfo { the module definition. These are used at elaboration time. */ list generate_schemes; + /* Nested modules are placed here, and are not elaborated + unless they are instantiated, implicitly or explicitly. */ + std::map nested_modules; + list specify_paths; // The mod_name() is the name of the module type. @@ -127,6 +136,9 @@ class Module : public PScopeExtra, public LineInfo { const vector& get_port(unsigned idx) const; unsigned find_port(const char*name) const; + // Return port name ("" for undeclared port) + perm_string get_port_name(unsigned idx) const; + PGate* get_gate(perm_string name); const list& get_gates() const; @@ -140,6 +152,7 @@ class Module : public PScopeExtra, public LineInfo { bool elaborate_sig(Design*, NetScope*scope) const; private: + void dump_specparams_(ostream&out, unsigned indent) const; list gates_; private: // Not implemented diff --git a/PClass.cc b/PClass.cc index 9a9a62355..45da536ce 100644 --- a/PClass.cc +++ b/PClass.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "PClass.h" diff --git a/PClass.h b/PClass.h index b4578ad68..ec5440468 100644 --- a/PClass.h +++ b/PClass.h @@ -16,12 +16,13 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "PScope.h" # include "LineInfo.h" # include "StringHeap.h" +# include /* * SystemVerilog supports class declarations with their own lexical @@ -35,6 +36,10 @@ class PClass : public PScopeExtra, public LineInfo { explicit PClass (perm_string name, LexicalScope*parent); ~PClass(); + void dump(std::ostream&out, unsigned indent) const; + + public: + class_type_t*type; }; #endif diff --git a/PDelays.cc b/PDelays.cc index b7cecf0c6..5fd72a37b 100644 --- a/PDelays.cc +++ b/PDelays.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/PDelays.h b/PDelays.h index 00e061807..7ecefd984 100644 --- a/PDelays.h +++ b/PDelays.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "svector.h" diff --git a/PEvent.cc b/PEvent.cc index 9334f00a6..0f2426404 100644 --- a/PEvent.cc +++ b/PEvent.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/PEvent.h b/PEvent.h index 5cf4f5af9..b51e87d13 100644 --- a/PEvent.h +++ b/PEvent.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "LineInfo.h" diff --git a/PExpr.cc b/PExpr.cc index 7cbc649a4..1992c0f28 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -281,6 +281,14 @@ PExpr* PEEvent::expr() const return expr_; } +PENull::PENull(void) +{ +} + +PENull::~PENull() +{ +} + PEFNumber::PEFNumber(verireal*v) : value_(v) { @@ -363,7 +371,7 @@ bool PEIdent::has_aa_term(Design*des, NetScope*scope) const const NetExpr*ex1, *ex2; - scope = symbol_search(0, des, scope, path_, net, par, eve, ex1, ex2); + scope = symbol_search(this, des, scope, path_, net, par, eve, ex1, ex2); if (scope) return scope->is_auto(); @@ -371,6 +379,24 @@ bool PEIdent::has_aa_term(Design*des, NetScope*scope) const return false; } +PENew::PENew(PExpr*size_expr) +: size_(size_expr) +{ +} + +PENew::~PENew() +{ + delete size_; +} + +PENewClass::PENewClass(void) +{ +} + +PENewClass::~PENewClass() +{ +} + PENumber::PENumber(verinum*vp) : value_(vp) { diff --git a/PExpr.h b/PExpr.h index 257f3e977..25c4bca4a 100644 --- a/PExpr.h +++ b/PExpr.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -49,6 +49,7 @@ class PExpr : public LineInfo { static const unsigned NO_FLAGS = 0x0; static const unsigned NEED_CONST = 0x1; static const unsigned SYS_TASK_ARG = 0x2; + static const unsigned ANNOTATABLE = 0x4; PExpr(); virtual ~PExpr(); @@ -120,6 +121,13 @@ class PExpr : public LineInfo { // to be propagated down to any context-dependant operands. void cast_signed(bool flag) { signed_flag_ = flag; } + // This is the more generic form of the elaborate_expr method + // below. The plan is to replace the simpler elaborate_expr + // method with this version, which can handle more advanced + // types. But for now, this is only implemented in special cases. + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned flags) const; + // Procedural elaboration of the expression. The expr_width is // the required width of the expression. // @@ -304,13 +312,15 @@ class PEIdent : public PExpr { NetScope*scope, bool is_force) const; + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned flags) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, unsigned expr_wid, unsigned flags) const; // Elaborate the PEIdent as a port to a module. This method // only applies to Ident expressions. - NetNet* elaborate_port(Design*des, NetScope*sc) const; + NetNet* elaborate_subport(Design*des, NetScope*sc) const; verinum* eval_const(Design*des, NetScope*sc) const; @@ -363,9 +373,14 @@ class PEIdent : public PExpr { 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_class_member_(Design*, NetScope*, + NetAssign_*, + const perm_string&) const; bool elaborate_lval_net_packed_member_(Design*, NetScope*, NetAssign_*, const perm_string&) const; + bool elaborate_lval_darray_bit_(Design*, NetScope*, + NetAssign_*) const; private: NetExpr*elaborate_expr_param_(Design*des, @@ -438,6 +453,59 @@ class PEIdent : public PExpr { long&midx, long&lidx) const; }; +class PENew : public PExpr { + + public: + explicit PENew (PExpr*s); + ~PENew(); + + virtual void dump(ostream&) const; + virtual unsigned test_width(Design*des, NetScope*scope, + width_mode_t&mode); + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned flags) const; + virtual NetExpr*elaborate_expr(Design*des, NetScope*, + unsigned expr_wid, + unsigned flags) const; + + private: + PExpr*size_; +}; + +class PENewClass : public PExpr { + + public: + explicit PENewClass (); + ~PENewClass(); + virtual void dump(ostream&) const; + // Class objects don't have a useful width, but the expression + // is IVL_VT_CLASS. + virtual unsigned test_width(Design*des, NetScope*scope, + width_mode_t&mode); + // Note that class (new) expressions only appear in context + // that uses this form of the elaborate_expr method. In fact, + // the type argument is going to be a netclas_t object. + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned flags) const; + + private: +}; + +class PENull : public PExpr { + public: + explicit PENull(); + ~PENull(); + + virtual void dump(ostream&) const; + virtual unsigned test_width(Design*des, NetScope*scope, + width_mode_t&mode); + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned flags) const; + virtual NetExpr*elaborate_expr(Design*des, NetScope*, + unsigned expr_wid, + unsigned flags) const; +}; + class PENumber : public PExpr { public: @@ -716,8 +784,17 @@ class PECallFunction : public PExpr { bool check_call_matches_definition_(Design*des, NetScope*dscope) const; + NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const; + NetExpr*elaborate_expr_method_(Design*des, NetScope*scope, + unsigned expr_wid) const; +#if 0 + NetExpr*elaborate_expr_string_method_(Design*des, NetScope*scope) const; + NetExpr*elaborate_expr_enum_method_(Design*des, NetScope*scope, + unsigned expr_wid) const; +#endif + NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const; @@ -725,6 +802,8 @@ class PECallFunction : public PExpr { unsigned expr_wid) const; unsigned test_width_sfunc_(Design*des, NetScope*scope, width_mode_t&mode); + unsigned test_width_method_(Design*des, NetScope*scope, + width_mode_t&mode); }; /* diff --git a/PFunction.cc b/PFunction.cc index 42adc7189..0db008011 100644 --- a/PFunction.cc +++ b/PFunction.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/PGate.cc b/PGate.cc index 9ec25d33f..afca2a575 100644 --- a/PGate.cc +++ b/PGate.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -260,7 +260,7 @@ const char* PGBuiltin::gate_name() const } PGModule::PGModule(perm_string type, perm_string name, list*pins) -: PGate(name, pins), overrides_(0), pins_(0), +: PGate(name, pins), bound_type_(0), overrides_(0), pins_(0), npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0) { type_ = type; @@ -268,12 +268,18 @@ PGModule::PGModule(perm_string type, perm_string name, list*pins) PGModule::PGModule(perm_string type, perm_string name, named*pins, unsigned npins) -: PGate(name, 0), overrides_(0), pins_(pins), +: PGate(name, 0), bound_type_(0), overrides_(0), pins_(pins), npins_(npins), parms_(0), nparms_(0), msb_(0), lsb_(0) { type_ = type; } +PGModule::PGModule(Module*type, perm_string name) +: PGate(name, 0), bound_type_(type), overrides_(0), pins_(0), + npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0) +{ +} + PGModule::~PGModule() { } diff --git a/PGate.h b/PGate.h index 84fb26b9d..85ea1194b 100644 --- a/PGate.h +++ b/PGate.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "svector.h" @@ -201,6 +201,9 @@ class PGModule : public PGate { explicit PGModule(perm_string type, perm_string name, named*pins, unsigned npins); + // If the module type is known by design, then use this + // constructor. + explicit PGModule(Module*type, perm_string name); ~PGModule(); @@ -223,6 +226,7 @@ class PGModule : public PGate { perm_string get_type() const; private: + Module*bound_type_; perm_string type_; list*overrides_; named*pins_; diff --git a/PGenerate.cc b/PGenerate.cc index 6a71dbacc..5e99f1a6e 100644 --- a/PGenerate.cc +++ b/PGenerate.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "PGenerate.h" diff --git a/PGenerate.h b/PGenerate.h index 29de61ea3..ff5fbbbff 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -1,7 +1,7 @@ #ifndef __PGenerate_H #define __PGenerate_H /* - * Copyright (c) 2006-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2006-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 @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "LineInfo.h" @@ -80,6 +80,10 @@ class PGenerate : public LineInfo, public LexicalScope { // test value. std::valarray item_test; + // defparam assignments found in this scope. + typedef pair named_expr_t; + listdefparms; + list gates; void add_gate(PGate*); @@ -87,9 +91,6 @@ class PGenerate : public LineInfo, public LexicalScope { map tasks; mapfuncs; - // genvars declared within this scheme. - map genvars; - // Generate schemes can contain further generate schemes. list generate_schemes; // PGenerate*parent; diff --git a/PPackage.cc b/PPackage.cc new file mode 100644 index 000000000..e235dafc7 --- /dev/null +++ b/PPackage.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Picture Elements, Inc. + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "PPackage.h" + +PPackage::PPackage(perm_string name, LexicalScope*parent) +: PScopeExtra(name, parent) +{ +} + +PPackage::~PPackage() +{ +} diff --git a/PPackage.h b/PPackage.h new file mode 100644 index 000000000..f828384ae --- /dev/null +++ b/PPackage.h @@ -0,0 +1,40 @@ +#ifndef __PPackage_H +#define __PPackage_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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 PPackage : public PScopeExtra, public LineInfo { + + public: + explicit PPackage (perm_string name, LexicalScope*parent); + ~PPackage(); + +}; + +#endif diff --git a/PScope.cc b/PScope.cc index 0e5dd4abe..9fb4cef55 100644 --- a/PScope.cc +++ b/PScope.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "PScope.h" diff --git a/PScope.h b/PScope.h index e14cb6b4e..8fe77cae8 100644 --- a/PScope.h +++ b/PScope.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "LineInfo.h" @@ -30,6 +30,7 @@ class PExpr; class PFunction; class AProcess; class PProcess; +class PClass; class PTask; class PWire; @@ -165,8 +166,13 @@ class PScopeExtra : public PScope { ~PScopeExtra(); /* Task definitions within this module */ - map tasks; - map funcs; + std::map tasks; + std::map funcs; + /* class definitions within this module. */ + std::map classes; + + protected: + void dump_classes_(ostream&out, unsigned indent) const; }; #endif diff --git a/PSpec.cc b/PSpec.cc index 0f5516240..54825344e 100644 --- a/PSpec.cc +++ b/PSpec.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "PSpec.h" diff --git a/PSpec.h b/PSpec.h index a2313e0e7..29df33791 100644 --- a/PSpec.h +++ b/PSpec.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "LineInfo.h" diff --git a/PTask.cc b/PTask.cc index 14e88dee6..e9910ed76 100644 --- a/PTask.cc +++ b/PTask.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/PTask.h b/PTask.h index aeb30419d..c1a59ebe3 100644 --- a/PTask.h +++ b/PTask.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "LineInfo.h" diff --git a/PUdp.cc b/PUdp.cc index 55a72c5e0..61a9ff4c9 100644 --- a/PUdp.cc +++ b/PUdp.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "PUdp.h" diff --git a/PUdp.h b/PUdp.h index 848739875..100e64572 100644 --- a/PUdp.h +++ b/PUdp.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/PWire.cc b/PWire.cc index 4539bba17..31e117b48 100644 --- a/PWire.cc +++ b/PWire.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -29,7 +29,7 @@ PWire::PWire(perm_string n, : name_(n), type_(t), port_type_(pt), data_type_(dt), signed_(false), isint_(false), port_set_(false), net_set_(false), is_scalar_(false), - error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), struct_type_(0), + error_cnt_(0), set_data_type_(0), discipline_(0) { if (t == NetNet::INTEGER) { @@ -242,30 +242,21 @@ void PWire::set_range(const list&rlist, PWSRType type) } } -void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx) +void PWire::set_unpacked_idx(const list&ranges) { - if (lidx_ != 0 || ridx_ != 0) { + if (! unpacked_.empty()) { cerr << get_fileline() << ": error: Array ``" << name_ << "'' has already been declared." << endl; error_cnt_ += 1; } else { - lidx_ = ldx; - ridx_ = rdx; + unpacked_ = ranges; } } -void PWire::set_enumeration(enum_type_t*enum_type) +void PWire::set_data_type(data_type_t*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; + assert(set_data_type_ == 0); + set_data_type_ = type; } void PWire::set_discipline(ivl_discipline_t d) diff --git a/PWire.h b/PWire.h index 23c496ba5..464d4d6c6 100644 --- a/PWire.h +++ b/PWire.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "netlist.h" @@ -33,6 +33,7 @@ class ostream; class PExpr; class Design; +class netdarray_t; /* * The different type of PWire::set_range() calls. @@ -78,10 +79,9 @@ class PWire : public LineInfo { 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_unpacked_idx(const std::list&ranges); - void set_enumeration(enum_type_t*enum_type); - void set_struct_type(struct_type_t*type); + void set_data_type(data_type_t*type); void set_discipline(ivl_discipline_t); ivl_discipline_t get_discipline(void) const; @@ -115,12 +115,12 @@ class PWire : public LineInfo { unsigned error_cnt_; // If this wire is actually a memory, these indices will give - // me the size and address range of the memory. - PExpr*lidx_; - PExpr*ridx_; + // me the size and address ranges of the memory. + std::listunpacked_; - enum_type_t*enum_type_; - struct_type_t*struct_type_; + // This is the complex type of the wire. the data_type_ may + // modify how this is interpreted. + data_type_t*set_data_type_; ivl_discipline_t discipline_; diff --git a/README.txt b/README.txt index 38f5b66fd..da1e70b4f 100644 --- a/README.txt +++ b/README.txt @@ -64,7 +64,7 @@ on a UNIX-like system: - termcap The readline library in turn uses termcap. -If you are building from CVS, you will also need software to generate +If you are building from git, you will also need software to generate the configure scripts. - autoconf 2.53 diff --git a/Statement.cc b/Statement.cc index a99e8b37e..54e9ad1b1 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2008,2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -114,6 +114,13 @@ PBlock::~PBlock() delete list_[idx]; } +void PBlock::set_join_type(PBlock::BL_TYPE type) +{ + assert(bl_type_ == BL_PAR); + assert(type==BL_PAR || type==BL_JOIN_NONE || type==BL_JOIN_ANY); + bl_type_ = type; +} + void PBlock::set_statement(const vector&st) { list_ = st; diff --git a/Statement.h b/Statement.h index 049aa118e..87b747222 100644 --- a/Statement.h +++ b/Statement.h @@ -1,7 +1,7 @@ #ifndef __Statement_H #define __Statement_H /* - * Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -106,6 +106,10 @@ class PAssign_ : public Statement { NetAssign_* elaborate_lval(Design*, NetScope*scope) const; NetExpr* elaborate_rval_(Design*, NetScope*, unsigned lv_width, ivl_variable_type_t type) const; + NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t ntype) const; + + NetExpr* elaborate_rval_obj_(Design*, NetScope*, + ivl_variable_type_t type) const; PExpr* delay_; PEventStatement*event_; @@ -165,7 +169,7 @@ class PAssignNB : public PAssign_ { class PBlock : public PScope, public Statement { public: - enum BL_TYPE { BL_SEQ, BL_PAR }; + enum BL_TYPE { BL_SEQ, BL_PAR, BL_JOIN_NONE, BL_JOIN_ANY }; // If the block has a name, it is a scope and also has a parent. explicit PBlock(perm_string n, LexicalScope*parent, BL_TYPE t); @@ -175,6 +179,10 @@ class PBlock : public PScope, public Statement { BL_TYPE bl_type() const { return bl_type_; } + // If the bl_type() is BL_PAR, it is possible to replace it + // with JOIN_NONE or JOIN_ANY. This is to help the parser. + void set_join_type(BL_TYPE); + void set_statement(const std::vector&st); virtual void dump(ostream&out, unsigned ind) const; @@ -183,7 +191,7 @@ class PBlock : public PScope, public Statement { virtual void elaborate_sig(Design*des, NetScope*scope) const; private: - const BL_TYPE bl_type_; + BL_TYPE bl_type_; std::vectorlist_; }; @@ -203,6 +211,8 @@ class PCallTask : public Statement { NetProc* elaborate_sys(Design*des, NetScope*scope) const; NetProc* elaborate_usr(Design*des, NetScope*scope) const; + NetProc*elaborate_method_(Design*des, NetScope*scope) const; + pform_name_t path_; vector parms_; }; diff --git a/_pli_types.h.in b/_pli_types.h.in index c64828c12..d3057eb04 100644 --- a/_pli_types.h.in +++ b/_pli_types.h.in @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # undef HAVE_INTTYPES_H diff --git a/acc_user.h b/acc_user.h index abbbdbb5f..48eac2e69 100644 --- a/acc_user.h +++ b/acc_user.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/async.cc b/async.cc index d1db2270c..fa5bbaee0 100644 --- a/async.cc +++ b/async.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/autoconf.sh b/autoconf.sh index 089c3ff93..55a6f0e6e 100644 --- a/autoconf.sh +++ b/autoconf.sh @@ -2,9 +2,9 @@ # # This shell script exists to run autoconf on source distributions -# that are pulled from CVS. The configure scripts are not included -# in CVS, and there are several configure.in files, so it is easiest -# to just run this script to autoconf wherever needed. +# that are pulled from git The configure script is not included +# in git, so it is easiest to just run this script whenever needed +# to generate the configure script. # echo "Autoconf in root..." autoconf -f diff --git a/cadpli/Makefile.in b/cadpli/Makefile.in index 24f52ebab..e3a0eb559 100644 --- a/cadpli/Makefile.in +++ b/cadpli/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/cadpli/cadpli.c b/cadpli/cadpli.c index 4b9d21e95..9a75ab7dd 100644 --- a/cadpli/cadpli.c +++ b/cadpli/cadpli.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/cadpli/ivl_dlfcn.h b/cadpli/ivl_dlfcn.h index 46043e5c3..edd8418a1 100644 --- a/cadpli/ivl_dlfcn.h +++ b/cadpli/ivl_dlfcn.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if defined(__MINGW32__) diff --git a/compiler.h b/compiler.h index 976cbc831..fd26fe4bf 100644 --- a/compiler.h +++ b/compiler.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -177,6 +177,11 @@ static inline bool gn_system_verilog(void) return false; } +static inline bool gn_modules_nest(void) +{ + return gn_system_verilog(); +} + /* The bits of these GN_KEYWORDS_* constants define non-intersecting sets of keywords. The compiler enables groups of keywords by setting lexor_keyword_mask with the OR of the bits for the keywords to be diff --git a/config.h.in b/config.h.in index 3fd7953c9..fee775dda 100644 --- a/config.h.in +++ b/config.h.in @@ -1,7 +1,7 @@ #ifndef __config_H /* -*- c++ -*- */ #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 @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if defined(__cplusplus) @@ -53,6 +53,8 @@ /* These two are needed by the lxt and lxt2 files (copied from GTKWave). */ # undef HAVE_ALLOCA_H # undef HAVE_FSEEKO +/* And this is needed by the fst files (copied from GTKWave). */ +# undef HAVE_LIBPTHREAD /* * Define this if you want to compile vvp with memory freeing and diff --git a/configure.in b/configure.in index 28349c475..f50207b12 100644 --- a/configure.in +++ b/configure.in @@ -36,7 +36,7 @@ then echo "" echo "*** Warning: No suitable gperf found. ***" echo " The gperf package is essential for building ivl from" - echo " CVS sources, or modifying the parse engine of ivl itself." + echo " git sources, or modifying the parse engine of ivl itself." echo " You can get away without it when simply building from" echo " snapshots or major releases." echo "" @@ -91,6 +91,20 @@ fi AC_LANG(C++) +AC_ARG_WITH([m32], [AC_HELP_STRING([--with-m32], [Compile 32-bit on x86_64])], + [ with_m32=yes ],[ with_m32=no ]) + +AS_IF( [test "x$with_m32" = xyes], + [ AC_MSG_NOTICE([Compiling for 32-bit environment - needs gcc on x86_64]) + LDTARGETFLAGS="-m elf_i386" + CTARGETFLAGS="-m32" + ], + []) + +CFLAGS="$CTARGETFLAGS $CFLAGS" +CXXFLAGS="$CTARGETFLAGS $CXXFLAGS" +LDFLAGS="$CTARGETFLAGS $LDFLAGS" + # Check that we are using either the GNU compilers or the Sun compilers # but not a mixture of the two (not currently supported). AC_CHECK_DECL(__SUNPRO_CC, using_sunpro_cc=1, using_sunpro_cc=0) @@ -111,7 +125,11 @@ else fi fi +iverilog_temp_cxxflags="$CXXFLAGS" +CXXFLAGS="-DHAVE_DECL_BASENAME $CXXFLAGS" + AC_CHECK_HEADERS(getopt.h inttypes.h libiberty.h iosfwd sys/wait.h) +CXXFLAGS="$iverilog_temp_cxxflags" AC_CHECK_SIZEOF(unsigned long long) AC_CHECK_SIZEOF(unsigned long) @@ -178,6 +196,11 @@ if test -z "$DLLIB" ; then AC_CHECK_LIB(dld,shl_load,[DLLIB=-ldld]) fi AC_SUBST(DLLIB) +AC_SUBST(LDRELOCFLAGS) + +AC_SUBST(CTARGETFLAGS) +AC_SUBST(LDTARGETFLAGS) + AC_PROG_INSTALL @@ -302,6 +325,4 @@ AC_MSG_ERROR(cannot configure white space in libdir: $libdir) fi AC_MSG_RESULT(ok) -# XXX disable tgt-fpga for the moment - AC_OUTPUT(Makefile ivlpp/Makefile vhdlpp/Makefile vvp/Makefile vpi/Makefile driver/Makefile driver-vpi/Makefile cadpli/Makefile libveriuser/Makefile tgt-null/Makefile tgt-stub/Makefile tgt-vvp/Makefile tgt-vhdl/Makefile tgt-fpga/Makefile tgt-verilog/Makefile tgt-pal/Makefile tgt-vlog95/Makefile tgt-pcb/Makefile) diff --git a/cppcheck.sup b/cppcheck.sup index 0c003b15d..002ac0e77 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:4169 -thisSubtraction:netlist.h:4178 +thisSubtraction:netlist.h:4430 +thisSubtraction:netlist.h:4439 diff --git a/cprop.cc b/cprop.cc index a4306766b..a37e66982 100644 --- a/cprop.cc +++ b/cprop.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -14,18 +14,19 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" +# include +# include # include # include "netlist.h" # include "netmisc.h" # include "functor.h" # include "compiler.h" # include "ivl_assert.h" -# include /* @@ -42,11 +43,14 @@ struct cprop_functor : public functor_t { virtual void signal(Design*des, NetNet*obj); virtual void lpm_add_sub(Design*des, NetAddSub*obj); virtual void lpm_compare(Design*des, NetCompare*obj); - virtual void lpm_compare_eq_(Design*des, NetCompare*obj); + virtual void lpm_concat(Design*des, NetConcat*obj); virtual void lpm_ff(Design*des, NetFF*obj); virtual void lpm_logic(Design*des, NetLogic*obj); virtual void lpm_mux(Design*des, NetMux*obj); -}; + virtual void lpm_part_select(Design*des, NetPartSelect*obj); + + void lpm_compare_eq_(Design*des, NetCompare*obj); + }; void cprop_functor::signal(Design*, NetNet*) { @@ -74,6 +78,45 @@ void cprop_functor::lpm_compare_eq_(Design*, NetCompare*) { } +void cprop_functor::lpm_concat(Design*des, NetConcat*obj) +{ + verinum result (verinum::Vz, obj->width()); + unsigned off = 0; + + for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) { + Nexus*nex = obj->pin(idx).nexus(); + // If there are non-constant drivers, then give up. + if (! nex->drivers_constant()) + return; + + verinum tmp = nex->driven_vector(); + result.set(off, tmp); + off += tmp.len(); + } + + if (debug_optimizer) + cerr << obj->get_fileline() << ": cprop_functor::lpm_concat: " + << "Replace NetConcat with " << result << "." << endl; + + + NetScope*scope = obj->scope(); + + // Create a NetConst object to carry the result. Give it the + // same name as the Concat object that we are replacing, and + // link the NetConst to the NetConcat object. Then delete the + // concat that is now replaced. + NetConst*result_obj = new NetConst(scope, obj->name(), result); + result_obj->set_line(*obj); + des->add_node(result_obj); + connect(obj->pin(0), result_obj->pin(0)); + + // Note that this will leave the const inputs to dangle. They + // will be reaped by other passes of cprop_functor. + delete obj; + + count += 1; +} + void cprop_functor::lpm_ff(Design*, NetFF*obj) { // Look for and count unlinked FF outputs. Note that if the @@ -150,6 +193,142 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj) count += 1; } +static bool compare_base(NetPartSelect*a, NetPartSelect*b) +{ + return a->base() < b->base(); +} + +/* + * This optimization searches for Nexa that are driven only by + * NetPartSelect(PV) outputs. These might turn from Verilog input that + * looks like this: + * wire [7:0] foo + * assign foo[7:4] = a; + * assign foo[3:0] = b; + * The idea is to convert the part selects of the above to a single + * concatenation that looks like this: + * assign foo = {a, b}; + */ +void cprop_functor::lpm_part_select(Design*des, NetPartSelect*obj) +{ + if (obj->dir() != NetPartSelect::PV) + return; + + NetScope*scope = obj->scope(); + Nexus*nex = obj->pin(1).nexus(); + vector obj_set; + + for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) { + + // If this is an input (or passive) then ignore it. + if (cur->get_dir() != Link::OUTPUT) + continue; + + // Check to see if this is the output of a + // NetPartSelect::PV. If not, then give up on the blend. + NetPins*tmp_obj = cur->get_obj(); + unsigned tmp_pin = cur->get_pin(); + + NetPartSelect*cur_obj = dynamic_cast (tmp_obj); + if (cur_obj == 0) + return; + + if (cur_obj->dir() != NetPartSelect::PV) + return; + + if (tmp_pin != 1) + return; + + obj_set.push_back(cur_obj); + } + + if (obj_set.size() < 2) + return; + + if (debug_optimizer) + cerr << obj->get_fileline() << ": cprop::lpm_part_select: " + << "Found " << obj_set.size() << " NetPartSelect(PV) objects." + << endl; + + // Sort by increasing base offset. + sort(obj_set.begin(), obj_set.end(), compare_base); + + // Check and make sure there are no overlaps. If there are, + // then give up on this optimization. + for (size_t idx = 1 ; idx < obj_set.size() ; idx += 1) { + unsigned top = obj_set[idx-1]->base() + obj_set[idx-1]->width(); + if (top > obj_set[idx]->base()) { + if (debug_optimizer) + cerr << obj->get_fileline() << ": cprop::lpm_part_select: " + << "Range [" << obj_set[idx-1]->base() + << " " << top << ") overlaps PV starting at " + << obj_set[idx]->base() << ". Give up." << endl; + return; + } + } + + // Check if the tail runs off the end of the target. If so it + // should be possible to replace it with a bit select to + // shorten the object for the target, but for now just give up. + unsigned sig_width = nex->vector_width(); + if (obj_set.back()->base() + obj_set.back()->width() > sig_width) { + if (debug_optimizer) + cerr << obj->get_fileline() << ": cprop::lpm_part_select: " + << "Range [" << obj_set.back()->base() + << ":" << (obj_set.back()->base() + obj_set.back()->width() - 1) + << "] runs off the end of target." << endl; + return; + } + + // Figure out how many components we are going to need. + unsigned part_count = 0; + unsigned off = 0; + for (size_t idx = 0 ; idx < obj_set.size() ; idx += 1) { + if (obj_set[idx]->base() > off) { + off = obj_set[idx]->base(); + part_count += 1; + } + off += obj_set[idx]->width(); + part_count += 1; + } + + if (off < sig_width) + part_count += 1; + + NetConcat*concat = new NetConcat(scope, scope->local_symbol(), + sig_width, part_count); + concat->set_line(*obj); + des->add_node(concat); + connect(concat->pin(0), obj->pin(1)); + + off = 0; + size_t concat_pin = 1; + for (size_t idx = 0 ; idx < obj_set.size() ; idx += 1) { + NetPartSelect*cobj = obj_set[idx]; + if (cobj->base() > off) { + NetNet*zzz = make_const_z(des, scope, cobj->base()-off); + connect(concat->pin(concat_pin), zzz->pin(0)); + concat_pin += 1; + off = cobj->base(); + } + connect(concat->pin(concat_pin), cobj->pin(0)); + concat_pin += 1; + off += cobj->width(); + } + if (off < sig_width) { + NetNet*zzz = make_const_z(des, scope, sig_width-off); + connect(concat->pin(concat_pin), zzz->pin(0)); + concat_pin += 1; + } + ivl_assert(*obj, concat_pin == concat->pin_count()); + + for (size_t idx = 0 ; idx < obj_set.size() ; idx += 1) { + delete obj_set[idx]; + } + + count += 1; +} + /* * This functor looks to see if the constant is connected to nothing * but signals. If that is the case, delete the dangling constant and diff --git a/design_dump.cc b/design_dump.cc index e3d14f3b0..9ad63954b 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -28,6 +28,8 @@ # include "netlist.h" # include "compiler.h" # include "discipline.h" +# include "netdarray.h" +# include "netvector.h" # include "ivl_assert.h" # include "PExpr.h" @@ -40,6 +42,12 @@ static ostream& operator<< (ostream&o, NetBlock::Type t) case NetBlock::PARA: o << "fork"; break; + case NetBlock::PARA_JOIN_NONE: + o << "fork-join_none"; + break; + case NetBlock::PARA_JOIN_ANY: + o << "fork-join_any"; + break; } return o; } @@ -98,6 +106,12 @@ ostream& operator << (ostream&o, ivl_variable_type_t val) case IVL_VT_STRING: o << "string"; break; + case IVL_VT_DARRAY: + o << "darray"; + break; + case IVL_VT_CLASS: + o << "class"; + break; } return o; } @@ -130,6 +144,24 @@ ostream& operator << (ostream&o, ivl_switch_type_t val) return o; } +ostream& ivl_type_s::debug_dump(ostream&o) const +{ + o << typeid(*this).name(); + return o; +} + +ostream& netdarray_t::debug_dump(ostream&o) const +{ + o << "dynamic array of " << *element_type(); + return o; +} + +ostream& netvector_t::debug_dump(ostream&o) const +{ + o << type_ << (signed_? " signed" : " unsigned") << packed_dims_; + return o; +} + static inline void dump_scope_path(ostream&o, const NetScope*scope) { const NetScope*parent = scope->parent(); @@ -187,11 +219,30 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const dump_node_pins(o, ind+4); } -ostream&operator<<(ostream&out, const list&rlist) +static inline ostream&operator<<(ostream&out, const netrange_t&that) { - for (list::const_iterator cur = rlist.begin() + if (that.defined()) + out << "[" << that.get_msb() << ":" << that.get_lsb() << "]"; + else + out << "[]"; + + return out; +} + +ostream&operator<<(ostream&out, const list&rlist) +{ + for (list::const_iterator cur = rlist.begin() ; cur != rlist.end() ; ++cur) { - out << "[" << cur->msb << ":" << cur->lsb << "]"; + out << *cur; + } + return out; +} + +ostream&operator<<(ostream&out, const vector&rlist) +{ + for (vector::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + out << *cur; } return out; } @@ -200,12 +251,10 @@ ostream&operator<<(ostream&out, const list&rlist) void NetNet::dump_net(ostream&o, unsigned ind) const { o << setw(ind) << "" << type() << ": " << name() - << "[" << s0_ << ":" << e0_ << " count=" << pin_count() << "]"; + << unpacked_dims_ << " unpacked dims=" << unpacked_dimensions(); + o << " pin_count=" << pin_count(); if (local_flag_) o << " (local)"; - o << " " << data_type_; - if (signed_) - o << " signed"; switch (port_type_) { case NetNet::NOT_A_PORT: break; @@ -229,7 +278,7 @@ void NetNet::dump_net(ostream&o, unsigned ind) const if (ivl_discipline_t dis = get_discipline()) o << " discipline=" << dis->name(); - o << " packed dims: " << packed_dims_; + if (net_type_) o << " " << *net_type_; o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")"; if (scope()) @@ -470,9 +519,7 @@ void NetCaseCmp::dump_node(ostream&o, unsigned ind) const void NetConst::dump_node(ostream&o, unsigned ind) const { - o << setw(ind) << "" << "constant " << width_ << "'b"; - for (unsigned idx = width_ ; idx > 0 ; idx -= 1) - o << value_[idx-1]; + o << setw(ind) << "" << "constant " << value_; o << ": " << name(); if (rise_time()) o << " #(" << *rise_time() @@ -808,6 +855,9 @@ void NetAssign_::dump_lval(ostream&o) const { if (sig_) { o << sig_->name(); + if (! member_.nil()) { + o << "." << member_; + } if (word_) { o << "[word=" << *word_ << "]"; } @@ -1059,7 +1109,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_->packed_dims() << endl; + o << result_sig_->name() << endl; } o << setw(ind+2) << "" << "Arguments: "; if (port_count() == 0) o << ""; @@ -1081,7 +1131,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const break; } if (port(idx)->get_signed()) o << "+"; - o << port(idx)->name() << port(idx)->packed_dims() << endl; + o << port(idx)->name() << endl; } if (statement_) statement_->dump(o, ind+2); @@ -1127,6 +1177,9 @@ void NetScope::dump(ostream&o) const print_type(o); if (is_auto()) o << " (automatic)"; if (is_cell()) o << " (cell)"; + if (nested_module()) o << " (nested)"; + if (program_block()) o << " (program)"; + o << endl; for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1) @@ -1141,7 +1194,10 @@ void NetScope::dump(ostream&o) const map::const_iterator pp; for (pp = parameters.begin() ; pp != parameters.end() ; ++ pp ) { - o << " parameter "; + if ((*pp).second.is_annotatable) + o << " specparam "; + else + o << " parameter "; o << pp->second.type << " "; @@ -1188,12 +1244,6 @@ void NetScope::dump(ostream&o) const o << ";" << endl; } - - for (pp = localparams.begin() - ; pp != localparams.end() ; ++ pp ) { - o << " localparam " << (*pp).first << " = " << - *(*pp).second.val << ";" << endl; - } } /* Dump the saved defparam assignments here. */ @@ -1245,27 +1295,6 @@ void NetScope::dump(ostream&o) const cur->second->dump_net(o, 4); } - // Dump specparams - typedef map::const_iterator specparam_it_t; - for (specparam_it_t cur = specparams.begin() - ; cur != specparams.end() ; ++ cur ) { - o << " specparam " << (*cur).first - << " = "; - spec_val_t value = (*cur).second; - switch (value.type) { - case IVL_VT_REAL: - o << "R:" << value.real_val; - break; - case IVL_VT_BOOL: - o << "I:" << value.integer; - break; - default: - o << ""; - break; - } - o << endl; - } - switch (type_) { case FUNC: if (func_def()) @@ -1293,12 +1322,12 @@ void NetSTask::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << name_; - if (parms_.count() > 0) { + if (! parms_.empty()) { o << "("; if (parms_[0]) parms_[0]->dump(o); - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { o << ", "; if (parms_[idx]) parms_[idx]->dump(o); @@ -1428,7 +1457,7 @@ void NetEConcat::dump(ostream&o) const else o << "{"; - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { if (parms_[idx]) o << ", " << *parms_[idx]; else @@ -1481,6 +1510,21 @@ void NetENetenum::dump(ostream&o) const o << ""; } +void NetENew::dump(ostream&o) const +{ + o << "new "; +} + +void NetENull::dump(ostream&o) const +{ + o << ""; +} + +void NetEProperty::dump(ostream&o) const +{ + o << net_->name() << ".<" << pidx_ << ">"; +} + void NetEScope::dump(ostream&o) const { o << ""; @@ -1502,7 +1546,14 @@ void NetESelect::dump(ostream&o) const else o << "(0)"; - o << "+:" << expr_width() << "]>"; + o << "+:" << expr_width() << "]"; + if (ivl_type_t nt = net_type()) { + o << " net_type=(" << *nt << ")"; + } else { + o << " expr_type=" << expr_type(); + } + + o << ">"; } void NetESFunc::dump(ostream&o) const @@ -1521,7 +1572,8 @@ void NetESignal::dump(ostream&o) const o << "+"; o << name(); if (word_) o << "[word=" << *word_ << "]"; - o << sig()->packed_dims(); + vectortmp = net_->net_type()->slice_dimensions(); + o << tmp; } void NetETernary::dump(ostream&o) const @@ -1533,9 +1585,9 @@ void NetETernary::dump(ostream&o) const void NetEUFunc::dump(ostream&o) const { o << func_->basename() << "("; - if (parms_.count() > 0) { + if (! parms_.empty()) { parms_[0]->dump(o); - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { o << ", "; parms_[idx]->dump(o); } diff --git a/discipline.cc b/discipline.cc index 13078895f..7320e19f6 100644 --- a/discipline.cc +++ b/discipline.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "discipline.h" diff --git a/discipline.h b/discipline.h index 0726710a9..7c407d52e 100644 --- a/discipline.h +++ b/discipline.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/dosify.c b/dosify.c index 77fa81be7..5f58d894e 100644 --- a/dosify.c +++ b/dosify.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/driver-vpi/Makefile.in b/driver-vpi/Makefile.in index 8abb6a4ce..731e155eb 100644 --- a/driver-vpi/Makefile.in +++ b/driver-vpi/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/driver-vpi/main.c b/driver-vpi/main.c index b66f0c6ff..67bccb6cf 100644 --- a/driver-vpi/main.c +++ b/driver-vpi/main.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/driver/Makefile.in b/driver/Makefile.in index c6f3e4922..a94001e30 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/driver/cflexor.lex b/driver/cflexor.lex index 532d3abb8..08bb455c3 100644 --- a/driver/cflexor.lex +++ b/driver/cflexor.lex @@ -19,7 +19,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "cfparse.h" @@ -195,7 +195,6 @@ int yywrap() void switch_to_command_file(const char *file) { char path[4096]; - char *cp; if (cmdfile_stack_ptr >= MAX_CMDFILE_DEPTH) { fprintf(stderr, "Error: command files nested too deeply (%d) " @@ -213,6 +212,7 @@ void switch_to_command_file(const char *file) * file name. */ if (file[0] != '/') { + char *cp; strcpy(path, current_file); cp = strrchr(path, '/'); if (cp == 0) strcpy(path, file); /* A base file. */ diff --git a/driver/cfparse.y b/driver/cfparse.y index 40f20c5a8..22f127d26 100644 --- a/driver/cfparse.y +++ b/driver/cfparse.y @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "globals.h" diff --git a/driver/cfparse_misc.h b/driver/cfparse_misc.h index 708d79f93..c72886b36 100644 --- a/driver/cfparse_misc.h +++ b/driver/cfparse_misc.h @@ -17,7 +17,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/driver/globals.h b/driver/globals.h index 55cc00da8..1ef723315 100644 --- a/driver/globals.h +++ b/driver/globals.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/driver/main.c b/driver/main.c index 923dbc5fd..d0ce6d54c 100644 --- a/driver/main.c +++ b/driver/main.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/driver/substit.c b/driver/substit.c index 3aa0fc420..c71ea9f2a 100644 --- a/driver/substit.c +++ b/driver/substit.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/dup_expr.cc b/dup_expr.cc index cccdff8c6..e3d9cd552 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -110,10 +110,10 @@ NetEBShift* NetEBShift::dup_expr() const NetEConcat* NetEConcat::dup_expr() const { - NetEConcat*dup = new NetEConcat(parms_.count(), repeat_); + NetEConcat*dup = new NetEConcat(parms_.size(), repeat_, expr_type_); ivl_assert(*this, dup); dup->set_line(*this); - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) if (parms_[idx]) { NetExpr*tmp = parms_[idx]->dup_expr(); ivl_assert(*this, tmp); @@ -177,6 +177,24 @@ NetENetenum* NetENetenum::dup_expr() const return 0; } +NetENew* NetENew::dup_expr() const +{ + ivl_assert(*this, 0); + return 0; +} + +NetENull* NetENull::dup_expr() const +{ + ivl_assert(*this, 0); + return 0; +} + +NetEProperty* NetEProperty::dup_expr() const +{ + ivl_assert(*this, 0); + return 0; +} + NetEScope* NetEScope::dup_expr() const { ivl_assert(*this, 0); @@ -232,9 +250,9 @@ NetETernary* NetETernary::dup_expr() const NetEUFunc* NetEUFunc::dup_expr() const { NetEUFunc*tmp; - svector tmp_parms (parms_.count()); + vector tmp_parms (parms_.size()); - for (unsigned idx = 0 ; idx < tmp_parms.count() ; idx += 1) { + for (unsigned idx = 0 ; idx < tmp_parms.size() ; idx += 1) { ivl_assert(*this, parms_[idx]); tmp_parms[idx] = parms_[idx]->dup_expr(); } diff --git a/elab_anet.cc b/elab_anet.cc index 7dedae83e..72489e1ad 100644 --- a/elab_anet.cc +++ b/elab_anet.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/elab_expr.cc b/elab_expr.cc index 2e51f4f3d..d7d58f27a 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -26,9 +26,12 @@ # include "pform.h" # include "netlist.h" +# include "netclass.h" # include "netenum.h" +# include "netvector.h" # include "discipline.h" # include "netmisc.h" +# include "netdarray.h" # include "netstruct.h" # include "util.h" # include "ivl_assert.h" @@ -89,6 +92,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, switch (lv_type) { case IVL_VT_REAL: case IVL_VT_STRING: + case IVL_VT_DARRAY: break; case IVL_VT_BOOL: case IVL_VT_LOGIC: @@ -98,6 +102,12 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, case IVL_VT_NO_TYPE: ivl_assert(*expr, 0); break; + case IVL_VT_CLASS: + cerr << expr->get_fileline() << ": sorry: " + << "I do not know how to elaborate r-value as IVL_VT_CLASS." << endl; + des->errors += 1; + return 0; + break; } return elab_and_eval(des, scope, expr, context_wid, need_const); @@ -128,6 +138,17 @@ unsigned PExpr::test_width(Design*des, NetScope*, width_mode_t&) return 1; } +NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, ivl_type_t, unsigned) const +{ + cerr << get_fileline() << ": internal error: I do not know how to" + << " elaborate (ivl_type_t) this expression. " << endl; + cerr << get_fileline() << ": : Expression is: " << *this + << endl; + des->errors += 1; + return 0; +} + + NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const { cerr << get_fileline() << ": internal error: I do not know how to" @@ -1021,6 +1042,15 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, return expr_width_; } + if (test_width_method_(des, scope, mode)) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: test_width " + << "of method returns width " << expr_width_ + << ", type=" << expr_type_ + << "." << endl; + return expr_width_; + } + if (debug_elaborate) cerr << get_fileline() << ": debug: test_width " << "cannot find definition of " << path_ @@ -1050,6 +1080,46 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, return 0; } +unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope, + width_mode_t&) +{ + if (!gn_system_verilog()) + return 0; + + // This is only useful if the path is at least 2 elements. For + // example, foo.bar() is a method, bar() is not. + if (path_.size() < 2) + return 0; + + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + NetNet *net; + const NetExpr *par; + NetEvent *eve; + const NetExpr *ex1, *ex2; + + symbol_search(this, des, scope, use_path, + net, par, eve, ex1, ex2); + + if (net == 0) + return 0; + + netdarray_t*darray = net->darray_type(); + + // function int size() + if (darray && method_name == "size") { + expr_type_ = IVL_VT_BOOL; + expr_width_ = 32; + min_width_ = expr_width_; + signed_flag_= true; + return expr_width_; + } + + return 0; +} + NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const { /* If the expression is a const, then replace it with a new @@ -1429,7 +1499,7 @@ static const netstruct_t::member_t*get_struct_member(const LineInfo*li, perm_string method_name, unsigned long&off) { - netstruct_t*type = net->struct_type(); + const netstruct_t*type = net->struct_type(); ivl_assert(*li, type); if (! type->packed()) { @@ -1443,26 +1513,189 @@ static const netstruct_t::member_t*get_struct_member(const LineInfo*li, return type->packed_member(method_name, off); } +bool calculate_part(const LineInfo*li, Design*des, NetScope*scope, + const index_component_t&index, long&off, unsigned long&wid) +{ + // Evaluate the last index expression into a constant long. + NetExpr*texpr = elab_and_eval(des, scope, index.msb, -1, true); + long msb; + if (texpr == 0 || !eval_as_long(msb, texpr)) { + cerr << li->get_fileline() << ": error: " + "Array/part index expressions must be constant here." << endl; + des->errors += 1; + return false; + } + + delete texpr; + + long lsb = msb; + if (index.lsb) { + texpr = elab_and_eval(des, scope, index.lsb, -1, true); + if (texpr==0 || !eval_as_long(lsb, texpr)) { + cerr << li->get_fileline() << ": error: " + "Array/part index expressions must be constant here." << endl; + des->errors += 1; + return false; + } + + delete texpr; + } + + switch (index.sel) { + case index_component_t::SEL_BIT: + off = msb; + wid = 1; + return true; + + case index_component_t::SEL_PART: + if (msb >= lsb) { + off = lsb; + wid = msb - lsb + 1; + } else { + off = msb; + wid = lsb - msb + 1; + } + return true; + + default: + ivl_assert(*li, 0); + break; + } + return true; +} + +/* + * Test if the tail name (method_name argument) is a member name and + * the net is a struct. If that turns out to be the case, and the + * struct is packed, then return a NetExpr that selects the member out + * of the variable. + */ static NetExpr* check_for_struct_members(const LineInfo*li, - Design*des, NetScope*, - NetNet*net, perm_string method_name) + Design*des, NetScope*scope, + NetNet*net, + const list&base_index, + const name_component_t&comp) { unsigned long off; const netstruct_t::member_t*mem = get_struct_member(li, des, 0, net, - method_name, off); + comp.name, off); if (mem == 0) return 0; + unsigned use_width = mem->width(); + if (debug_elaborate) { - cerr << li->get_fileline() << ": debug: Found struct member " <name - << " At offset " << off << endl; + cerr << li->get_fileline() << ": debug: check_for_struct_members: " + << "Found struct member " << mem->name + << " At offset " << off + << ", member width = " << use_width << endl; + } + + // The struct member may be a packed array. Process index + // expression that address the member element. + if ( ! comp.index.empty() ) { + // Evaluate all but the last index expression, into prefix_indices. + listprefix_indices; + bool rc = evaluate_index_prefix(des, scope, prefix_indices, comp.index); + ivl_assert(*li, rc); + + // Make sure that index values that select array + // elements are in fact like bit selects. The tail may + // be part selects only if we are taking the part-select + // of the word of an array. + ivl_assert(*li, comp.index.size() >= mem->packed_dims.size() || comp.index.back().sel == index_component_t::SEL_BIT); + + // Evaluate the part/bit select expressions. This may be + // a bit select or a part select. In any case, assume + // the arguments are constant and generate a part select + // of the appropriate width. + long poff = 0; + unsigned long pwid = 0; + rc = calculate_part(li, des, scope, comp.index.back(), poff, pwid); + ivl_assert(*li, rc); + + // Now use the prefix_to_slice function to calculate the + // offset and width of the addressed slice of the member. + long loff; + unsigned long lwid; + prefix_to_slice(mem->packed_dims, prefix_indices, poff, loff, lwid); + + if (debug_elaborate) { + cerr << li->get_fileline() << ": debug: check_for_struct_members: " + << "Evaluate prefix gives slice loff=" << loff + << ", lwid=" << lwid << ", part select pwid=" << pwid << endl; + } + + off += loff; + if (comp.index.size() >= mem->packed_dims.size()) + use_width = pwid; + else + use_width = lwid; + } + + // If the base symbol has dimensions, then this is a packed + // array of structures. Convert an array of indices to a + // single part select. For example, "net" is a packed array + // of struct, and "mem" is the struct member. In Verilog it + // looks something like "net[idx].mem". We've already + // converted "mem" to an offset into the packed struct, so now + // we just canonicalize "[idx]" and add the ".mem" offset to + // get a collapsed index. + NetExpr*packed_base = 0; + if(net->packed_dimensions() > 1) { + listtmp_index = base_index; + index_component_t member_select; + member_select.sel = index_component_t::SEL_BIT; + member_select.msb = new PENumber(new verinum(off)); + tmp_index.push_back(member_select); + packed_base = collapse_array_exprs(des, scope, li, net, tmp_index); + ivl_assert(*li, packed_base); + if (debug_elaborate) { + cerr << li->get_fileline() << ": debug: check_for_struct_members: " + << "Got collapsed array expr: " << *packed_base << endl; + } + } + + long tmp; + if (packed_base && eval_as_long(tmp, packed_base)) { + off = tmp; + delete packed_base; + packed_base = 0; } NetESignal*sig = new NetESignal(net); - NetEConst*base = make_const_val(off); - NetESelect*sel = new NetESelect(sig, base, mem->width()); + NetExpr *base = packed_base? packed_base : make_const_val(off); + + if (debug_elaborate) { + cerr << li->get_fileline() << ": debug: check_for_struct_members: " + << "Convert packed indices/member select into part select: " << *base << endl; + } + + NetESelect*sel = new NetESelect(sig, base, use_width); return sel; } +static NetExpr* check_for_class_property(const LineInfo*li, + Design*des, NetScope*scope, + NetNet*net, + const name_component_t&comp) +{ + netclass_t*class_type = net->class_type(); + const ivl_type_s*ptype = class_type->get_property(comp.name); + + if (ptype == 0) { + cerr << li->get_fileline() << ": error: " + << "Class " << class_type->get_name() + << " has no property " << comp.name << "." << endl; + des->errors += 1; + return 0; + } + + NetEProperty*tmp = new NetEProperty(net, comp.name); + tmp->set_line(*li); + return tmp; +} + + NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { @@ -1481,43 +1714,11 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, return elaborate_access_func_(des, scope, access_nature, expr_wid); - // Maybe this is a method attached to an enumeration name? If - // this is system verilog, then test to see if the name is - // really a method attached to an object. - if (gn_system_verilog() && path_.size() >= 2) { - pform_name_t use_path = path_; - perm_string method_name = peek_tail_name(use_path); - use_path.pop_back(); - - NetNet *net; - const NetExpr *par; - NetEvent *eve; - const NetExpr *ex1, *ex2; - - 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 an - // enumeration? If so then check to see if this is an - // enumeration method call. - if (net != 0) { - if (netenum_t*netenum = net->enumeration()) { - // We may need the net expression for the - // enumeration variable so get it. - NetESignal*expr = new NetESignal(net); - expr->set_line(*this); - // This expression cannot be a select! - assert(use_path.back().index.empty()); - - PExpr*tmp = parms_.size() ? parms_[0] : 0; - return check_for_enum_methods(this, des, scope, - netenum, use_path, - method_name, expr, - expr_wid, tmp, - parms_.size()); - } - - } + // Maybe this is a method attached to a signal? If this + // is SystemVerilog then try that possibility. + if (gn_system_verilog()) { + NetExpr*tmp = elaborate_expr_method_(des, scope, expr_wid); + if (tmp) return tmp; } // Nothing was found so report this as an error. @@ -1562,7 +1763,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, if ((parms_count == 1) && (parms_[0] == 0)) parms_count = 0; - svector parms (parms_count); + vector parms (parms_count); /* Elaborate the input expressions for the function. This is done in the scope of the function call, and not the scope @@ -1571,7 +1772,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, unsigned parm_errors = 0; unsigned missing_parms = 0; - for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) { + for (unsigned idx = 0 ; idx < parms.size() ; idx += 1) { PExpr*tmp = parms_[idx]; if (tmp) { parms[idx] = elaborate_rval_expr(des, scope, @@ -1658,6 +1859,64 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, return 0; } +NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, + unsigned expr_wid) const +{ + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + NetNet *net; + const NetExpr *par; + NetEvent *eve; + const NetExpr *ex1, *ex2; + + symbol_search(this, des, scope, use_path, + net, par, eve, ex1, ex2); + + if (net == 0) + return 0; + + if (net->data_type() == IVL_VT_STRING) { + + if (method_name == "len") { + NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$len", + IVL_VT_BOOL, 32, 1); + sys_expr->parm(0, new NetESignal(net)); + return sys_expr; + } + } + + if (netenum_t*netenum = net->enumeration()) { + // We may need the net expression for the + // enumeration variable so get it. + NetESignal*expr = new NetESignal(net); + expr->set_line(*this); + // This expression cannot be a select! + assert(use_path.back().index.empty()); + + PExpr*tmp = parms_.size() ? parms_[0] : 0; + return check_for_enum_methods(this, des, scope, + netenum, use_path, + method_name, expr, + expr_wid, tmp, + parms_.size()); + } + + if (net->darray_type()) { + + if (method_name == "size") { + NetESFunc*sys_expr = new NetESFunc("$ivl_darray_method$size", + IVL_VT_BOOL, 32, 1); + sys_expr->parm(0, new NetESignal(net)); + sys_expr->set_line(*this); + return sys_expr; + } + } + + return 0; +} + unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&) { expr_width_ = size_; @@ -1681,15 +1940,36 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope, unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&) { expr_width_ = 0; + enum {NO, MAYBE, YES} expr_is_string = MAYBE; for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { + // Add in the width of this sub-expression. expr_width_ += parms_[idx]->test_width(des, scope, width_modes_[idx]); + + // If we already know this is not a string, then move on. + if (expr_is_string == NO) + continue; + + // If this expression is a string, then the + // concatenation is a string until we find a reason to + // deny it. + if (parms_[idx]->expr_type()==IVL_VT_STRING) { + expr_is_string = YES; + continue; + } + + // If this is a string literal, then this may yet be a string. + if (dynamic_cast (parms_[idx])) + continue; + + // Failed to allow a string result. + expr_is_string = NO; } - expr_type_ = IVL_VT_LOGIC; + expr_type_ = (expr_is_string==YES)? IVL_VT_STRING : IVL_VT_LOGIC; signed_flag_ = false; - /* If there is a repeat expression, then evaluate the constant - value and set the repeat count. */ + // If there is a repeat expression, then evaluate the constant + // value and set the repeat count. if (repeat_ && (scope != tested_scope_)) { NetExpr*tmp = elab_and_eval(des, scope, repeat_, -1, true); if (tmp == 0) return 0; @@ -1818,7 +2098,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, } /* Make the empty concat expression. */ - NetEConcat*concat = new NetEConcat(parm_cnt, repeat_count_); + NetEConcat*concat = new NetEConcat(parm_cnt, repeat_count_, expr_type_); concat->set_line(*this); /* Remove any zero width constants. */ @@ -1873,7 +2153,7 @@ bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net, { list index; index = path_.back().index; - for (size_t idx = 0 ; idx < net->array_dimensions() ; idx += 1) + for (size_t idx = 0 ; idx < net->unpacked_dimensions() ; idx += 1) index.pop_front(); return evaluate_index_prefix(des, scope, prefix_indices, index); @@ -1994,15 +2274,18 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope, NetExpr*wid_ex = elab_and_eval(des, scope, index_tail.lsb, -1, true); NetEConst*wid_c = dynamic_cast(wid_ex); - if (wid_c == 0) { - cerr << get_fileline() << ": error: Indexed part width must be " - << "constant. Expression in question is..." << endl; - cerr << get_fileline() << ": : " << *wid_ex << endl; + wid = wid_c? wid_c->value().as_ulong() : 0; + if (wid == 0) { + cerr << index_tail.lsb->get_fileline() << ": error: " + "Indexed part widths must be constant and greater than zero." + << endl; + cerr << index_tail.lsb->get_fileline() << ": : " + "This part width expression violates the rule: " + << *index_tail.lsb << endl; des->errors += 1; flag = false; + wid = 1; } - - wid = wid_c? wid_c->value().as_ulong() : 1; delete wid_ex; return flag; @@ -2061,7 +2344,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) const NetExpr*ex1, *ex2; - NetScope*found_in = symbol_search(0, des, scope, path_, net, par, eve, + NetScope*found_in = symbol_search(this, des, scope, path_, net, par, eve, ex1, ex2); // If there is a part/bit select expression, then process it @@ -2073,7 +2356,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) if (!name_tail.index.empty()) { const index_component_t&index_tail = name_tail.index.back(); // Skip full array word net selects. - if (!net || (name_tail.index.size() > net->array_dimensions())) { + if (!net || (name_tail.index.size() > net->unpacked_dimensions())) { use_sel = index_tail.sel; } } @@ -2110,6 +2393,21 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) ivl_assert(*this, 0); } + if (netdarray_t*darray = net? net->darray_type() : 0) { + if (use_sel == index_component_t::SEL_BIT) { + expr_type_ = darray->element_base_type(); + expr_width_ = darray->element_width(); + min_width_ = expr_width_; + signed_flag_ = net->get_signed(); + } else { + expr_type_ = net->data_type(); + expr_width_ = net->vector_width(); + min_width_ = expr_width_; + signed_flag_ = net->get_signed(); + } + return expr_width_; + } + if (use_width != UINT_MAX) { expr_type_ = IVL_VT_LOGIC; // Assume bit/parts selects are logic expr_width_ = use_width; @@ -2124,8 +2422,13 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) expr_type_ = net->data_type(); expr_width_ = net->vector_width(); min_width_ = expr_width_; - signed_flag_ = net->get_signed(); - + signed_flag_ = net->get_signed(); + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::test_width: " + << net->name() << " is a net, " + << "type=" << expr_type_ + << ", width=" << expr_width_ << endl; + } return expr_width_; } @@ -2136,7 +2439,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) ivl_assert(*this, use_enum != 0); expr_type_ = use_enum->base_type(); - expr_width_ = use_enum->base_width(); + expr_width_ = use_enum->packed_width(); min_width_ = expr_width_; signed_flag_ = par_enum->has_sign(); @@ -2172,47 +2475,29 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) return expr_width_; } - // The width of a specparam is the width of the specparam value - // (as evaluated earlier). Note that specparams aren't fully - // supported yet, so this code is likely to need rework when - // they are. - map::const_iterator specp; - perm_string key = peek_tail_name(path_); - if (path_.size() == 1 && - ((specp = scope->specparams.find(key)) != scope->specparams.end())) { - NetScope::spec_val_t value = (*specp).second; - if (value.type == IVL_VT_REAL) { - expr_type_ = IVL_VT_REAL; - expr_width_ = 1; - min_width_ = 1; - signed_flag_ = true; - } else { - verinum val (value.integer); - expr_type_ = IVL_VT_BOOL; - expr_width_ = val.len(); - min_width_ = expr_width_; - signed_flag_ = true; - - if (mode < LOSSLESS) mode = LOSSLESS; - } - 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); + ivl_assert(*this, net == 0); + 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. + // a struct member. If it is, then we know the + // width of this identifier my knowing the width + // of the member. We don't even need to know + // anything about positions in containing arrays. if (net->struct_type() != 0) { - ivl_assert(*this, use_path.back().index.empty()); + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: PEIdent::test_width: " + << "Net " << use_path << " is a struct, " + << "checking width of member " << method_name << endl; + } const netstruct_t::member_t*mem; unsigned long unused; @@ -2226,6 +2511,17 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) return expr_width_; } } + + if (netclass_t*class_type = net->class_type()) { + const ivl_type_s*ptype = class_type->get_property(method_name); + if (ptype) { + expr_type_ = ptype->base_type(); + expr_width_ = ptype->packed_width(); + min_width_ = expr_width_; + signed_flag_ = ptype->get_signed(); + return expr_width_; + } + } } } @@ -2239,6 +2535,52 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) return expr_width_; } + +NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, + ivl_type_t ntype, unsigned) const +{ + NetNet* net = 0; + const NetExpr*par = 0; + NetEvent* eve = 0; + const NetExpr*ex1, *ex2; + + NetScope*found_in = symbol_search(this, des, scope, path_, + net, par, eve, + ex1, ex2); + + if (net == 0) { + cerr << get_fileline() << ": internal error: " + << "Expecting idents wtih ntype to be signals." << endl; + des->errors += 1; + return 0; + } + + if (net->net_type() != ntype) { + cerr << get_fileline() << ": internal_error: " + << "net type doesn't match context type." << endl; + + cerr << get_fileline() << ": : " + << "net type="; + if (net->net_type()) + net->net_type()->debug_dump(cerr); + else + cerr << ""; + cerr << endl; + + cerr << get_fileline() << ": : " + << "context type="; + ivl_assert(*this, ntype); + ntype->debug_dump(cerr); + cerr << endl; + } + ivl_assert(*this, net->net_type() == ntype); + + NetESignal*tmp = new NetESignal(net); + tmp->set_line(*this); + + return tmp; +} + /* * Elaborate an identifier in an expression. The identifier can be a * parameter name, a signal name or a memory name. It can also be a @@ -2279,6 +2621,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, scope->is_const_func(false); } + if (debug_elaborate) + cerr << get_fileline() << ": PEIdent::elaborate_expr: path_=" << path_ << endl; + NetScope*found_in = symbol_search(this, des, scope, path_, net, par, eve, ex1, ex2); @@ -2371,44 +2716,21 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return tmp; } - // A specparam? Look up the name to see if it is a - // specparam. If we find it, then turn it into a NetEConst - // value and return that. - map::const_iterator specp; - perm_string key = peek_tail_name(path_); - if (path_.size() == 1 && - ((specp = scope->specparams.find(key)) != scope->specparams.end())) { - NetScope::spec_val_t value = (*specp).second; - NetExpr*tmp = 0; - switch (value.type) { - case IVL_VT_BOOL: - tmp = new NetEConst(verinum(value.integer)); - break; - case IVL_VT_REAL: - tmp = new NetECReal(verireal(value.real_val)); - break; - default: - break; - } - assert(tmp); - tmp->set_line(*this); - - if (debug_elaborate) - cerr << get_fileline() << ": debug: " << path_ - << " is a specparam" << endl; - return tmp; - } - // Maybe this is a method attached to an enumeration name? If // this is system verilog, then test to see if the name is // really a method attached to an object. 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); + name_component_t member_comp = use_path.back(); use_path.pop_back(); - found_in = symbol_search(this, des, scope, use_path, - net, par, eve, ex1, ex2); + if (debug_elaborate) + cerr << get_fileline() << ": PEIdent::elaborate_expr: " + << "Look for base_path " << use_path + << " for member " << member_comp << "." << endl; + + ivl_assert(*this, net == 0); + 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 an // enumeration? If so then check to see if this is an @@ -2426,19 +2748,38 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return check_for_enum_methods(this, des, scope, netenum, - use_path, method_name, + use_path, member_comp.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()); + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "PEIdent::elaborate_expr: " + << "Ident " << use_path + << " is a struct." + << " Expecting " << net->packed_dims().size() + << "-1 dimensions, " + << "got " << use_path.back().index.size() << "." << endl; + } return check_for_struct_members(this, des, scope, - net, method_name); + net, use_path.back().index, + member_comp); } + if (net->class_type() != 0) { + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr: " + << "Ident " << use_path + << " look for property " << member_comp << endl; + } + + return check_for_class_property(this, des, scope, + net, member_comp); + } } } @@ -2692,8 +3033,8 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, NetExpr*base = calculate_up_do_base_(des, scope, need_const); if (base == 0) return 0; - unsigned long wid = 0; - calculate_up_do_width_(des, scope, wid); + // Use the part select width already calculated by test_width(). + unsigned long wid = min_width_; if (debug_elaborate) cerr << get_fileline() << ": debug: Calculate part select " @@ -2778,8 +3119,8 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, NetExpr*base = calculate_up_do_base_(des, scope, need_const); if (base == 0) return 0; - unsigned long wid = 0; - calculate_up_do_width_(des, scope, wid); + // Use the part select width already calculated by test_width(). + unsigned long wid = min_width_; if (debug_elaborate) cerr << get_fileline() << ": debug: Calculate part select " @@ -2862,6 +3203,16 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, { bool need_const = NEED_CONST & flags; + if (need_const && !(ANNOTATABLE & flags)) { + perm_string name = peek_tail_name(path_); + if (found_in->make_parameter_unannotatable(name)) { + cerr << get_fileline() << ": warning: specparam '" << name + << "' is being used in a constant expression." << endl; + cerr << get_fileline() << ": : This will prevent it " + "being annotated at run time." << endl; + } + } + const name_component_t&name_tail = path_.back(); index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; if (!name_tail.index.empty()) @@ -3081,78 +3432,69 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, const name_component_t&name_tail = path_.back(); - if (name_tail.index.empty() && !(SYS_TASK_ARG & flags)) { + // Special case: This is the entire array, and we are a direct + // argument of a system task. + if (name_tail.index.empty() && (SYS_TASK_ARG & flags)) { + NetESignal*res = new NetESignal(net, 0); + res->set_line(*this); + return res; + } + + if (name_tail.index.empty()) { cerr << get_fileline() << ": error: Array " << path() << " Needs an array index here." << endl; des->errors += 1; return 0; } - index_component_t index_front; - if (! name_tail.index.empty()) { - index_front = name_tail.index.front(); - ivl_assert(*this, index_front.sel != index_component_t::SEL_NONE); - if (index_front.sel != index_component_t::SEL_BIT) { - cerr << get_fileline() << ": error: Array " << path_ - << " cannot be indexed by a range." << endl; - des->errors += 1; - return 0; - } - ivl_assert(*this, index_front.msb); - ivl_assert(*this, !index_front.lsb); - } - - NetExpr*word_index = 0; - if (index_front.sel != index_component_t::SEL_NONE) - word_index = elab_and_eval(des, scope, index_front.msb, -1, - need_const); - - if (word_index == 0 && !(SYS_TASK_ARG & flags)) + // Make sure there are enough indices to address an array element. + if (name_tail.index.size() < net->unpacked_dimensions()) { + cerr << get_fileline() << ": error: Array " << path() + << " needs " << net->unpacked_dimensions() << " indices," + << " but got only " << name_tail.index.size() << "." << endl; + des->errors += 1; return 0; - - if (NetEConst*word_addr = dynamic_cast(word_index)) { - long addr = word_addr->value().as_long(); - - // Special case: The index is out of range, so the value - // of this expression is a 'bx vector the width of a word. - if (!net->array_index_is_valid(addr)) { - cerr << get_fileline() << ": warning: returning 'bx for out " - "of bounds array access " << net->name() - << "[" << addr << "]." << endl; - NetEConst*resx = make_const_x(net->vector_width()); - resx->set_line(*this); - delete word_index; - return resx; - } - - // Recalculate the constant address with the adjusted base. - unsigned use_addr = net->array_index_to_address(addr); - if (addr < 0 || use_addr != (unsigned long)addr) { - verinum val ( (uint64_t)use_addr, 8*sizeof(use_addr)); - NetEConst*tmp = new NetEConst(val); - tmp->set_line(*this); - delete word_index; - word_index = tmp; - } - - } else if (word_index) { - // If there is a non-zero base to the memory, then build an - // expression to calculate the canonical address. - if (long base = net->array_first()) { - - word_index = normalize_variable_array_base( - word_index, base, net->array_count()); - eval_expr(word_index); - } } - NetESignal*res = new NetESignal(net, word_index); + // Evaluate all the index expressions into an + // "unpacked_indices" array. + listunpacked_indices; + list unpacked_indices_const; + bool flag = indices_to_expressions(des, scope, this, + name_tail.index, net->unpacked_dimensions(), + need_const, + unpacked_indices, + unpacked_indices_const); + + NetExpr*canon_index = 0; + if (flag) { + ivl_assert(*this, unpacked_indices_const.size() == net->unpacked_dimensions()); + canon_index = normalize_variable_unpacked(net, unpacked_indices_const); + + if (canon_index == 0) { + cerr << get_fileline() << ": warning: " + << "returning 'bx for out of bounds array access " + << net->name() << as_indices(unpacked_indices_const) << "." << endl; + } + + } else { + ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions()); + canon_index = normalize_variable_unpacked(net, unpacked_indices); + } + + if (canon_index == 0) { + NetEConst*xxx = make_const_x(net->vector_width()); + xxx->set_line(*this); + return xxx; + } + + NetESignal*res = new NetESignal(net, canon_index); res->set_line(*this); // Detect that the word has a bit/part select as well. index_component_t::ctype_t word_sel = index_component_t::SEL_NONE; - if (name_tail.index.size() > 1) + if (name_tail.index.size() > net->unpacked_dimensions()) word_sel = name_tail.index.back().sel; if (net->get_scalar() && @@ -3161,7 +3503,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, if (res->expr_type() == IVL_VT_REAL) cerr << "real"; else cerr << "scalar"; cerr << " array word: " << net->name() - <<"[" << *word_index << "]" << endl; + << as_indices(unpacked_indices) << endl; des->errors += 1; delete res; return 0; @@ -3310,9 +3652,8 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, NetExpr*base = calculate_up_do_base_(des, scope, need_const); - unsigned long wid = 0; - calculate_up_do_width_(des, scope, wid); - + // Use the part select width already calculated by test_width(). + unsigned long wid = min_width_; // Handle the special case that the base is constant as // well. In this case it can be converted to a conventional @@ -3323,12 +3664,12 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, long lsv = base_c->value().as_long(); long offset = 0; // Get the signal range. - const list&packed = net->sig()->packed_dims(); + const vector&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) { + const netrange_t&rng = packed.back(); + if (rng.get_msb() < rng.get_lsb()) { offset = -wid + 1; } @@ -3413,8 +3754,8 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, NetExpr*base = calculate_up_do_base_(des, scope, need_const); - unsigned long wid = 0; - calculate_up_do_width_(des, scope, wid); + // Use the part select width already calculated by test_width(). + unsigned long wid = min_width_; // Handle the special case that the base is constant as // well. In this case it can be converted to a conventional @@ -3508,6 +3849,20 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1, need_const); + if (netdarray_t*darray = net->sig()->darray_type()) { + // Special case: This is a select of a dynamic + // array. Generate a NetESelect and attach it to + // the NetESignal. This should be interpreted as + // an array word select downstream. + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Bit select of a dynamic array becomes NetESelect." << endl; + } + NetESelect*res = new NetESelect(net, mux, darray->element_width()); + res->set_line(*net); + return res; + } + // 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. @@ -3538,7 +3893,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, long msv = msc->value().as_long(); - const list& sig_packed = net->sig()->packed_dims(); + const vector& 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: @@ -3550,6 +3905,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, unsigned long lwid; long idx; rc = net->sig()->sb_to_slice(prefix_indices, msv, idx, lwid); + ivl_assert(*this, rc); // Make an expression out of the index NetEConst*idx_c = new NetEConst(verinum(idx)); @@ -3560,6 +3916,32 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return res; } + if (net->sig()->data_type()==IVL_VT_STRING && (msv < 0)) { + // Special case: This is a constant bit select of + // a string, and the index is < 0. For example: + // string foo; + // ... foo[-1] ... + // This is known to be 8'h00. + NetEConst*tmp = make_const_0(8); + tmp->set_line(*this); + delete mux; + return tmp; + } + + if (net->sig()->data_type()==IVL_VT_STRING) { + // Special case: This is a select of a string + // variable. Generate a NetESelect and attach it + // to the NetESignal. This should be interpreted + // as a character select downstream. + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Bit select of string becomes NetESelect." << endl; + } + NetESelect*res = new NetESelect(net, mux, 8); + res->set_line(*net); + return res; + } + long idx = net->sig()->sb_to_idx(prefix_indices,msv); if (idx >= (long)net->vector_width() || idx < 0) { @@ -3605,7 +3987,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return res; } - const list& sig_packed = net->sig()->packed_dims(); + const vector& 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: @@ -3643,7 +4025,7 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { - if (net->array_dimensions() > 0) + if (net->unpacked_dimensions() > 0) return elaborate_expr_net_word_(des, scope, net, found_in, expr_wid, flags); @@ -3698,6 +4080,82 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, return node; } +unsigned PENew::test_width(Design*, NetScope*, width_mode_t&) +{ + expr_type_ = IVL_VT_DARRAY; + expr_width_ = 1; + min_width_ = 1; + signed_flag_= false; + return 1; +} + +NetExpr* PENew::elaborate_expr(Design*des, NetScope*scope, + ivl_type_t ntype, unsigned flags) const +{ + // Elaborate the size expression. + width_mode_t mode = LOSSLESS; + unsigned use_wid = size_->test_width(des, scope, mode); + NetExpr*size = size_->elaborate_expr(des, scope, use_wid, flags); + + NetENew*tmp = new NetENew(ntype, size); + tmp->set_line(*this); + return tmp; +} + +/* + * This method should never actually be called. + */ +NetExpr* PENew::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const +{ + ivl_assert(*this, 0); + return 0; +} + +unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&) +{ + expr_type_ = IVL_VT_CLASS; + expr_width_ = 1; + min_width_ = 1; + signed_flag_= false; + return 1; +} + +NetExpr* PENewClass::elaborate_expr(Design*, NetScope*, + ivl_type_t ntype, unsigned) const +{ + NetENew*tmp = new NetENew(ntype); + tmp->set_line(*this); + return tmp; +} + +/* + * A "null" expression represents class objects/handles. This brings + * up a ton of special cases, but we handle it here bu setting the + * expr_type_ and expr_width_ to fixed values. + */ +unsigned PENull::test_width(Design*, NetScope*, width_mode_t&) +{ + expr_type_ = IVL_VT_CLASS; + expr_width_ = 1; + min_width_ = 1; + signed_flag_ = false; + return expr_width_; +} + +NetExpr* PENull::elaborate_expr(Design*, NetScope*, ivl_type_t, unsigned) const +{ + NetENull*tmp = new NetENull; + tmp->set_line(*this); + return tmp; +} + +NetExpr* PENull::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const +{ + NetENull*tmp = new NetENull; + tmp->set_line(*this); + return tmp; +} + unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode) { expr_type_ = IVL_VT_LOGIC; @@ -4214,9 +4672,9 @@ NetNet* Design::find_discipline_reference(ivl_discipline_t dis, NetScope*scope) if (gnd) return gnd; string name = string(dis->name()) + "$gnd"; - gnd = new NetNet(scope, lex_strings.make(name), NetNet::WIRE, 1); + netvector_t*gnd_vec = new netvector_t(IVL_VT_REAL,0,0); + gnd = new NetNet(scope, lex_strings.make(name), NetNet::WIRE, gnd_vec); gnd->set_discipline(dis); - gnd->data_type(IVL_VT_REAL); discipline_references_[dis->name()] = gnd; if (debug_elaborate) diff --git a/elab_lval.cc b/elab_lval.cc index 2cfb98016..91d3691d2 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 @@ -14,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -23,6 +24,7 @@ # include "netlist.h" # include "netmisc.h" # include "netstruct.h" +# include "netclass.h" # include "compiler.h" # include # include @@ -163,12 +165,17 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, the search with "a.b". */ if (reg == 0 && path_.size() >= 2) { pform_name_t use_path = path_; - method_name = peek_tail_name(use_path); + perm_string tmp_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(); + if (reg && reg->struct_type()) { + method_name = tmp_name; + + } else if (reg && reg->class_type()) { + method_name = tmp_name; + + } else { reg = 0; } } @@ -185,7 +192,8 @@ 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. + // "c" at this point. (Note that if method_name is not nil, + // then this is "a.b.c.method" and "a.b.c" is a struct or class.) const name_component_t&name_tail = path_.back(); // Use the last index to determine what kind of select @@ -202,7 +210,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, // 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()) { + if (reg->unpacked_dimensions() > name_tail.index.size()) { cerr << get_fileline() << ": error: Cannot assign to array " << path_ << ". Did you forget a word index?" << endl; des->errors += 1; @@ -228,7 +236,17 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, return lv; } - if (reg->array_dimensions() > 0) + if (reg->class_type() && !method_name.nil() && gn_system_verilog()) { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_net_class_member_(des, scope, lv, method_name); + return lv; + } + + // Past this point, we should have taken care of the cases + // where the name is a member/method of a struct/class. + ivl_assert(*this, method_name.nil()); + + if (reg->unpacked_dimensions() > 0) return elaborate_lval_net_word_(des, scope, reg); // This must be after the array word elaboration above! @@ -257,9 +275,15 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, if (use_sel == index_component_t::SEL_BIT) { - NetAssign_*lv = new NetAssign_(reg); - elaborate_lval_net_bit_(des, scope, lv); - return lv; + if (reg->darray_type()) { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_darray_bit_(des, scope, lv); + return lv; + } else { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_net_bit_(des, scope, lv); + return lv; + } } ivl_assert(*this, use_sel == index_component_t::SEL_NONE); @@ -278,6 +302,15 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, const name_component_t&name_tail = path_.back(); ivl_assert(*this, !name_tail.index.empty()); + if (name_tail.index.size() < reg->unpacked_dimensions()) { + cerr << get_fileline() << ": error: Array " << reg->name() + << " needs " << reg->unpacked_dimensions() << " indices," + << " but got only " << name_tail.index.size() << "." << endl; + des->errors += 1; + return 0; + } + + // Make sure there are enough indices to address an array element. const index_component_t&index_head = name_tail.index.front(); if (index_head.sel == index_component_t::SEL_PART) { cerr << get_fileline() << ": error: cannot perform a part " @@ -286,47 +319,47 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, return 0; } - ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT); - ivl_assert(*this, index_head.msb != 0); - ivl_assert(*this, index_head.lsb == 0); - NetExpr*word = elab_and_eval(des, scope, index_head.msb, -1); + // Evaluate all the index expressions into an + // "unpacked_indices" array. + listunpacked_indices; + list unpacked_indices_const; + bool flag = indices_to_expressions(des, scope, this, + name_tail.index, reg->unpacked_dimensions(), + false, + unpacked_indices, + unpacked_indices_const); - // If there is a non-zero base to the memory, then build an - // expression to calculate the canonical address. - if (long base = reg->array_first()) { - - word = normalize_variable_array_base(word, base, - reg->array_count()); - eval_expr(word); + NetExpr*canon_index = 0; + if (flag) { + ivl_assert(*this, unpacked_indices_const.size() == reg->unpacked_dimensions()); + canon_index = normalize_variable_unpacked(reg, unpacked_indices_const); + if (canon_index == 0) { + cerr << get_fileline() << ": warning: " + << "ignoring out of bounds l-value array access " << reg->name(); + for (list::const_iterator cur = unpacked_indices_const.begin() + ; cur != unpacked_indices_const.end() ; ++cur) { + cerr << "[" << *cur << "]"; + } + cerr << "." << endl; + } + } else { + ivl_assert(*this, unpacked_indices.size() == reg->unpacked_dimensions()); + canon_index = normalize_variable_unpacked(reg, unpacked_indices); } + NetAssign_*lv = new NetAssign_(reg); - lv->set_word(word); + lv->set_word(canon_index); if (debug_elaborate) - cerr << get_fileline() << ": debug: Set array word=" << *word << endl; + cerr << get_fileline() << ": debug: Set array word=" << *canon_index << endl; - // Test for the case that the index is a constant, and is out - // of bounds. The "word" expression is the word index already - // converted to canonical address, so this just needs to check - // that the address is not too big. - if (NetEConst*word_const = dynamic_cast(word)) { - verinum word_val = word_const->value(); - long index = word_val.as_long(); - - if (index < 0 || index >= (long) reg->array_count()) { - cerr << get_fileline() << ": warning: Constant array index " - << (index + reg->array_first()) - << " is out of range for array " - << reg->name() << "." << endl; - } - } /* An array word may also have part selects applied to them. */ index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; - if (name_tail.index.size() > 1) + if (name_tail.index.size() > reg->unpacked_dimensions()) use_sel = name_tail.index.back().sel; if (reg->get_scalar() && @@ -335,7 +368,7 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, if (reg->data_type() == IVL_VT_REAL) cerr << "real"; else cerr << "scalar"; cerr << " array word: " << reg->name() - << "[" << *word << "]" << endl; + << "[" << *canon_index << "]" << endl; des->errors += 1; return 0; } @@ -404,6 +437,22 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, lv->set_part(mux, lwid); } + } else if (reg->data_type() == IVL_VT_STRING) { + // Special case: This is a select of a string + // variable. The target of the assignment is a character + // select of a string. Force the r-value to be an 8bit + // vector and set the "part" to be the character select + // expression. The code generator knows what to do with + // this. + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Bit select of string becomes character select." << endl; + } + if (mux) + lv->set_part(mux, 8); + else + lv->set_part(new NetEConst(verinum(lsb)), 8); + } else if (mux) { // Non-constant bit mux. Correct the mux for the range // of the vector, then set the l-value part select @@ -433,6 +482,26 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, return true; } +bool PEIdent::elaborate_lval_darray_bit_(Design*des, NetScope*scope, NetAssign_*lv)const +{ + const name_component_t&name_tail = path_.back(); + ivl_assert(*this, !name_tail.index.empty()); + + // For now, only support single-dimension dynamic arrays. + ivl_assert(*this, name_tail.index.size() == 1); + + const index_component_t&index_tail = name_tail.index.back(); + ivl_assert(*this, index_tail.msb != 0); + ivl_assert(*this, index_tail.lsb == 0); + + // Evaluate the select expression... + NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1); + + lv->set_word(mux); + + return true; +} + bool PEIdent::elaborate_lval_net_part_(Design*des, NetScope*scope, NetAssign_*lv) const @@ -455,7 +524,7 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, NetNet*reg = lv->sig(); ivl_assert(*this, reg); - const list&packed = reg->packed_dims(); + const vector&packed = reg->packed_dims(); // Part selects cannot select slices. So there must be enough // prefix_indices to get all the way to the final dimension. @@ -544,14 +613,14 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, long lsv = base_c->value().as_long(); long offset = 0; // Get the signal range. - const list&packed = reg->packed_dims(); + const vector&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) && + const netrange_t&rng = packed.back(); + if (((rng.get_msb() < rng.get_lsb()) && use_sel == index_component_t::SEL_IDX_UP) || - ((rng.msb > rng.lsb) && + ((rng.get_msb() > rng.get_lsb()) && use_sel == index_component_t::SEL_IDX_DO)) { offset = -wid + 1; } @@ -563,7 +632,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, if (warn_ob_select) { if (rel_base < 0) { cerr << get_fileline() << ": warning: " << reg->name(); - if (reg->array_dimensions() > 0) cerr << "[]"; + if (reg->unpacked_dimensions() > 0) cerr << "[]"; cerr << "[" << lsv; if (use_sel == index_component_t::SEL_IDX_UP) { cerr << "+:"; @@ -574,7 +643,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, } if (rel_base + wid > reg->vector_width()) { cerr << get_fileline() << ": warning: " << reg->name(); - if (reg->array_dimensions() > 0) cerr << "[]"; + if (reg->unpacked_dimensions() > 0) cerr << "[]"; cerr << "[" << lsv; if (use_sel == index_component_t::SEL_IDX_UP) { cerr << "+:"; @@ -587,7 +656,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, } else { if (warn_ob_select) { cerr << get_fileline() << ": warning: " << reg->name(); - if (reg->array_dimensions() > 0) cerr << "[]"; + if (reg->unpacked_dimensions() > 0) cerr << "[]"; cerr << "['bx"; if (use_sel == index_component_t::SEL_IDX_UP) { cerr << "+:"; @@ -621,17 +690,49 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, return true; } -bool PEIdent::elaborate_lval_net_packed_member_(Design*des, - NetScope*, +bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*, + NetAssign_*lv, + const perm_string&method_name) const +{ + if (debug_elaborate) { + cerr << get_fileline() << ": elaborate_lval_net_class_member_: " + << "l-value is property " << method_name + << " of " << lv->sig()->name() << "." << endl; + } + + netclass_t*class_type = lv->sig()->class_type(); + ivl_assert(*this, class_type); + + /* Make sure the property is really present in the class. If + not, then generate an error message and return an error. */ + const ivl_type_s*ptype = class_type->get_property(method_name); + if (ptype == 0) { + cerr << get_fileline() << ": error: Class " << class_type->get_name() + << " does not have a property " << method_name << "." << endl; + des->errors += 1; + return false; + } + + lv->set_property(method_name); + return true; +} + + +bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, NetAssign_*lv, const perm_string&member_name) const { NetNet*reg = lv->sig(); ivl_assert(*this, reg); - netstruct_t*struct_type = reg->struct_type(); + const netstruct_t*struct_type = reg->struct_type(); ivl_assert(*this, struct_type); + if (debug_elaborate) { + cerr << get_fileline() << ": debug: elaborate lval packed member: " + << "path_=" << path_ << endl; + } + if (! struct_type->packed()) { cerr << get_fileline() << ": sorry: Only packed structures " << "are supported in l-value." << endl; @@ -639,6 +740,27 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, return false; } + // Shouldn't be seeing unpacked arrays of packed structs... + ivl_assert(*this, reg->unpacked_dimensions() == 0); + + // This is a packed member, so the name is of the form + // "a.b[...].c[...]" which means that the path_ must have at + // least 2 components. We are processing "c[...]" at that + // point (otherwise known as member_name) so we'll save a + // reference to it in name_tail. We are also processing "b[]" + // so save that as name_base. + + ivl_assert(*this, path_.size() >= 2); + + pform_name_t::const_reverse_iterator name_idx = path_.rbegin(); + ivl_assert(*this, name_idx->name == member_name); + const name_component_t&name_tail = *name_idx; + ++ name_idx; + const name_component_t&name_base = *name_idx; + + // Calculate the offset within the packed structure of the + // member, and any indices. We will add in the offset of the + // struct into the packed array later. unsigned long off; const netstruct_t::member_t* member = struct_type->packed_member(member_name, off); @@ -649,8 +771,90 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, return false; } - lv->set_part(new NetEConst(verinum(off)), member->width()); - return true; + unsigned long use_width = member->width(); + + if (name_tail.index.size() > member->packed_dims.size()) { + cerr << get_fileline() << ": error: Too many index expressions for member." << endl; + des->errors += 1; + return false; + } + + // Get the index component type. At this point, we only + // support bit select or none. + index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; + if (!name_tail.index.empty()) + use_sel = name_tail.index.back().sel; + + ivl_assert(*this, use_sel == index_component_t::SEL_NONE || use_sel == index_component_t::SEL_BIT); + + if (! name_tail.index.empty()) { + // Evaluate all but the last index expression, into prefix_indices. + listprefix_indices; + bool rc = evaluate_index_prefix(des, scope, prefix_indices, name_tail.index); + ivl_assert(*this, rc); + + // Evaluate the last index expression into a constant long. + NetExpr*texpr = elab_and_eval(des, scope, name_tail.index.back().msb, -1, true); + long tmp; + if (texpr == 0 || !eval_as_long(tmp, texpr)) { + cerr << get_fileline() << ": error: " + "Array index expressions must be constant here." << endl; + des->errors += 1; + return false; + } + + delete texpr; + + // Now use the prefix_to_slice function to calculate the + // offset and width of the addressed slice of the member. + long loff; + unsigned long lwid; + prefix_to_slice(member->packed_dims, prefix_indices, tmp, loff, lwid); + + off += loff; + use_width = lwid; + } + + // The dimenions in the expression must match the packed + // dimensions that are declared for the variable. For example, + // if foo is a packed array of struct, then this expression + // must be "b[n][m]" with the right number of dimensions to + // match the declaration of "b". + // Note that one of the packed dimensions is the packed struct + // itself. + ivl_assert(*this, name_base.index.size()+1 == reg->packed_dimensions()); + + // Generate an expression that takes the input array of + // expressions and generates a canonical offset into the + // packed array. + NetExpr*packed_base = 0; + if (reg->packed_dimensions() > 1) { + listtmp_index = name_base.index; + index_component_t member_select; + member_select.sel = index_component_t::SEL_BIT; + member_select.msb = new PENumber(new verinum(off)); + tmp_index.push_back(member_select); + packed_base = collapse_array_indices(des, scope, reg, tmp_index); + } + + long tmp; + if (packed_base && eval_as_long(tmp, packed_base)) { + off = tmp; + delete packed_base; + packed_base = 0; + } + + if (packed_base == 0) { + lv->set_part(new NetEConst(verinum(off)), use_width); + return true; + } + + // Oops, packed_base is not fully evaluated, so I don't know + // yet what to do with it. + cerr << get_fileline() << ": internal error: " + << "I don't know how to handle this index expression? " << *packed_base << endl; + ivl_assert(*this, 0); + return false; } NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const diff --git a/elab_net.cc b/elab_net.cc index db70c4069..6d39f8f4c 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 @@ -14,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -23,6 +24,7 @@ # include "netlist.h" # include "netmisc.h" # include "netstruct.h" +# include "netvector.h" # include "compiler.h" # include @@ -97,12 +99,12 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope, concat operator from most significant to least significant, which is the order they are given in the concat list. */ + netvector_t*tmp2_vec = new netvector_t(nets[0]->data_type(),width-1,0); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); + NetNet::IMPLICIT, tmp2_vec); /* Assume that the data types of the nets are all the same, so we can take the data type of any, the first will do. */ - osig->data_type(nets[0]->data_type()); osig->local_flag(true); osig->set_line(*this); @@ -153,8 +155,6 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope, assert(width == 0); } - osig->data_type(nets[0]->data_type()); - osig->local_flag(true); return osig; } @@ -208,7 +208,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, // Only treat as part/bit selects any index that is beyond the // word selects for an array. This is not an array, then // dimensions==0 and any index is treated as a select. - if (name_tail.index.size() <= sig->array_dimensions()) { + if (name_tail.index.size() <= sig->unpacked_dimensions()) { midx = sig->vector_width()-1; lidx = 0; return true; @@ -247,7 +247,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, if (warn_ob_select) { cerr << get_fileline() << ": warning: " << sig->name(); - if (sig->array_dimensions() > 0) cerr << "[]"; + if (sig->unpacked_dimensions() > 0) cerr << "[]"; cerr << "['bx"; if (index_tail.sel == index_component_t::SEL_IDX_UP) { @@ -279,7 +279,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, /* Warn about an indexed part select that is out of range. */ if (warn_ob_select && (lidx < 0)) { cerr << get_fileline() << ": warning: " << sig->name(); - if (sig->array_dimensions() > 0) cerr << "[]"; + if (sig->unpacked_dimensions() > 0) cerr << "[]"; cerr << "[" << midx_val; if (index_tail.sel == index_component_t::SEL_IDX_UP) { cerr << "+:"; @@ -290,7 +290,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, } if (warn_ob_select && (midx >= (long)sig->vector_width())) { cerr << get_fileline() << ": warning: " << sig->name(); - if (sig->array_dimensions() > 0) { + if (sig->unpacked_dimensions() > 0) { cerr << "[]"; } cerr << "[" << midx_val; @@ -337,16 +337,11 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) { cerr << get_fileline() << ": warning: Part select " << sig->name(); - if (sig->array_dimensions() > 0) { + if (sig->unpacked_dimensions() > 0) { cerr << "[]"; } cerr << "[" << msb << ":" << lsb << "] is out of range." << endl; -#if 0 - midx_tmp = sig->vector_width() - 1; - lidx_tmp = 0; - des->errors += 1; -#endif } /* This is completely out side the signal so just skip it. */ if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) { @@ -359,20 +354,31 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, } case index_component_t::SEL_BIT: - if (name_tail.index.size() > sig->array_dimensions()) { + if (name_tail.index.size() > sig->unpacked_dimensions()) { long msb; bool bit_defined_flag; /* bool flag = */ calculate_bits_(des, scope, msb, bit_defined_flag); ivl_assert(*this, bit_defined_flag); - midx = sig->sb_to_idx(prefix_indices, msb); - if (midx >= (long)sig->vector_width()) { - cerr << get_fileline() << ": error: Index " << sig->name() - << "[" << msb << "] is out of range." - << endl; - des->errors += 1; - midx = 0; + + if (prefix_indices.size()+2 <= sig->packed_dims().size()) { + long tmp_loff; + unsigned long tmp_lwid; + bool rcl = sig->sb_to_slice(prefix_indices, msb, + tmp_loff, tmp_lwid); + ivl_assert(*this, rcl); + midx = tmp_loff + tmp_lwid - 1; + lidx = tmp_loff; + } else { + midx = sig->sb_to_idx(prefix_indices, msb); + if (midx >= (long)sig->vector_width()) { + cerr << get_fileline() << ": error: Index " << sig->name() + << "[" << msb << "] is out of range." + << endl; + des->errors += 1; + midx = 0; + } + lidx = midx; } - lidx = midx; } else { cerr << get_fileline() << ": internal error: " @@ -412,18 +418,30 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, return 0; } + // Break the path_ into the tail name and the prefix. For + // example, a name "a.b.c" is broken into name_tail="c" and + // path_prefix="a.b". + const name_component_t&path_tail = path_.back(); + pform_name_t path_prefix = path_; + path_prefix.pop_back(); + /* 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); + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " + "Symbol not found, try again with path_prefix=" << path_prefix + << " and method_name=" << path_tail.name << endl; + } + method_name = path_tail.name; + symbol_search(this, des, scope, path_prefix, sig, par, eve); // Whoops, not a struct signal, so give up on this avenue. if (sig && sig->struct_type() == 0) { + cerr << get_fileline() << ": XXXXX: sig=" << sig->name() + << " is found, but not a struct with member " << method_name << endl; method_name = perm_string(); sig = 0; } @@ -460,19 +478,19 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, unsigned midx = sig->vector_width()-1, lidx = 0; // The default word select is the first. long widx = 0; - // The widx_val is the word select as entered in the source - // code. It's used for error messages. - long widx_val = 0; - const name_component_t&name_tail = path_.back(); + list unpacked_indices_const; - netstruct_t*struct_type = 0; + const 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. + // method name detected. We've already found that + // the path_ is <>.sig.method_name and signal + // (NetNet). We also know that sig is struct_type(), so + // look for a method named method_name. if (debug_elaborate) - cerr << get_fileline() << ": debug: " + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " << "Signal " << sig->name() << " is a structure, " << "try to match member " << method_name << endl; @@ -480,58 +498,133 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, const struct netstruct_t::member_t*member = struct_type->packed_member(method_name, member_off); ivl_assert(*this, member); + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " + << "Member " << method_name + << " has packed dimensions " << member->packed_dims << "." << endl; + cerr << get_fileline() << ": : " + << "Tail name has " << path_tail.index.size() << " indices." << endl; + } + // 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) { + // The dimensions of the tail of the prefix must match + // the dimensions of the signal at this point. (The sig + // has a packed dimension for the packed struct size.) + // For example, if the path_=a[][].member, then + // sig must have 3 packed dimenions: one for the struct + // members and two actual packed dimensions. + ivl_assert(*this, path_prefix.back().index.size()+1 == sig->packed_dimensions()); - if (name_tail.index.empty()) { - cerr << get_fileline() << ": error: array " << sig->name() - << " must be used with an index." << endl; + // Elaborate an expression from the packed indices and + // the member offset (into the structure) to get a + // canonical expression into the packed signal vector. + NetExpr*packed_base = 0; + if (sig->packed_dimensions() > 1) { + listtmp_index = path_prefix.back().index; + index_component_t member_select; + member_select.sel = index_component_t::SEL_BIT; + member_select.msb = new PENumber(new verinum(member_off)); + tmp_index.push_back(member_select); + packed_base = collapse_array_indices(des, scope, sig, tmp_index); + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "packed_base expression = " << *packed_base << endl; + } + } + + long tmp; + if (packed_base && eval_as_long(tmp, packed_base)) { + lidx = tmp; + midx = lidx + member->width() - 1; + delete packed_base; + packed_base = 0; + } + + // Currently, only support const dimensions here. + ivl_assert(*this, packed_base == 0); + + // Now the lidx/midx values get us to the member. Next + // up, deal with bit/part selects from the member + // itself. + ivl_assert(*this, member->packed_dims.size() <= 1); + ivl_assert(*this, path_tail.index.size() <= 1); + if (! path_tail.index.empty()) { + long tmp_off; + unsigned long tmp_wid; + const index_component_t&tail_sel = path_tail.index.back(); + ivl_assert(*this, tail_sel.sel == index_component_t::SEL_PART || tail_sel.sel == index_component_t::SEL_BIT); + bool rc = calculate_part(this, des, scope, tail_sel, tmp_off, tmp_wid); + ivl_assert(*this, rc); + if (debug_elaborate) + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " + << "tmp_off=" << tmp_off << ", tmp_wid=" << tmp_wid << endl; + lidx += tmp_off; + midx = lidx + tmp_wid - 1; + } + + } else if (sig->unpacked_dimensions() > 0) { + + // Make sure there are enough indices to address an array element. + if (path_tail.index.size() < sig->unpacked_dimensions()) { + cerr << get_fileline() << ": error: Array " << path() + << " needs " << sig->unpacked_dimensions() << " indices," + << " but got only " << path_tail.index.size() << "." << endl; des->errors += 1; return 0; } - const index_component_t&index_head = name_tail.index.front(); - if (index_head.sel == index_component_t::SEL_PART) { - cerr << get_fileline() << ": error: cannot perform a part " - << "select on array " << sig->name() << "." << endl; - des->errors += 1; - return 0; - } - ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT); - - NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1, true); - NetEConst*tmp = dynamic_cast(tmp_ex); - if (!tmp) { + // Evaluate all the index expressions into an + // "unpacked_indices" array. + listunpacked_indices; + bool flag = indices_to_expressions(des, scope, this, + path_tail.index, sig->unpacked_dimensions(), + true, + unpacked_indices, + unpacked_indices_const); + // Note that !flag includes that there were any other + // elaboration errors generating the unpacked_indices list. + if (!flag) { cerr << get_fileline() << ": error: array " << sig->name() << " index must be a constant in this context." << endl; des->errors += 1; return 0; } - widx_val = tmp->value().as_long(); - if (sig->array_index_is_valid(widx_val)) - widx = sig->array_index_to_address(widx_val); - else + NetExpr*canon_index = 0; + ivl_assert(*this, unpacked_indices_const.size() == sig->unpacked_dimensions()); + canon_index = normalize_variable_unpacked(sig, unpacked_indices_const); + if (canon_index == 0) { + // Normalize detected an out-of-bounds + // index. Indicate that by setting the generated + // widx to -1. widx = -1; - delete tmp_ex; + + } else { + NetEConst*canon_const = dynamic_cast(canon_index); + ivl_assert(*this, canon_const); + + widx = canon_const->value().as_long(); + delete canon_index; + } if (debug_elaborate) cerr << get_fileline() << ": debug: Use [" << widx << "]" << " to index l-value array." << endl; /* The array has a part/bit select at the end. */ - if (name_tail.index.size() > sig->array_dimensions()) { + if (path_tail.index.size() > sig->unpacked_dimensions()) { if (sig->get_scalar()) { cerr << get_fileline() << ": error: " << "can not select part of "; if (sig->data_type() == IVL_VT_REAL) cerr << "real"; else cerr << "scalar"; cerr << " array word: " << sig->name() - << "[" << widx_val << "]" << endl; + << as_indices(unpacked_indices_const) << endl; des->errors += 1; return 0; } @@ -550,7 +643,8 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, midx = midx_tmp; lidx = lidx_tmp; } - } else if (!name_tail.index.empty()) { + + } else if (!path_tail.index.empty()) { if (sig->get_scalar()) { cerr << get_fileline() << ": error: " << "can not select part of "; @@ -590,15 +684,16 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, if (widx < 0 || widx >= (long) sig->pin_count()) { cerr << get_fileline() << ": warning: ignoring out of " "bounds l-value array access " - << sig->name() << "[" << widx_val << "]." << endl; + << sig->name() << as_indices(unpacked_indices_const) << "." << endl; return 0; } + netvector_t*tmp2_vec = new netvector_t(sig->data_type(), + sig->vector_width()-1,0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - sig->type(), sig->vector_width()); + sig->type(), tmp2_vec); tmp->set_line(*this); tmp->local_flag(true); - tmp->data_type( sig->data_type() ); connect(sig->pin(widx), tmp->pin(0)); sig = tmp; } @@ -622,10 +717,11 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, << " wid=" << subnet_wid <<"]" << endl; + netvector_t*tmp2_vec = new netvector_t(sig->data_type(), + subnet_wid-1,0); NetNet*subsig = new NetNet(sig->scope(), sig->scope()->local_symbol(), - NetNet::WIRE, subnet_wid); - subsig->data_type( sig->data_type() ); + NetNet::WIRE, tmp2_vec); subsig->local_flag(true); subsig->set_line(*this); @@ -675,9 +771,9 @@ NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const * instantiation (PGModule::elaborate_mod_) to get NetNet objects for * the port. */ -NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const +NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const { - assert(scope->type() == NetScope::MODULE); + ivl_assert(*this, scope->type() == NetScope::MODULE); NetNet*sig = des->find_signal(scope, path_); if (sig == 0) { cerr << get_fileline() << ": error: no wire/reg " << path_ @@ -732,17 +828,17 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const /* If this is a part select of the entire signal (or no part select at all) then we're done. */ if ((lidx == 0) && (midx == (long)sig->vector_width()-1)) { - scope->add_module_port(sig); + scope->add_module_port_net(sig); return sig; } unsigned swid = abs(midx - lidx) + 1; ivl_assert(*this, swid > 0 && swid < sig->vector_width()); + netvector_t*tmp2_vec = new netvector_t(sig->data_type(),swid-1,0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, swid); + NetNet::WIRE, tmp2_vec); tmp->port_type(sig->port_type()); - tmp->data_type(sig->data_type()); tmp->set_line(*this); tmp->local_flag(true); NetNode*ps = 0; @@ -779,7 +875,7 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const ps->set_line(*this); des->add_node(ps); - scope->add_module_port(sig); + scope->add_module_port_net(sig); return sig; } diff --git a/elab_scope.cc b/elab_scope.cc index 5d8af02dc..1341fb064 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -33,8 +33,10 @@ */ # include "Module.h" -# include "PEvent.h" +# include "PClass.h" # include "PExpr.h" +# include "PEvent.h" +# include "PClass.h" # include "PGate.h" # include "PGenerate.h" # include "PTask.h" @@ -42,6 +44,7 @@ # include "Statement.h" # include "AStatement.h" # include "netlist.h" +# include "netclass.h" # include "netenum.h" # include "util.h" # include @@ -51,7 +54,9 @@ typedef map::const_iterator mparm_it_t; static void collect_parm_item_(Design*des, NetScope*scope, perm_string name, - const LexicalScope::param_expr_t&cur) + const LexicalScope::param_expr_t&cur, + bool is_annotatable, + bool local_flag) { NetScope::range_t*range_list = 0; for (LexicalScope::range_t*range = cur.range ; range ; range = range->next) { @@ -87,8 +92,9 @@ static void collect_parm_item_(Design*des, NetScope*scope, perm_string name, range_list = tmp; } - scope->set_parameter(name, cur.expr, cur.type, cur.msb, cur.lsb, - cur.signed_flag, range_list, cur); + + scope->set_parameter(name, is_annotatable, cur.expr, cur.type, cur.msb, + cur.lsb, cur.signed_flag, local_flag, range_list, cur); } static void collect_scope_parameters_(Design*des, NetScope*scope, @@ -106,7 +112,7 @@ static void collect_scope_parameters_(Design*des, NetScope*scope, des->errors += 1; } - collect_parm_item_(des, scope, (*cur).first, (*cur).second); + collect_parm_item_(des, scope, (*cur).first, (*cur).second, false, false); } } @@ -125,7 +131,26 @@ static void collect_scope_localparams_(Design*des, NetScope*scope, des->errors += 1; } - collect_parm_item_(des, scope, (*cur).first, (*cur).second); + collect_parm_item_(des, scope, (*cur).first, (*cur).second, false, true); + } +} + +static void collect_scope_specparams_(Design*des, NetScope*scope, + const map&specparams) +{ + for (mparm_it_t cur = specparams.begin() + ; cur != specparams.end() ; ++ cur ) { + + // A specparam can not have the same name as a genvar. + if (scope->find_genvar((*cur).first)) { + cerr << cur->second.get_fileline() + << ": error: specparam and genvar in '" + << scope->fullname() << "' have the same name '" + << (*cur).first << "'." << endl; + des->errors += 1; + } + + collect_parm_item_(des, scope, (*cur).first, (*cur).second, true, false); } } @@ -159,12 +184,12 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, verinum max_value (0); if (enum_type->signed_flag) { min_value = v_not((pow(verinum(2), - verinum(use_enum->base_width()-1)))) + + verinum(use_enum->packed_width()-1)))) + one_value; - max_value = pow(verinum(2), verinum(use_enum->base_width()-1)) - + max_value = pow(verinum(2), verinum(use_enum->packed_width()-1)) - one_value; } else { - max_value = pow(verinum(2), verinum(use_enum->base_width())) - + max_value = pow(verinum(2), verinum(use_enum->packed_width())) - one_value; } min_value.has_sign(true); @@ -227,15 +252,15 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, // The values are explicitly sized to the width of the // base type of the enumeration. verinum tmp_val (0); - if (cur_value.len() < use_enum->base_width()) { + if (cur_value.len() < (unsigned long)use_enum->packed_width()) { // Pad the current value if it is narrower than the final // width of the enum. - tmp_val = pad_to_width (cur_value, use_enum->base_width()); + tmp_val = pad_to_width (cur_value, use_enum->packed_width()); tmp_val.has_len(true); } else { // Truncate an oversized value. We report out of bound // values above. This may create duplicates. - tmp_val = verinum(cur_value, use_enum->base_width()); + tmp_val = verinum(cur_value, use_enum->packed_width()); } tmp_val.has_sign(enum_type->signed_flag); @@ -264,6 +289,30 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope, } } +static void elaborate_scope_class(Design*des, NetScope*scope, + PClass*pclass) +{ + class_type_t*use_type = pclass->type; + netclass_t*use_class = new netclass_t(use_type->name); + + for (map::iterator cur = use_type->properties.begin() + ; cur != use_type->properties.end() ; ++ cur) { + ivl_type_s*tmp = cur->second->elaborate_type(des, scope); + use_class->set_property(cur->first, tmp); + } + + scope->add_class(use_class); +} + +static void elaborate_scope_classes(Design*des, NetScope*scope, + const map&classes) +{ + for (map::const_iterator cur = classes.begin() + ; cur != classes.end() ; ++ cur) { + elaborate_scope_class(des, scope, cur->second); + } +} + static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc, const Module::replace_t&replacements) { @@ -469,6 +518,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, collect_scope_localparams_(des, scope, localparams); + collect_scope_specparams_(des, scope, specparams); + // Run parameter replacements that were collected from the // containing scope and meant for me. @@ -476,6 +527,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, elaborate_scope_enumerations(des, scope, enum_sets); + elaborate_scope_classes(des, scope, classes); + // Run through the defparams for this module and save the result // in a table for later final override. @@ -519,6 +572,19 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, elaborate_scope_funcs(des, scope, funcs); + // Look for implicit modules and implicit gates for them. + + for (map::iterator cur = nested_modules.begin() + ; cur != nested_modules.end() ; ++cur) { + // Skip modules that must be explicitly instantiated. + if (cur->second->port_count() > 0) + continue; + + PGModule*nested_gate = new PGModule(cur->second, cur->second->mod_name()); + nested_gate->set_line(*cur->second); + gates_.push_back(nested_gate); + } + // Gates include modules, which might introduce new scopes, so // scan all of them to create those scopes. @@ -708,7 +774,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) genvar_verinum); // The file and line information should really come // from the genvar statement, not the for loop. - scope->set_localparam(loop_index, gp, *this); + scope->set_parameter(loop_index, gp, *this); if (debug_scopes) cerr << get_fileline() << ": debug: " << "Create implicit localparam " @@ -1054,6 +1120,21 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) scope->add_genvar((*cur).first, (*cur).second); } + // Scan the localparams in this scope, and store the information + // needed to evaluate the parameter expressions. The expressions + // will be evaluated later, once all parameter overrides for this + // module have been done. + collect_scope_localparams_(des, scope, localparams); + + // Run through the defparams for this scope and save the result + // in a table for later final override. + + typedef list::const_iterator defparms_iter_t; + for (defparms_iter_t cur = defparms.begin() + ; cur != defparms.end() ; ++ cur ) { + scope->defparams.push_back(make_pair(cur->first, cur->second)); + } + // Scan the generated scope for nested generate schemes, // and *generate* new scopes, which is slightly different // from simple elaboration. @@ -1064,12 +1145,6 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) (*cur) -> generate_scope(des, scope); } - // Scan the localparams in this scope, and store the information - // needed to evaluate the parameter expressions. The expressions - // will be evaluated later, once all parameter overrides for this - // module have been done. - collect_scope_localparams_(des, scope, localparams); - // Scan through all the task and function declarations in this // scope. elaborate_scope_tasks(des, scope, tasks); @@ -1307,8 +1382,12 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s << "." << endl; } - // Create the new scope as a MODULE with my name. - NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE); + // Create the new scope as a MODULE with my name. Note + // that if this is a nested module, mark it thus so that + // scope searches will continue into the parent scope. + NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE, + bound_type_? true : false, + mod->program_block); my_scope->set_line(get_file(), mod->get_file(), get_lineno(), mod->get_lineno()); my_scope->set_module_name(mod->mod_name()); @@ -1525,7 +1604,9 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const << "Elaborate block scope " << use_name << " within " << scope_path(scope) << endl; - my_scope = new NetScope(scope, use_name, bl_type_==BL_PAR + // The scope type is begin-end or fork-join. The + // sub-types of fork-join are not interesting to the scope. + my_scope = new NetScope(scope, use_name, bl_type_!=BL_SEQ ? NetScope::FORK_JOIN : NetScope::BEGIN_END); my_scope->set_line(get_file(), get_lineno()); diff --git a/elab_sig.cc b/elab_sig.cc index f5ba9d4ca..1ca0ad751 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 @@ -14,11 +15,12 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" +# include # include # include @@ -32,10 +34,17 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netclass.h" +# include "netenum.h" # include "netstruct.h" +# include "netvector.h" +# include "netdarray.h" +# include "netparray.h" # include "util.h" # include "ivl_assert.h" +using namespace std; + static bool get_const_argument(NetExpr*exp, verinum&res) { switch (exp->expr_type()) { @@ -388,7 +397,6 @@ bool PGenerate::elaborate_sig_direct_(Design*des, NetScope*container) const ; cur != generate_schemes.end() ; ++ cur ) { PGenerate*item = *cur; if (item->scheme_type == PGenerate::GS_CASE) { - typedef list::const_iterator generate_it_t; for (generate_it_t icur = item->generate_schemes.begin() ; icur != item->generate_schemes.end() ; ++ icur ) { PGenerate*case_item = *icur; @@ -479,6 +487,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const } NetNet*ret_sig = 0; + netvector_t*ret_vec = 0; /* Create the signals/variables of the return value and write them into the function scope. */ @@ -514,50 +523,51 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const des->errors += 1; } - list packed; - packed.push_back(NetNet::range_t(mnum, lnum)); - ret_sig = new NetNet(scope, fname, NetNet::REG, packed); - ret_sig->set_scalar(false); + vector packed; + packed.push_back(netrange_t(mnum, lnum)); + ret_vec = new netvector_t(packed, IVL_VT_LOGIC); + ret_vec->set_signed(return_type_.type == PTF_REG_S); + ret_vec->set_scalar(false); + ret_sig = new NetNet(scope, fname, NetNet::REG, ret_vec); } else { - ret_sig = new NetNet(scope, fname, NetNet::REG); - ret_sig->set_scalar(true); + ret_vec = new netvector_t(IVL_VT_LOGIC); + ret_vec->set_signed(return_type_.type == PTF_REG_S); + ret_vec->set_scalar(true); + ret_sig = new NetNet(scope, fname, NetNet::REG, ret_vec); } ret_sig->set_line(*this); - ret_sig->set_signed(return_type_.type == PTF_REG_S); ret_sig->port_type(NetNet::POUTPUT); - ret_sig->data_type(IVL_VT_LOGIC); break; case PTF_INTEGER: - ret_sig = new NetNet(scope, fname, NetNet::REG, integer_width); + ret_vec = new netvector_t(IVL_VT_LOGIC, integer_width-1,0); + ret_vec->set_signed(true); + ret_vec->set_isint(true); + ret_vec->set_scalar(false); + ret_sig = new NetNet(scope, fname, NetNet::REG, ret_vec); ret_sig->set_line(*this); - ret_sig->set_signed(true); - ret_sig->set_isint(true); - ret_sig->set_scalar(false); ret_sig->port_type(NetNet::POUTPUT); - ret_sig->data_type(IVL_VT_LOGIC); break; case PTF_TIME: - ret_sig = new NetNet(scope, fname, NetNet::REG, 64); + ret_vec = new netvector_t(IVL_VT_LOGIC, 64-1,0); + ret_vec->set_isint(false); + ret_vec->set_scalar(false); + ret_sig = new NetNet(scope, fname, NetNet::REG, ret_vec); ret_sig->set_line(*this); - ret_sig->set_signed(false); - ret_sig->set_isint(false); - ret_sig->set_scalar(false); ret_sig->port_type(NetNet::POUTPUT); - ret_sig->data_type(IVL_VT_LOGIC); break; case PTF_REAL: case PTF_REALTIME: - ret_sig = new NetNet(scope, fname, NetNet::REG, 1); + ret_vec = new netvector_t(IVL_VT_REAL); + ret_vec->set_signed(true); + ret_vec->set_isint(false); + ret_vec->set_scalar(true); + ret_sig = new NetNet(scope, fname, NetNet::REG, ret_vec); ret_sig->set_line(*this); - ret_sig->set_signed(true); - ret_sig->set_isint(false); - ret_sig->set_scalar(true); ret_sig->port_type(NetNet::POUTPUT); - ret_sig->data_type(IVL_VT_REAL); break; case PTF_ATOM2: @@ -592,13 +602,13 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const use_wid = mnum - lnum + 1; } - ret_sig = new NetNet(scope, fname, NetNet::REG, use_wid); + ret_vec = new netvector_t(IVL_VT_BOOL, use_wid-1, 0); + ret_vec->set_isint(true); + ret_vec->set_scalar(false); + ret_vec->set_signed(return_type_.type == PTF_ATOM2_S? true : false); + ret_sig = new NetNet(scope, fname, NetNet::REG, ret_vec); ret_sig->set_line(*this); - ret_sig->set_signed(return_type_.type == PTF_ATOM2_S? true : false); - ret_sig->set_isint(true); - ret_sig->set_scalar(false); ret_sig->port_type(NetNet::POUTPUT); - ret_sig->data_type(IVL_VT_BOOL); break; case PTF_STRING: @@ -624,7 +634,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const } } - svectorports (ports_? ports_->count() : 0); + vectorports (ports_? ports_->count() : 0); if (ports_) for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) { @@ -813,64 +823,18 @@ 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, + vector&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; + long use_msb, use_lsb; NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); - if (! eval_as_long(lrng.msb, texpr)) { + if (! eval_as_long(use_msb, texpr)) { cerr << cur->first->get_fileline() << ": error: " "Range expressions must be constant." << endl; cerr << cur->first->get_fileline() << " : " @@ -883,7 +847,7 @@ static bool evaluate_ranges(Design*des, NetScope*scope, delete texpr; texpr = elab_and_eval(des, scope, cur->second, -1, true); - if (! eval_as_long(lrng.lsb, texpr)) { + if (! eval_as_long(use_lsb, texpr)) { cerr << cur->second->get_fileline() << ": error: " "Range expressions must be constant." << endl; cerr << cur->second->get_fileline() << " : " @@ -895,23 +859,97 @@ static bool evaluate_ranges(Design*des, NetScope*scope, delete texpr; - llist.push_back(lrng); + llist.push_back(netrange_t(use_msb, use_lsb)); } return bad_msb | bad_lsb; } -bool test_ranges_eeq(const list&lef, const list&rig) +static netclass_t* locate_class_type(Design*des, NetScope*scope, + class_type_t*class_type) +{ + netclass_t*use_class = scope->find_class(class_type->name); + return use_class; +} + +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) { + + vectorpacked_dimensions; + + struct_member_t*curp = *cur; + if (curp->range.get() && ! curp->range->empty()) { + bool bad_range; + bad_range = evaluate_ranges(des, scope, packed_dimensions, *curp->range); + ivl_assert(*curp, !bad_range); + } else { + packed_dimensions.push_back(netrange_t(0,0)); + } + + 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.packed_dims = packed_dimensions; + res->append_member(memb); + } + } + + return res; +} + +static ivl_type_s*elaborate_type(Design*des, NetScope*scope, + data_type_t*pform_type) +{ + if (struct_type_t*struct_type = dynamic_cast(pform_type)) { + netstruct_t*use_type = elaborate_struct_type(des, scope, struct_type); + return use_type; + } + + cerr << pform_type->get_fileline() << ": sorry: I don't know how to elaborate " + << typeid(*pform_type).name() << " here." << endl; + des->errors += 1; + + return 0; +} + +static netparray_t* elaborate_parray_type(Design*des, NetScope*scope, + parray_type_t*data_type) +{ + + vectorpacked_dimensions; + bool bad_range = evaluate_ranges(des, scope, packed_dimensions, * data_type->packed_dims); + ivl_assert(*data_type, !bad_range); + + ivl_type_s*element_type = elaborate_type(des, scope, data_type->base_type); + + netparray_t*res = new netparray_t(packed_dimensions, element_type); + //res->set_line(*data_type); + + return res; +} + +bool test_ranges_eeq(const vector&lef, const vector&rig) { if (lef.size() != rig.size()) return false; - list::const_iterator lcur = lef.begin(); - list::const_iterator rcur = rig.begin(); + vector::const_iterator lcur = lef.begin(); + vector::const_iterator rcur = rig.begin(); while (lcur != lef.end()) { - if (lcur->msb != rcur->msb) + if (lcur->get_msb() != rcur->get_msb()) return false; - if (lcur->lsb != rcur->lsb) + if (lcur->get_lsb() != rcur->get_lsb()) return false; ++ lcur; @@ -942,7 +980,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } unsigned wid = 1; - listpacked_dimensions; + vectorpacked_dimensions; des->errors += error_cnt_; @@ -983,7 +1021,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (port_set_ || net_set_) { bool bad_range = false; - list plist, nlist; + vector plist, nlist; /* If they exist get the port definition MSB and LSB */ if (port_set_ && !port_.empty()) { bad_range |= evaluate_ranges(des, scope, plist, port_); @@ -1049,7 +1087,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } packed_dimensions = nlist; - wid = NetNet::vector_width(packed_dimensions); + wid = netrange_width(packed_dimensions); } @@ -1057,19 +1095,32 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib, des, scope); - long array_s0 = 0; - long array_e0 = 0; - unsigned array_dimensions = 0; - /* If the ident has idx expressions, then this is a - memory. It can only have the idx registers after the msb - and lsb expressions are filled. And, if it has one index, - it has both. */ - if (lidx_ || ridx_) { - assert(lidx_ && ridx_); + listunpacked_dimensions; + netdarray_t*netarray = 0; - NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1, true); - NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1, true); + for (list::const_iterator cur = unpacked_.begin() + ; cur != unpacked_.end() ; ++cur) { + PExpr*use_lidx = cur->first; + PExpr*use_ridx = cur->second; + + // Special case: If we encounter an undefined + // dimensions, then turn this into a dynamic array and + // put all the packed dimensions there. + if (use_lidx==0 && use_ridx==0) { + netvector_t*vec = new netvector_t(packed_dimensions, data_type_); + packed_dimensions.clear(); + ivl_assert(*this, netarray==0); + netarray = new netdarray_t(vec); + continue; + } + + // Cannot handle dynamic arrays of arrays yet. + ivl_assert(*this, netarray==0); + ivl_assert(*this, use_lidx && use_ridx); + + NetExpr*lexp = elab_and_eval(des, scope, use_lidx, -1, true); + NetExpr*rexp = elab_and_eval(des, scope, use_ridx, -1, true); if ((lexp == 0) || (rexp == 0)) { cerr << get_fileline() << ": internal error: There is " @@ -1086,19 +1137,21 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const delete rexp; delete lexp; - if (!const_flag) { + long index_l, index_r; + if (! const_flag) { cerr << get_fileline() << ": error: The indices " << "are not constant for array ``" << name_ << "''." << endl; des->errors += 1; /* Attempt to recover from error, */ - array_s0 = 0; - array_e0 = 0; + index_l = 0; + index_r = 0; } else { - array_s0 = lval.as_long(); - array_e0 = rval.as_long(); - } - array_dimensions = 1; + index_l = lval.as_long(); + index_r = rval.as_long(); + } + + unpacked_dimensions.push_back(netrange_t(index_l, index_r)); } if (data_type_ == IVL_VT_REAL && !packed_dimensions.empty()) { @@ -1151,10 +1204,20 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const NetNet*sig = 0; - // If this is a struct type, then build the net with the - // struct type. - if (struct_type_) { - netstruct_t*use_type = elaborate_struct_type(des, scope, struct_type_); + if (class_type_t*class_type = dynamic_cast(set_data_type_)) { + // If this is a class variable, then the class type + // should already have been elaborated. All we need to + // do right now is locate the netclass_t object for the + // class, and use that to build the net. + netclass_t*use_type = locate_class_type(des, scope, class_type); + // (No arrays of classes) + list use_unpacked; + sig = new NetNet(scope, name_, wtype, use_unpacked, use_type); + + } else if (struct_type_t*struct_type = dynamic_cast(set_data_type_)) { + // If this is a struct type, then build the net with the + // struct type. + netstruct_t*use_type = elaborate_struct_type(des, scope, struct_type); if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype; if (use_type->packed()) @@ -1167,54 +1230,90 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig = new NetNet(scope, name_, wtype, use_type); + } else if (enum_type_t*enum_type = dynamic_cast(set_data_type_)) { + list::const_iterator sample_name = enum_type->names->begin(); + netenum_t*use_enum = scope->enumeration_for_name(sample_name->name); + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Create signal " << wtype + << " enumeration " + << name_ << " in scope " << scope_path(scope) + << " with packed_dimensions=" << packed_dimensions + << " and packed_width=" << use_enum->packed_width() << endl; + } + + ivl_assert(*this, packed_dimensions.empty()); + sig = new NetNet(scope, name_, wtype, unpacked_dimensions, use_enum); + + + } else if (netarray) { + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Create signal " << wtype + << " dynamic array " + << name_ << " in scope " << scope_path(scope) << endl; + } + + ivl_assert(*this, packed_dimensions.empty()); + ivl_assert(*this, unpacked_dimensions.empty()); + sig = new NetNet(scope, name_, wtype, netarray); + + } else if (parray_type_t*parray_type = dynamic_cast(set_data_type_)) { + // The pform gives us a parray_type_t for packed arrays + // that show up in type definitions. This can be handled + // a lot like packed dimensions from other means. + + // The trick here is that the parray type has an + // arbitrary sub-type, and not just a scalar bit... + netparray_t*use_type = elaborate_parray_type(des, scope, parray_type); + // Should not be getting packed dimensions other then + // through the parray type declaration. + ivl_assert(*this, packed_dimensions.empty()); + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Create signal " << wtype + << " parray=" << use_type->packed_dimensions() + << " " << name_ << unpacked_dimensions + << " in scope " << scope_path(scope) << endl; + } + + sig = new NetNet(scope, name_, wtype, unpacked_dimensions, 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 << " " << name_ << unpacked_dimensions; 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); - } + ivl_variable_type_t use_data_type = data_type_; + if (use_data_type == IVL_VT_NO_TYPE) { + use_data_type = IVL_VT_LOGIC; + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Signal " << name_ + << " in scope " << scope_path(scope) + << " defaults to data type " << use_data_type << endl; + } + } + + netvector_t*vec = new netvector_t(packed_dimensions, use_data_type); + vec->set_signed(get_signed()); + vec->set_isint(get_isint()); + if (is_implicit_scalar) vec->set_scalar(true); + else vec->set_scalar(get_scalar()); + packed_dimensions.clear(); + sig = new NetNet(scope, name_, wtype, unpacked_dimensions, vec); - // 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); - sig->set_enumeration(use_enum); } if (wtype == NetNet::WIRE) sig->devirtualize_pins(); - - ivl_variable_type_t use_data_type = data_type_; - if (use_data_type == IVL_VT_NO_TYPE) { - use_data_type = IVL_VT_LOGIC; - if (debug_elaborate) { - cerr << get_fileline() << ": debug: " - << "Signal " << name_ - << " in scope " << scope_path(scope) - << " defaults to data type " << use_data_type << endl; - } - } - - sig->data_type(use_data_type); sig->set_line(*this); sig->port_type(port_type_); - sig->set_signed(get_signed()); - sig->set_isint(get_isint()); - if (is_implicit_scalar) sig->set_scalar(true); - else sig->set_scalar(get_scalar()); if (ivl_discipline_t dis = get_discipline()) { sig->set_discipline(dis); diff --git a/elab_sig_analog.cc b/elab_sig_analog.cc index 82b8b9e68..6907a35a3 100644 --- a/elab_sig_analog.cc +++ b/elab_sig_analog.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/elab_type.cc b/elab_type.cc new file mode 100644 index 000000000..06938b66f --- /dev/null +++ b/elab_type.cc @@ -0,0 +1,64 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "pform_types.h" +# include "netlist.h" +# include "netvector.h" +# include +# include "ivl_assert.h" + +using namespace std; + +ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*) const +{ + cerr << get_fileline() << ": internal error: " + << "Elaborate method not implemented for " << typeid(*this).name() + << "." << endl; + des->errors += 1; + return 0; +} + +ivl_type_s* atom2_type_t::elaborate_type(Design*des, NetScope*) const +{ + switch (type_code) { + case 32: + if (signed_flag) + return &netvector_t::atom2s32; + else + return &netvector_t::atom2u32; + + case 16: + if (signed_flag) + return &netvector_t::atom2s16; + else + return &netvector_t::atom2u16; + + case 8: + if (signed_flag) + return &netvector_t::atom2s8; + else + return &netvector_t::atom2u8; + + default: + cerr << get_fileline() << ": internal error: " + << "atom2_type_t type_code=" << type_code << "." << endl; + des->errors += 1; + return 0; + } +} diff --git a/elaborate.cc b/elaborate.cc index 77a82f745..c618f7d5a 100644 --- a/elaborate.cc +++ b/elaborate.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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -35,6 +35,9 @@ # include "PGenerate.h" # include "PSpec.h" # include "netlist.h" +# include "netvector.h" +# include "netdarray.h" +# include "netclass.h" # include "netmisc.h" # include "util.h" # include "parse_api.h" @@ -75,8 +78,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: PGAssign: elaborated l-value" - << " width=" << lval->vector_width() - << ", type=" << lval->data_type() << endl; + << " width=" << lval->vector_width() << endl; } NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->data_type(), @@ -115,7 +117,6 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const cerr << get_fileline() << ": debug: PGAssign: elaborated r-value" << " width="<< rval->vector_width() << ", type="<< rval->data_type() - << ", signed="<< rval->get_signed() << ", expr=" << *rval_expr << endl; } @@ -164,11 +165,12 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const NetPartSelect::VP); des->add_node(tmp); tmp->set_line(*this); + netvector_t*osig_vec = new netvector_t(rval->data_type(), + lval->vector_width()-1,0); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::TRI, lval->vector_width()); + NetNet::TRI, osig_vec); osig->set_line(*this); osig->local_flag(true); - osig->data_type(rval->data_type()); connect(osig->pin(0), tmp->pin(0)); rval = osig; need_driver_flag = false; @@ -190,10 +192,11 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const connect(rval->pin(0), driver->pin(1)); + netvector_t*tmp_vec = new netvector_t(rval->data_type(), + rval->vector_width()-1,0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, rval->vector_width()); + NetNet::WIRE, tmp_vec); tmp->set_line(*this); - tmp->data_type(rval->data_type()); tmp->local_flag(true); connect(driver->pin(0), tmp->pin(0)); @@ -772,7 +775,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const NetExpr* rise_time, *fall_time, *decay_time; eval_delays(des, scope, rise_time, fall_time, decay_time); - struct attrib_list_t*attrib_list = 0; + struct attrib_list_t*attrib_list; unsigned attrib_list_n = 0; attrib_list = evaluate_attributes(attributes, attrib_list_n, des, scope); @@ -868,10 +871,11 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->add_node(rep); connect(rep->pin(1), sig->pin(0)); + netvector_t*osig_vec = new netvector_t(IVL_VT_LOGIC, + instance_width-1,0); sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, instance_width); + NetNet::WIRE, osig_vec); sig->set_line(*this); - sig->data_type(IVL_VT_LOGIC); sig->local_flag(true); connect(rep->pin(0), sig->pin(0)); @@ -948,12 +952,12 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const unsigned dev = gdx*gate_count; connect(cur[dev+idx]->pin(0), cc->pin(gdx+1)); + netvector_t*tmp2_vec = new netvector_t(IVL_VT_LOGIC); NetNet*tmp2 = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); + NetNet::WIRE, tmp2_vec); tmp2->set_line(*this); tmp2->local_flag(true); - tmp2->data_type(IVL_VT_LOGIC); connect(cc->pin(gdx+1), tmp2->pin(0)); } @@ -965,11 +969,11 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const tmp1->set_line(*this); des->add_node(tmp1); connect(tmp1->pin(1), sig->pin(0)); + netvector_t*tmp2_vec = new netvector_t(sig->data_type()); NetNet*tmp2 = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); + NetNet::WIRE, tmp2_vec); tmp2->set_line(*this); tmp2->local_flag(true); - tmp2->data_type(sig->data_type()); connect(tmp1->pin(0), tmp2->pin(0)); unsigned use_idx = idx - gate_count + 1; unsigned dev = gdx*gate_count; @@ -996,8 +1000,9 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope, ivl_assert(*this, dir != NetNet::NOT_A_PORT); ivl_assert(*this, dir != NetNet::PIMPLICIT); + netvector_t*tmp_type = new netvector_t(IVL_VT_LOGIC, port_wid-1, 0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, port_wid); + NetNet::WIRE, tmp_type); tmp->local_flag(true); tmp->set_line(*this); @@ -1250,6 +1255,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const get_name() << "..." << endl; for (unsigned inst = 0 ; inst < instance.size() ; inst += 1) { rmod->elaborate(des, instance[inst]); + instance[inst]->set_num_ports( rmod->port_count() ); } if (debug_elaborate) cerr << get_fileline() << ": debug: ...done." << endl; @@ -1329,7 +1335,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const unconnected_port = true; } - // Inside the module, the port is zero or more signals + // Inside the module, the port connects zero or more signals // that were already elaborated. List all those signals // and the NetNet equivalents, for all the instances. vector mport = rmod->get_port(idx); @@ -1349,19 +1355,24 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // will be assembled in that order as well. NetScope*inst_scope = instance[instance.size()-inst-1]; + unsigned int prt_vector_width = 0; + PortType::Enum ptype = PortType::PIMPLICIT; // Scan the module sub-ports for this instance... for (unsigned ldx = 0 ; ldx < mport.size() ; ldx += 1) { unsigned lbase = inst * mport.size(); PEIdent*pport = mport[ldx]; assert(pport); - prts[lbase + ldx] - = pport->elaborate_port(des, inst_scope); - if (prts[lbase + ldx] == 0) + NetNet *netnet = pport->elaborate_subport(des, inst_scope); + prts[lbase + ldx] = netnet; + if (netnet == 0) continue; - assert(prts[lbase + ldx]); - prts_vector_width += prts[lbase + ldx]->vector_width(); + assert(netnet); + prts_vector_width += netnet->vector_width(); + prt_vector_width += netnet->vector_width(); + ptype = PortType::merged(netnet->port_type(), ptype); } + inst_scope->add_module_port_info(idx, rmod->get_port_name(idx), ptype, prt_vector_width ); } // If I find that the port is unconnected inside the @@ -1409,6 +1420,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const << "too complicated for elaboration." << endl; continue; } + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Elaborating INPUT port expression: " << *tmp_expr << endl; + } + sig = tmp_expr->synthesize(des, scope, tmp_expr); if (sig == 0) { cerr << pins[idx]->get_fileline() @@ -1426,11 +1443,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const des->add_node(tmp); connect(tmp->pin(1), sig->pin(0)); + netvector_t*tmp2_vec = new netvector_t(sig->data_type(), + sig->vector_width()-1,0); NetNet*tmp2 = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, sig->vector_width()); + NetNet::WIRE, tmp2_vec); tmp2->local_flag(true); tmp2->set_line(*this); - tmp2->data_type(sig->data_type()); connect(tmp->pin(0), tmp2->pin(0)); sig = tmp2; } @@ -1598,7 +1616,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const assert(sig); #ifndef NDEBUG - if ((prts.size() >= 1) + if ((! prts.empty()) && (prts[0]->port_type() != NetNet::PINPUT)) { assert(sig->type() != NetNet::REG); } @@ -1922,7 +1940,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const net->fall_time(fall_expr); net->decay_time(decay_expr); - struct attrib_list_t*attrib_list = 0; + struct attrib_list_t*attrib_list; unsigned attrib_list_n = 0; attrib_list = evaluate_attributes(attributes, attrib_list_n, des, scope); @@ -2068,6 +2086,10 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const bool PGModule::elaborate_sig(Design*des, NetScope*scope) const { + if (bound_type_) { + return elaborate_sig_mod_(des, scope, bound_type_); + } + // Look for the module type map::const_iterator mod = pform_modules.find(type_); if (mod != pform_modules.end()) @@ -2087,6 +2109,11 @@ bool PGModule::elaborate_sig(Design*des, NetScope*scope) const void PGModule::elaborate(Design*des, NetScope*scope) const { + if (bound_type_) { + elaborate_mod_(des, bound_type_, scope); + return; + } + // Look for the module type map::const_iterator mod = pform_modules.find(type_); if (mod != pform_modules.end()) { @@ -2108,10 +2135,16 @@ void PGModule::elaborate(Design*des, NetScope*scope) const void PGModule::elaborate_scope(Design*des, NetScope*sc) const { + // If the module type is known by design, then go right to it. + if (bound_type_) { + elaborate_scope_mod_(des, bound_type_, sc); + return; + } + // Look for the module type map::const_iterator mod = pform_modules.find(type_); if (mod != pform_modules.end()) { - elaborate_scope_mod_(des, (*mod).second, sc); + elaborate_scope_mod_(des, mod->second, sc); return; } @@ -2128,7 +2161,7 @@ void PGModule::elaborate_scope(Design*des, NetScope*sc) const // Try again to find the module type mod = pform_modules.find(type_); if (mod != pform_modules.end()) { - elaborate_scope_mod_(des, (*mod).second, sc); + elaborate_scope_mod_(des, mod->second, sc); return; } @@ -2163,6 +2196,17 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const return lval_->elaborate_lval(des, scope, false); } +NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, + ivl_type_t net_type) const +{ + ivl_assert(*this, rval_); + + NetExpr*rv = rval_->elaborate_expr(des, scope, net_type, 0); + + ivl_assert(*this, !is_constant_); + return rv; +} + NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, unsigned lv_width, ivl_variable_type_t lv_type) const @@ -2297,6 +2341,18 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const return cur; } +static bool lval_not_program_variable(const NetAssign_*lv) +{ + while (lv) { + NetScope*sig_scope = lv->sig()->scope(); + if (! sig_scope->program_block()) + return true; + + lv = lv->more; + } + return false; +} + NetProc* PAssign::elaborate(Design*des, NetScope*scope) const { assert(scope); @@ -2311,14 +2367,36 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const NetAssign_*lv = elaborate_lval(des, scope); if (lv == 0) return 0; + if (scope->program_block() && lval_not_program_variable(lv)) { + cerr << get_fileline() << ": error: Blocking assignments to " + << "non-program variables are not allowed." << endl; + des->errors += 1; + } + /* If there is an internal delay expression, elaborate it. */ NetExpr*delay = 0; if (delay_ != 0) delay = elaborate_delay_expr(delay_, des, scope); + NetExpr*rv; + const ivl_type_s*lv_net_type = lv->net_type(); + + /* If the l-value is a compound type of some sort, then use + the newer net_type form of the elaborate_rval_ method to + handle the new types. */ + if (dynamic_cast (lv_net_type)) { + ivl_assert(*this, lv->more==0); + rv = elaborate_rval_(des, scope, lv_net_type); + + } else if (dynamic_cast (lv_net_type)) { + ivl_assert(*this, lv->more==0); + rv = elaborate_rval_(des, scope, lv_net_type); + + } else { + /* Elaborate the r-value expression, then try to evaluate it. */ + rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type()); + } - /* Elaborate the r-value expression, then try to evaluate it. */ - NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type()); if (rv == 0) return 0; assert(rv); @@ -2343,11 +2421,11 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const if (delay || event_) { unsigned wid = count_lval_width(lv); + netvector_t*tmp2_vec = new netvector_t(rv->expr_type(),wid-1,0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::REG, wid); + NetNet::REG, tmp2_vec); tmp->local_flag(true); tmp->set_line(*this); - tmp->data_type(rv->expr_type()); NetESignal*sig = new NetESignal(tmp); @@ -2438,10 +2516,17 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const if (lv->expr_type() == IVL_VT_BOOL && rv->expr_type() != IVL_VT_BOOL) { if (debug_elaborate) - cerr << get_fileline() << ": debug: Cast expression to int2" << endl; + cerr << get_fileline() << ": debug: " + << "Cast expression to int2" << endl; rv = cast_to_int2(rv); } + if (lv->expr_type() == IVL_VT_REAL && rv->expr_type() != IVL_VT_REAL) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Cast expression to real." << endl; + rv = cast_to_real(rv); + } if (lv->enumeration() && (lv->enumeration() != rv->enumeration())) { cerr << get_fileline() << ": error: " << "Enumeration type mismatch in assignment." << endl; @@ -2454,6 +2539,22 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const return cur; } +/* + * Return true if any lvalue parts are in a program block scope. + */ +static bool lval_is_program_variable(const NetAssign_*lv) +{ + while (lv) { + NetScope*sig_scope = lv->sig()->scope(); + if (sig_scope->program_block()) + return true; + + lv = lv->more; + } + + return false; +} + /* * Elaborate non-blocking assignments. The statement is of the general * form: @@ -2490,6 +2591,14 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const NetAssign_*lv = elaborate_lval(des, scope); if (lv == 0) return 0; + if (scope->program_block() && lval_is_program_variable(lv)) { + cerr << get_fileline() << ": error: Non-blocking assignments to " + << "program variables are not allowed." << endl; + des->errors += 1; + // This is an error, but we can let elaboration continue + // because it would necessarily trigger other errors. + } + NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type()); if (rv == 0) return 0; @@ -2576,9 +2685,27 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const { assert(scope); - NetBlock::Type type = (bl_type_==PBlock::BL_PAR) - ? NetBlock::PARA - : NetBlock::SEQU; + NetBlock::Type type; + switch (bl_type_) { + case PBlock::BL_SEQ: + type = NetBlock::SEQU; + break; + case PBlock::BL_PAR: + type = NetBlock::PARA; + break; + case PBlock::BL_JOIN_NONE: + type = NetBlock::PARA_JOIN_NONE; + break; + case PBlock::BL_JOIN_ANY: + type = NetBlock::PARA_JOIN_ANY; + break; + // Added to remove a "type" uninitialized compiler warning. + // This should never be reached since all the PBlock enumeration + // cases are handled above. + default: + type = NetBlock::SEQU; + assert(0); + } NetScope*nscope = 0; if (pscope_name() != 0) { @@ -2695,7 +2822,7 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const a separate case for each. (Yes, the statement will be elaborated again for each.) */ PExpr*cur_expr = *idx_expr; - NetExpr*gu = 0; + NetExpr*gu; NetProc*st = 0; assert(cur_expr); gu = elab_and_eval(des, scope, cur_expr, -1); @@ -2833,7 +2960,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const if ((parm_count== 1) && (parms_[0] == 0)) parm_count = 0; - svectoreparms (parm_count); + vectoreparms (parm_count); perm_string name = peek_tail_name(path_); @@ -2912,6 +3039,12 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const NetScope*task = des->find_task(scope, path_); if (task == 0) { + // Maybe this is a method attached to a signal? + if (gn_system_verilog()) { + NetProc*tmp = elaborate_method_(des, scope); + if (tmp) return tmp; + } + cerr << get_fileline() << ": error: Enable of unknown task " << "``" << path_ << "''." << endl; des->errors += 1; @@ -3094,6 +3227,39 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const return block; } +NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const +{ + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + NetNet *net; + const NetExpr *par; + NetEvent *eve; + const NetExpr *ex1, *ex2; + + symbol_search(this, des, scope, use_path, + net, par, eve, ex1, ex2); + + if (net == 0) + return 0; + + // Is this a delete method for dynamic arrays? + if (net->darray_type() && method_name=="delete") { + NetESignal*sig = new NetESignal(net); + + vector argv (1); + argv[0] = sig; + + NetSTask*sys = new NetSTask("$ivl_darray_method$delete", + IVL_SFUNC_AS_TASK_IGNORE, argv); + sys->set_line(*this); + return sys; + } + + return 0; +} + /* * Elaborate a procedural continuous assign. This really looks very * much like other procedural assignments, at this point, but there @@ -4123,7 +4289,7 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const // Evaluate the attributes for this process, if there // are any. These attributes are to be attached to the // NetProcTop object. - struct attrib_list_t*attrib_list = 0; + struct attrib_list_t*attrib_list; unsigned attrib_list_n = 0; attrib_list = evaluate_attributes(attributes, attrib_list_n, des, scope); @@ -4443,53 +4609,11 @@ static void elaborate_tasks(Design*des, NetScope*scope, * When a module is instantiated, it creates the scope then uses this * method to elaborate the contents of the module. */ + bool Module::elaborate(Design*des, NetScope*scope) const { bool result_flag = true; - // Elaborate specparams - typedef map::const_iterator specparam_it_t; - for (specparam_it_t cur = specparams.begin() ; - cur != specparams.end() ; ++ cur ) { - - NetExpr*val = elab_and_eval(des, scope, (*cur).second, -1, true); - NetScope::spec_val_t value; - - if (NetECReal*val_cr = dynamic_cast (val)) { - - value.type = IVL_VT_REAL; - value.real_val = val_cr->value().as_double(); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate " - << "specparam " << (*cur).first - << " value=" << value.real_val << endl; - } - - } else if (NetEConst*val_c = dynamic_cast (val)) { - - value.type = IVL_VT_BOOL; - value.integer = val_c->value().as_long(); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate " - << "specparam " << (*cur).first - << " value=" << value.integer << endl; - } - - } else { - value.type = IVL_VT_NO_TYPE; - cerr << (*cur).second->get_fileline() << ": error: " - << "specparam " << (*cur).first - << " value is not constant: " << *val << endl; - des->errors += 1; - } - - assert(val); - delete val; - scope->specparams[(*cur).first] = value; - } - // Elaborate within the generate blocks. typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() @@ -4627,7 +4751,6 @@ bool PGenerate::elaborate_direct_(Design*des, NetScope*container) const // contain anything. Instead scan the case items, which // are listed as sub-schemes of the item. if (item->scheme_type == PGenerate::GS_CASE) { - typedef list::const_iterator generate_it_t; for (generate_it_t icur = item->generate_schemes.begin() ; icur != item->generate_schemes.end() ; ++ icur ) { PGenerate*case_item = *icur; @@ -4738,6 +4861,9 @@ class top_defparams : public elaborator_work_item_t { virtual void elaborate_runrun() { + if (debug_scopes) { + cerr << "debug: top_defparams::elaborate_runrun()" << endl; + } // This method recurses through the scopes, looking for // defparam assignments to apply to the parameters in the // various scopes. This needs to be done after all the scopes @@ -4749,6 +4875,10 @@ class top_defparams : public elaborator_work_item_t { // scopes and evaluate the parameters all the way down to // constants. des->evaluate_parameters(); + + if (debug_scopes) { + cerr << "debug: top_defparams::elaborate_runrun() done" << endl; + } } }; @@ -4762,6 +4892,10 @@ class later_defparams : public elaborator_work_item_t { virtual void elaborate_runrun() { + if (debug_scopes) { + cerr << "debug: later_defparams::elaborate_runrun()" << endl; + } + listtmp_list; for (set::iterator cur = des->defparams_later.begin() ; cur != des->defparams_later.end() ; ++ cur ) @@ -4774,7 +4908,13 @@ class later_defparams : public elaborator_work_item_t { tmp_list.pop_front(); cur->run_defparams_later(des); } - des->evaluate_parameters(); + + // The overridden parameters will be evaluated later in + // a top_defparams work item. + + if (debug_scopes) { + cerr << "debuf: later_defparams::elaborate_runrun() done" << endl; + } } }; @@ -4859,7 +4999,7 @@ Design* elaborate(listroots) // Make the root scope. This makes a NetScope object and // pushes it into the list of root scopes in the Design. - NetScope*scope = des->make_root_scope(*root); + NetScope*scope = des->make_root_scope(*root, rmod->program_block); // Collect some basic properties of this scope from the // Module definition. @@ -4933,10 +5073,22 @@ Design* elaborate(listroots) // creates all the NetNet and NetMemory objects for declared // objects. for (i = 0; i < root_elems.count(); i++) { + Module *rmod = root_elems[i]->mod; NetScope *scope = root_elems[i]->scope; + scope->set_num_ports( rmod->port_count() ); + + if (debug_elaborate) { + cerr << "" << ": debug: " << rmod->mod_name() + << ": port elaboration root " + << rmod->port_count() << " ports" << endl; + } if (! rmod->elaborate_sig(des, scope)) { + if (debug_elaborate) { + cerr << "" << ": debug: " << rmod->mod_name() + << ": elaborate_sig failed!!!" << endl; + } delete des; return 0; } @@ -4945,11 +5097,24 @@ Design* elaborate(listroots) // defined for the root modules. This code does that. for (unsigned idx = 0; idx < rmod->port_count(); idx += 1) { vector mport = rmod->get_port(idx); + unsigned int prt_vector_width = 0; + PortType::Enum ptype = PortType::PIMPLICIT; for (unsigned pin = 0; pin < mport.size(); pin += 1) { // This really does more than we need and adds extra // stuff to the design that should be cleaned later. - (void) mport[pin]->elaborate_port(des, scope); + NetNet *netnet = mport[pin]->elaborate_subport(des, scope); + if (netnet != 0) { + // Elaboration may actually fail with erroneous input source + prt_vector_width += netnet->vector_width(); + ptype = PortType::merged(netnet->port_type(), ptype); + } } + if (debug_elaborate) { + cerr << "" << ": debug: " << rmod->mod_name() + << ": adding module port " + << rmod->get_port_name(idx) << endl; + } + scope->add_module_port_info(idx, rmod->get_port_name(idx), ptype, prt_vector_width ); } } @@ -4976,5 +5141,11 @@ Design* elaborate(listroots) des = 0; } + if (debug_elaborate) { + cerr << "" << ": debug: " + << " finishing with " + << des->find_root_scopes().size() << " root scopes " << endl; + } + return des; } diff --git a/elaborate_analog.cc b/elaborate_analog.cc index 25cbdd4e6..8b901e3a8 100644 --- a/elaborate_analog.cc +++ b/elaborate_analog.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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -55,7 +55,7 @@ bool AProcess::elaborate(Design*des, NetScope*scope) const // Evaluate the attributes for this process, if there // are any. These attributes are to be attached to the // NetProcTop object. - struct attrib_list_t*attrib_list = 0; + struct attrib_list_t*attrib_list; unsigned attrib_list_n = 0; attrib_list = evaluate_attributes(attributes, attrib_list_n, des, scope); diff --git a/emit.cc b/emit.cc index 8411489a8..60a61f96c 100644 --- a/emit.cc +++ b/emit.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -385,6 +385,10 @@ void NetScope::emit_scope(struct target_t*tgt) const for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) tgt->event(cur); + for (map::const_iterator cur = classes_.begin() + ; cur != classes_.end() ; ++cur) + tgt->class_type(this, cur->second); + for (list::const_iterator cur = enum_sets_.begin() ; cur != enum_sets_.end() ; ++cur) tgt->enumeration(this, *cur); @@ -551,6 +555,21 @@ void NetENetenum::expr_scan(struct expr_scan_t*tgt) const tgt->expr_netenum(this); } +void NetENew::expr_scan(struct expr_scan_t*tgt) const +{ + tgt->expr_new(this); +} + +void NetENull::expr_scan(struct expr_scan_t*tgt) const +{ + tgt->expr_null(this); +} + +void NetEProperty::expr_scan(struct expr_scan_t*tgt) const +{ + tgt->expr_property(this); +} + void NetEScope::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_scope(this); diff --git a/eval.cc b/eval.cc index 84dbc5aea..996aacd4e 100644 --- a/eval.cc +++ b/eval.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/eval_attrib.cc b/eval_attrib.cc index a293fb14c..ecdf7efa8 100644 --- a/eval_attrib.cc +++ b/eval_attrib.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/eval_tree.cc b/eval_tree.cc index bbce3cbc2..d677e774d 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -34,11 +34,11 @@ NetExpr* NetExpr::eval_tree() return 0; } -static bool get_real_arg_(NetExpr*expr, verireal&val) +static bool get_real_arg_(const NetExpr*expr, verireal&val) { switch (expr->expr_type()) { case IVL_VT_REAL: { - NetECReal*c = dynamic_cast (expr); + const NetECReal*c = dynamic_cast (expr); if (c == 0) return false; val = c->value(); break; @@ -46,13 +46,16 @@ static bool get_real_arg_(NetExpr*expr, verireal&val) case IVL_VT_BOOL: case IVL_VT_LOGIC: { - NetEConst*c = dynamic_cast(expr); + const NetEConst*c = dynamic_cast(expr); if (c == 0) return false; verinum tmp = c->value(); val = verireal(tmp.as_double()); break; } + case IVL_VT_DARRAY: + return false; + default: assert(0); } @@ -60,7 +63,7 @@ static bool get_real_arg_(NetExpr*expr, verireal&val) return true; } -static bool get_real_arguments(NetExpr*le, NetExpr*re, +static bool get_real_arguments(const NetExpr*le, const NetExpr*re, double&lval, double&rval) { verireal val; @@ -82,15 +85,15 @@ bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval) return true; } -NetECReal* NetEBAdd::eval_tree_real_() +NetECReal* NetEBAdd::eval_tree_real_(const NetExpr*l, const NetExpr*r) const { - verireal lval; - verireal rval; + double lval; + double rval; - bool flag = get_real_arguments_(lval, rval); + bool flag = get_real_arguments(l, r, lval, rval); if (!flag) return 0; - verireal res_val; + double res_val; switch (op()) { case '+': @@ -103,7 +106,7 @@ NetECReal* NetEBAdd::eval_tree_real_() ivl_assert(*this, 0); } - NetECReal*res = new NetECReal( res_val ); + NetECReal*res = new NetECReal( verireal(res_val) ); ivl_assert(*this, res); res->set_line(*this); @@ -119,52 +122,24 @@ NetExpr* NetEBAdd::eval_tree() eval_expr(left_); eval_expr(right_); - if (expr_type() == IVL_VT_REAL) - return eval_tree_real_(); - - NetEConst*lc = dynamic_cast(left_); - NetEConst*rc = dynamic_cast(right_); - - /* If both operands are constant, then replace the entire - expression with a constant value. */ - if (lc != 0 && rc != 0) { - verinum lval = lc->value(); - verinum rval = rc->value(); - - unsigned wid = expr_width(); - ivl_assert(*this, wid > 0); - ivl_assert(*this, lval.len() == wid); - ivl_assert(*this, rval.len() == wid); - - verinum val; - switch (op_) { - case '+': - val = verinum(lval + rval, wid); - break; - case '-': - val = verinum(lval - rval, wid); - break; - default: - return 0; - } - - NetEConst *res = new NetEConst(val); - ivl_assert(*this, res); - res->set_line(*this); - - if (debug_eval_tree) - cerr << get_fileline() << ": debug: Evaluated: " << *this - << " --> " << *res << endl; - + // First try to elaborate the expression completely. + NetExpr*res = eval_arguments_(left_,right_); + if (res != 0) return res; - } - /* Try to combine a right constant value with the right - constant value of a sub-expression add. For example, the - expression (a + 2) - 1 can be rewritten as a + 1. */ + // If the expression type is real, then do not attempt the + // following alternative processing. + if (expr_type() == IVL_VT_REAL) + return 0; + + // The expression has not evaluated to a constant. Let's still + // try to optimize by trying to combine a right constant value + // with the right constant value of a sub-expression add. For + // example, the expression (a + 2) - 1 can be rewritten as a + 1. NetEBAdd*se = dynamic_cast(left_); - lc = se? dynamic_cast(se->right_) : 0; + NetEConst*lc = se? dynamic_cast(se->right_) : 0; + NetEConst*rc = dynamic_cast(right_); if (lc != 0 && rc != 0) { ivl_assert(*this, se != 0); @@ -200,11 +175,56 @@ NetExpr* NetEBAdd::eval_tree() tmp->set_line(*right_); delete right_; right_ = tmp; - /* We've changed the subexpression, but the result is - still not constant, so return nil here anyhow. */ - return 0; } + // We may have changed the subexpression, but the result is + // still not constant, so return nil here anyhow. + return 0; +} + +NetExpr* NetEBAdd::eval_arguments_(const NetExpr*l, const NetExpr*r) const +{ + if (expr_type() == IVL_VT_REAL) + return eval_tree_real_(l,r); + + const NetEConst*lc = dynamic_cast(l); + const NetEConst*rc = dynamic_cast(r); + + /* If both operands are constant, then replace the entire + expression with a constant value. */ + if (lc != 0 && rc != 0) { + verinum lval = lc->value(); + verinum rval = rc->value(); + + unsigned wid = expr_width(); + ivl_assert(*this, wid > 0); + ivl_assert(*this, lval.len() == wid); + ivl_assert(*this, rval.len() == wid); + + verinum val; + switch (op_) { + case '+': + val = verinum(lval + rval, wid); + break; + case '-': + val = verinum(lval - rval, wid); + break; + default: + return 0; + } + + NetEConst *res = new NetEConst(val); + ivl_assert(*this, res); + res->set_line(*this); + + if (debug_eval_tree) + cerr << get_fileline() << ": debug: Evaluated: " << *this + << " --> " << *res << endl; + + return res; + } + + /* Nothing more to be done, the value is not constant. */ return 0; } @@ -276,13 +296,12 @@ NetEConst* NetEBBits::eval_tree() return new NetEConst(res); } -NetEConst* NetEBComp::eval_less_() +NetEConst* NetEBComp::eval_less_(const NetExpr*le, const NetExpr*re) const { - if (right_->expr_type() == IVL_VT_REAL || - left_->expr_type() == IVL_VT_REAL) - return eval_leeq_real_(left_, right_, false); + if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL) + return eval_leeq_real_(le, re, false); - NetEConst*rc = dynamic_cast(right_); + const NetEConst*rc = dynamic_cast(re); if (rc == 0) return 0; verinum rv = rc->value(); @@ -292,12 +311,12 @@ NetEConst* NetEBComp::eval_less_() return res; } - if (NetEConst*tmp = must_be_leeq_(left_, rv, false)) { + if (NetEConst*tmp = must_be_leeq_(le, rv, false)) { return tmp; } /* Now go on to the normal test of the values. */ - NetEConst*lc = dynamic_cast(left_); + const NetEConst*lc = dynamic_cast(le); if (lc == 0) return 0; verinum lv = lc->value(); @@ -318,7 +337,7 @@ NetEConst* NetEBComp::eval_less_() } } -NetEConst* NetEBComp::must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag) +NetEConst* NetEBComp::must_be_leeq_(const NetExpr*le, const verinum&rv, bool eq_flag) const { assert(le->expr_width() > 0); verinum lv (verinum::V1, le->expr_width()); @@ -339,7 +358,7 @@ NetEConst* NetEBComp::must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag) return 0; } -NetEConst* NetEBComp::eval_leeq_real_(NetExpr*le, NetExpr*re, bool eq_flag) +NetEConst* NetEBComp::eval_leeq_real_(const NetExpr*le, const NetExpr*re, bool eq_flag) const { double lval; double rval; @@ -358,14 +377,13 @@ NetEConst* NetEBComp::eval_leeq_real_(NetExpr*le, NetExpr*re, bool eq_flag) return res; } -NetEConst* NetEBComp::eval_leeq_() +NetEConst* NetEBComp::eval_leeq_(const NetExpr*le, const NetExpr*re) const { - if (right_->expr_type() == IVL_VT_REAL || - left_->expr_type() == IVL_VT_REAL) - return eval_leeq_real_(left_, right_, true); + if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL) + return eval_leeq_real_(le, re, true); // assert(expr_type() == IVL_VT_LOGIC); - NetEConst*r = dynamic_cast(right_); + const NetEConst*r = dynamic_cast(re); if (r == 0) return 0; verinum rv = r->value(); @@ -375,18 +393,18 @@ NetEConst* NetEBComp::eval_leeq_() return res; } - if (left_->expr_width() == 0) { + if (le->expr_width() == 0) { cerr << get_fileline() << ": internal error: Something wrong " << "with the left side width of <= ?" << endl; cerr << get_fileline() << ": : " << *this << endl; } - if (NetEConst*tmp = must_be_leeq_(left_, rv, true)) { + if (NetEConst*tmp = must_be_leeq_(le, rv, true)) { return tmp; } /* Now go on to the normal test of the values. */ - NetEConst*l = dynamic_cast(left_); + const NetEConst*l = dynamic_cast(le); if (l == 0) return 0; verinum lv = l->value(); @@ -407,13 +425,12 @@ NetEConst* NetEBComp::eval_leeq_() } } -NetEConst* NetEBComp::eval_gt_() +NetEConst* NetEBComp::eval_gt_(const NetExpr*le, const NetExpr*re) const { - if (right_->expr_type() == IVL_VT_REAL || - left_->expr_type() == IVL_VT_REAL) - return eval_leeq_real_(right_, left_, false); + if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL) + return eval_leeq_real_(re, le, false); - NetEConst*l = dynamic_cast(left_); + const NetEConst*l = dynamic_cast(le); if (l == 0) return 0; verinum lv = l->value(); @@ -423,12 +440,12 @@ NetEConst* NetEBComp::eval_gt_() return res; } - if (NetEConst*tmp = must_be_leeq_(right_, lv, false)) { + if (NetEConst*tmp = must_be_leeq_(re, lv, false)) { return tmp; } /* Now go on to the normal test of the values. */ - NetEConst*r = dynamic_cast(right_); + const NetEConst*r = dynamic_cast(re); if (r == 0) return 0; verinum rv = r->value(); @@ -449,13 +466,12 @@ NetEConst* NetEBComp::eval_gt_() } } -NetEConst* NetEBComp::eval_gteq_() +NetEConst* NetEBComp::eval_gteq_(const NetExpr*le, const NetExpr*re) const { - if (right_->expr_type() == IVL_VT_REAL || - left_->expr_type() == IVL_VT_REAL) - return eval_leeq_real_(right_, left_, true); + if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL) + return eval_leeq_real_(re, le, true); - NetEConst*l = dynamic_cast(left_); + const NetEConst*l = dynamic_cast(left_); if (l == 0) return 0; verinum lv = l->value(); @@ -465,12 +481,12 @@ NetEConst* NetEBComp::eval_gteq_() return res; } - if (NetEConst*tmp = must_be_leeq_(right_, lv, true)) { + if (NetEConst*tmp = must_be_leeq_(re, lv, true)) { return tmp; } /* Now go on to the normal test of the values. */ - NetEConst*r = dynamic_cast(right_); + const NetEConst*r = dynamic_cast(re); if (r == 0) return 0; verinum rv = r->value(); @@ -498,15 +514,15 @@ NetEConst* NetEBComp::eval_gteq_() * are equal, but there are are x/z bits, then the situation is * ambiguous so the result is x. */ -NetEConst* NetEBComp::eval_eqeq_real_(bool ne_flag) +NetEConst* NetEBComp::eval_eqeq_real_(bool ne_flag, const NetExpr*le, const NetExpr*re) const { - verireal lval; - verireal rval; + double lval; + double rval; - bool flag = get_real_arguments_(lval, rval); + bool flag = get_real_arguments(le, re, lval, rval); if (! flag) return 0; - verinum result(((lval.as_double() == rval.as_double()) ^ ne_flag) ? + verinum result(((lval == rval) ^ ne_flag) ? verinum::V1 : verinum::V0, 1); NetEConst*res = new NetEConst(result); ivl_assert(*this, res); @@ -514,14 +530,14 @@ NetEConst* NetEBComp::eval_eqeq_real_(bool ne_flag) return res; } -NetEConst* NetEBComp::eval_eqeq_(bool ne_flag) +NetEConst* NetEBComp::eval_eqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const { - if (left_->expr_type() == IVL_VT_REAL || - right_->expr_type() == IVL_VT_REAL) - return eval_eqeq_real_(ne_flag); + if (le->expr_type() == IVL_VT_REAL || + re->expr_type() == IVL_VT_REAL) + return eval_eqeq_real_(ne_flag, le, re); - NetEConst*lc = dynamic_cast(left_); - NetEConst*rc = dynamic_cast(right_); + const NetEConst*lc = dynamic_cast(le); + const NetEConst*rc = dynamic_cast(re); if (lc == 0 || rc == 0) return 0; const verinum&lv = lc->value(); @@ -631,10 +647,10 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag) return result; } -NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag) +NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const { - NetEConst*lc = dynamic_cast(left_); - NetEConst*rc = dynamic_cast(right_); + const NetEConst*lc = dynamic_cast(le); + const NetEConst*rc = dynamic_cast(re); if (lc == 0 || rc == 0) return 0; const verinum&lv = lc->value(); @@ -687,47 +703,54 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag) return result; } +NetEConst* NetEBComp::eval_arguments_(const NetExpr*l, const NetExpr*r) const +{ + NetEConst*res = 0; + + switch (op_) { + case 'E': // Case equality (===) + res = eval_eqeqeq_(false, l, r); + break; + + case 'e': // Equality (==) + res = eval_eqeq_(false, l, r); + break; + + case 'G': // >= + res = eval_gteq_(l, r); + break; + + case 'L': // <= + res = eval_leeq_(l, r); + break; + + case 'N': // Case inequality (!==) + res = eval_eqeqeq_(true, l, r); + break; + + case 'n': // not-equal (!=) + res = eval_eqeq_(true, l, r); + break; + + case '<': // Less than + res = eval_less_(l, r); + break; + + case '>': // Greater than + res = eval_gt_(l, r); + break; + + } + + return res; +} + NetEConst* NetEBComp::eval_tree() { eval_expr(left_); eval_expr(right_); - NetEConst*res = 0; - - switch (op_) { - case 'E': // Case equality (===) - res = eval_eqeqeq_(false); - break; - - case 'e': // Equality (==) - res = eval_eqeq_(false); - break; - - case 'G': // >= - res = eval_gteq_(); - break; - - case 'L': // <= - res = eval_leeq_(); - break; - - case 'N': // Case inequality (!==) - res = eval_eqeqeq_(true); - break; - - case 'n': // not-equal (!=) - res = eval_eqeq_(true); - break; - - case '<': // Less than - res = eval_less_(); - break; - - case '>': // Greater than - res = eval_gt_(); - break; - - } + NetEConst*res = eval_arguments_(left_, right_); if (res == 0) return 0; res->set_line(*this); @@ -934,15 +957,15 @@ NetEConst* NetEBLogic::eval_tree() } -NetExpr* NetEBMult::eval_tree_real_() +NetExpr* NetEBMult::eval_tree_real_(const NetExpr*l, const NetExpr*r) const { - verireal lval; - verireal rval; + double lval; + double rval; - bool flag = get_real_arguments_(lval, rval); + bool flag = get_real_arguments(l, r, lval, rval); if (! flag) return 0; - NetECReal*res = new NetECReal(lval * rval); + NetECReal*res = new NetECReal( verireal(lval * rval) ); ivl_assert(*this, res); res->set_line(*this); @@ -958,11 +981,16 @@ NetExpr* NetEBMult::eval_tree() eval_expr(left_); eval_expr(right_); - if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); + return eval_arguments_(left_, right_); +} + +NetExpr* NetEBMult::eval_arguments_(const NetExpr*l, const NetExpr*r) const +{ + if (expr_type() == IVL_VT_REAL) return eval_tree_real_(l,r); assert(expr_type() == IVL_VT_LOGIC); - NetEConst*lc = dynamic_cast(left_); - NetEConst*rc = dynamic_cast(right_); + const NetEConst*lc = dynamic_cast(l); + const NetEConst*rc = dynamic_cast(r); if (lc == 0 || rc == 0) return 0; verinum lval = lc->value(); @@ -1043,9 +1071,13 @@ NetEConst* NetEBShift::eval_tree() { eval_expr(left_); eval_expr(right_); + return eval_arguments_(left_,right_); +} - NetEConst*le = dynamic_cast(left_); - NetEConst*re = dynamic_cast(right_); +NetEConst* NetEBShift::eval_arguments_(const NetExpr*l, const NetExpr*r) const +{ + const NetEConst*le = dynamic_cast(l); + const NetEConst*re = dynamic_cast(r); if (le == 0 || re == 0) return 0; NetEConst*res; @@ -1098,7 +1130,7 @@ NetEConst* NetEConcat::eval_tree() } unsigned gap = 0; - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { // Parameter not here? This is an error, but presumably // already caught and we are here just to catch more. @@ -1149,7 +1181,7 @@ NetEConst* NetEConcat::eval_tree() unsigned cur = 0; bool is_string_flag = true; - for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) { + for (unsigned idx = parms_.size() ; idx > 0 ; idx -= 1) { NetEConst*expr = dynamic_cast(parms_[idx-1]); if (expr == 0) return 0; @@ -1314,12 +1346,18 @@ NetExpr* NetETernary::eval_tree() eval_expr(true_val_); eval_expr(false_val_); - NetEConst*t = dynamic_cast(true_val_); - NetEConst*f = dynamic_cast(false_val_); + return blended_arguments_(true_val_, false_val_); +} + +NetExpr*NetETernary::blended_arguments_(const NetExpr*te, const NetExpr*fe) const +{ + + const NetEConst*t = dynamic_cast(te); + const NetEConst*f = dynamic_cast(fe); if (t == 0 || f == 0) { verireal tv, fv; - if (!get_real_arg_(true_val_, tv)) return 0; - if (!get_real_arg_(false_val_, fv)) return 0; + if (!get_real_arg_(te, tv)) return 0; + if (!get_real_arg_(te, fv)) return 0; verireal val = verireal(0.0); if (tv.as_double() == fv.as_double()) val = tv; @@ -1963,8 +2001,16 @@ NetExpr* NetEUFunc::eval_tree() } if (need_const_) { - cerr << get_fileline() << ": sorry: Constant user functions are " - "not yet supported." << endl; + NetFuncDef*def = func_->func_def(); + ivl_assert(*this, def); + + vectorargs(parms_.size()); + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) + args[idx] = parms_[idx]->dup_expr(); + + NetExpr*res = def->evaluate_function(*this, args); + return res; } + return 0; } diff --git a/examples/clbff.v b/examples/clbff.v index d3ea02201..76e7378cb 100644 --- a/examples/clbff.v +++ b/examples/clbff.v @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/examples/hello.vl b/examples/hello.vl index acf46aa71..cf1d16dad 100644 --- a/examples/hello.vl +++ b/examples/hello.vl @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/examples/hello_vpi.c b/examples/hello_vpi.c index 111a10f01..3ff2e6ec0 100644 --- a/examples/hello_vpi.c +++ b/examples/hello_vpi.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: hello_vpi.c,v 1.5 2007/01/17 05:35:48 steve Exp $" -#endif /* * This file contains an example VPI module to demonstrate the tools @@ -60,22 +57,3 @@ void (*vlog_startup_routines[])() = { my_hello_register, 0 }; -/* - * $Log: hello_vpi.c,v $ - * Revision 1.5 2007/01/17 05:35:48 steve - * Fix typo is hello_vpi.c example. - * - * Revision 1.4 2006/10/30 22:46:25 steve - * Updates for Cygwin portability (pr1585922) - * - * Revision 1.3 2002/08/12 01:35:01 steve - * conditional ident string using autoconfig. - * - * Revision 1.2 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - * Revision 1.1 2002/04/18 03:25:16 steve - * More examples. - * - */ - diff --git a/examples/hello_vpi.vl b/examples/hello_vpi.vl index 520f95719..dfe05e2be 100644 --- a/examples/hello_vpi.vl +++ b/examples/hello_vpi.vl @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/examples/outff.v b/examples/outff.v index 9ecd56acb..369ce0e7d 100644 --- a/examples/outff.v +++ b/examples/outff.v @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/examples/pal_reg.v b/examples/pal_reg.v index 2207c88a1..1bc3a316e 100644 --- a/examples/pal_reg.v +++ b/examples/pal_reg.v @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/examples/show_vcd.vl b/examples/show_vcd.vl index d0a6d7e69..15cc811e7 100644 --- a/examples/show_vcd.vl +++ b/examples/show_vcd.vl @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/examples/sqrt-virtex.v b/examples/sqrt-virtex.v index ad532eab3..6df22c27c 100644 --- a/examples/sqrt-virtex.v +++ b/examples/sqrt-virtex.v @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id: sqrt-virtex.v,v 1.5 2007/03/22 16:08:18 steve Exp $" */ diff --git a/examples/sqrt.vl b/examples/sqrt.vl index fb91d84e9..f882b0992 100644 --- a/examples/sqrt.vl +++ b/examples/sqrt.vl @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id: sqrt.vl,v 1.5 2007/03/22 16:08:18 steve Exp $" */ diff --git a/examples/xnf_add.vl b/examples/xnf_add.vl index 69bbb3573..bfac12cd8 100644 --- a/examples/xnf_add.vl +++ b/examples/xnf_add.vl @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/examples/xram16x1.v b/examples/xram16x1.v index 67d6e8dd1..3354e290c 100644 --- a/examples/xram16x1.v +++ b/examples/xram16x1.v @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // This example describes a 16x1 RAM that can be synthesized into diff --git a/expr_synth.cc b/expr_synth.cc index 8a7138a39..9f5cc0e3f 100644 --- a/expr_synth.cc +++ b/expr_synth.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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -24,6 +24,7 @@ # include # include "netlist.h" +# include "netvector.h" # include "netmisc.h" # include "ivl_assert.h" @@ -118,11 +119,11 @@ NetNet* NetEBAdd::synthesize(Design*des, NetScope*scope, NetExpr*root) } perm_string path = lsig->scope()->local_symbol(); - NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, width); + netvector_t*osig_vec = new netvector_t(expr_type(), width-1, 0); + osig_vec->set_signed(has_sign()); + NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, osig_vec); osig->set_line(*this); osig->local_flag(true); - osig->data_type(expr_type()); - osig->set_signed(has_sign()); perm_string oname = osig->scope()->local_symbol(); NetAddSub *adder = new NetAddSub(lsig->scope(), oname, width); @@ -173,11 +174,11 @@ NetNet* NetEBBits::synthesize(Design*des, NetScope*scope, NetExpr*root) rsig = pad_to_width(des, rsig, width, *this); assert(lsig->vector_width() == rsig->vector_width()); + netvector_t*osig_vec = new netvector_t(expr_type(), width-1, 0); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); + NetNet::IMPLICIT, osig_vec); osig->set_line(*this); osig->local_flag(true); - osig->data_type(expr_type()); perm_string oname = scope->local_symbol(); NetLogic*gate; @@ -243,11 +244,11 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root) rsig = pad_to_width(des, rsig, width, *this); } + netvector_t*osig_vec = new netvector_t(IVL_VT_LOGIC); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); + NetNet::IMPLICIT, osig_vec); osig->set_line(*this); osig->local_flag(true); - osig->data_type(IVL_VT_LOGIC); // Test if the comparison is signed. // @@ -390,11 +391,11 @@ NetNet* NetEBPow::synthesize(Design*des, NetScope*scope, NetExpr*root) connect(powr->pin_DataA(), lsig->pin(0)); connect(powr->pin_DataB(), rsig->pin(0)); + netvector_t*osig_vec = new netvector_t(expr_type(), width-1, 0); + osig_vec->set_signed(has_sign()); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); + NetNet::IMPLICIT, osig_vec); osig->set_line(*this); - osig->data_type(expr_type()); - osig->set_signed(has_sign()); osig->local_flag(true); connect(powr->pin_Result(), osig->pin(0)); @@ -427,11 +428,11 @@ NetNet* NetEBMult::synthesize(Design*des, NetScope*scope, NetExpr*root) connect(mult->pin_DataA(), lsig->pin(0)); connect(mult->pin_DataB(), rsig->pin(0)); + netvector_t*osig_vec = new netvector_t(expr_type(), width-1, 0); + osig_vec->set_signed(has_sign()); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); + NetNet::IMPLICIT, osig_vec); osig->set_line(*this); - osig->data_type(expr_type()); - osig->set_signed(has_sign()); osig->local_flag(true); connect(mult->pin_Result(), osig->pin(0)); @@ -452,11 +453,11 @@ NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope, NetExpr*root) if (real_args) width = 1; else width = expr_width(); + netvector_t*osig_vec = new netvector_t(lsig->data_type(), width-1, 0); + osig_vec->set_signed(has_sign()); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); + NetNet::IMPLICIT, osig_vec); osig->set_line(*this); - osig->data_type(lsig->data_type()); - osig->set_signed(has_sign()); osig->local_flag(true); switch (op()) { @@ -530,10 +531,10 @@ NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope, NetExpr*root) return 0; } + netvector_t*osig_tmp = new netvector_t(expr_type()); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); + NetNet::IMPLICIT, osig_tmp); osig->set_line(*this); - osig->data_type(expr_type()); osig->local_flag(true); NetLogic*olog; @@ -597,10 +598,10 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root) if (shift == 0) return lsig; + netvector_t*osig_vec = new netvector_t(expr_type(), expr_width()-1,0); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, expr_width()); + NetNet::IMPLICIT, osig_vec); osig->set_line(*this); - osig->data_type(expr_type()); osig->local_flag(true); // ushift is the amount of pad created by the shift. @@ -618,10 +619,10 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root) psel->set_line(*this); des->add_node(psel); + netvector_t*psig_vec = new netvector_t(expr_type(), part_width-1, 0); NetNet*psig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, part_width); + NetNet::IMPLICIT, psig_vec); psig->set_line(*this); - psig->data_type(expr_type()); psig->local_flag(true); connect(psig->pin(0), psel->pin(0)); @@ -646,10 +647,11 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root) znum); des->add_node(zcon); + netvector_t*zsig_vec = new netvector_t(osig->data_type(), + znum.len()-1, 0); NetNet*zsig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, znum.len()); + NetNet::WIRE, zsig_vec); zsig->set_line(*this); - zsig->data_type(osig->data_type()); zsig->local_flag(true); connect(zcon->pin(0), zsig->pin(0)); @@ -676,10 +678,10 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root) if (rsig == 0) return 0; + netvector_t*osig_vec = new netvector_t(expr_type(), expr_width()-1, 0); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, expr_width()); + NetNet::IMPLICIT, osig_vec); osig->set_line(*this); - osig->data_type(expr_type()); osig->local_flag(true); NetCLShift*dev = new NetCLShift(scope, scope->local_symbol(), @@ -702,11 +704,11 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root) NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root) { /* First, synthesize the operands. */ - unsigned num_parms = parms_.count(); - NetNet**tmp = new NetNet*[parms_.count()]; + unsigned num_parms = parms_.size(); + NetNet**tmp = new NetNet*[parms_.size()]; bool flag = true; ivl_variable_type_t data_type = IVL_VT_NO_TYPE; - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { if (parms_[idx]->expr_width() == 0) { /* We need to synthesize a replication of zero. */ tmp[idx] = parms_[idx]->synthesize(des, scope, root); @@ -739,10 +741,10 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root) /* Make a NetNet object to carry the output vector. */ perm_string path = scope->local_symbol(); - NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width()); + netvector_t*osig_vec = new netvector_t(data_type, expr_width()-1, 0); + NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, osig_vec); osig->set_line(*this); osig->local_flag(true); - osig->data_type(data_type); NetConcat*concat = new NetConcat(scope, scope->local_symbol(), osig->vector_width(), @@ -754,8 +756,8 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root) unsigned count_input_width = 0; unsigned cur_pin = 1; for (unsigned rpt = 0; rpt < repeat(); rpt += 1) { - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { - unsigned concat_item = parms_.count()-idx-1; + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { + unsigned concat_item = parms_.size()-idx-1; if (tmp[concat_item] == 0) continue; connect(concat->pin(cur_pin), tmp[concat_item]->pin(0)); cur_pin += 1; @@ -785,11 +787,11 @@ NetNet* NetEConst::synthesize(Design*des, NetScope*scope, NetExpr*) return 0; } - NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width); + netvector_t*osig_vec = new netvector_t(expr_type(), width-1, 0); + osig_vec->set_signed(has_sign()); + NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, osig_vec); osig->set_line(*this); osig->local_flag(true); - osig->data_type(expr_type()); - osig->set_signed(has_sign()); NetConst*con = new NetConst(scope, scope->local_symbol(), value()); con->set_line(*this); @@ -806,11 +808,11 @@ NetNet* NetECReal::synthesize(Design*des, NetScope*scope, NetExpr*) { perm_string path = scope->local_symbol(); - NetNet*osig = new NetNet(scope, path, NetNet::WIRE, 1); + netvector_t*osig_vec = new netvector_t(IVL_VT_REAL); + osig_vec->set_signed(has_sign()); + NetNet*osig = new NetNet(scope, path, NetNet::WIRE, osig_vec); osig->set_line(*this); osig->local_flag(true); - osig->data_type(IVL_VT_REAL); - osig->set_signed(has_sign()); NetLiteral*con = new NetLiteral(scope, scope->local_symbol(), value_); con->set_line(*this); @@ -839,10 +841,10 @@ NetNet* NetEUBits::synthesize(Design*des, NetScope*scope, NetExpr*root) } unsigned width = isig->vector_width(); + netvector_t*osig_vec = new netvector_t(expr_type(), width-1, 0); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); + NetNet::IMPLICIT, osig_vec); osig->set_line(*this); - osig->data_type(expr_type()); osig->local_flag(true); perm_string oname = scope->local_symbol(); @@ -882,11 +884,12 @@ NetNet* NetEUnary::synthesize(Design*des, NetScope*scope, NetExpr*root) if (expr_->has_sign() == false) return sub; + netvector_t*sig_vec = new netvector_t(sub->data_type(), + sub->vector_width()-1, 0); NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, sub->vector_width()); + NetNet::WIRE, sig_vec); sig->set_line(*this); sig->local_flag(true); - sig->data_type(sub->data_type()); NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub->vector_width()); tmp->set_line(*this); @@ -956,10 +959,10 @@ NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope, NetExpr*root) gate->set_line(*this); des->add_node(gate); + netvector_t*osig_vec = new netvector_t(expr_type()); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); + NetNet::IMPLICIT, osig_vec); osig->set_line(*this); - osig->data_type(expr_type()); osig->local_flag(true); connect(gate->pin(0), osig->pin(0)); @@ -1006,8 +1009,6 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) if (sub == 0) return 0; - NetNet*off = 0; - // Detect the special case that there is a base expression and // it is constant. In this case we can generate fixed part selects. if (NetEConst*base_const = dynamic_cast(base_)) { @@ -1064,10 +1065,12 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) NetPartSelect::VP); des->add_node(sel); + ivl_assert(*this, select_width > 0); + netvector_t*tmp_vec = new netvector_t(sub->data_type(), + select_width-1, 0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, select_width); + NetNet::WIRE, tmp_vec); tmp->set_line(*this); - tmp->data_type(sub->data_type()); tmp->local_flag(true); connect(sel->pin(0), tmp->pin(0)); @@ -1091,10 +1094,10 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) connect(cat->pin(concat_count), above->pin(0)); } + tmp_vec = new netvector_t(sub->data_type(), expr_width()-1, 0); tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, expr_width()); + NetNet::WIRE, tmp_vec); tmp->set_line(*this); - tmp->data_type(sub->data_type()); tmp->local_flag(true); connect(cat->pin(0), tmp->pin(0)); } @@ -1105,16 +1108,17 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) // actual part/bit select. Generate a NetPartSelect object to // do the work, and replace "sub" with the selected output. if (base_ != 0) { - off = base_->synthesize(des, scope, root); + NetNet*off = base_->synthesize(des, scope, root); NetPartSelect*sel = new NetPartSelect(sub, off, expr_width(), base_->has_sign()); sel->set_line(*this); des->add_node(sel); + netvector_t*tmp_vec = new netvector_t(sub->data_type(), + expr_width()-1, 0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, expr_width()); - tmp->data_type(sub->data_type()); + NetNet::IMPLICIT, tmp_vec); tmp->local_flag(true); tmp->set_line(*this); sub = tmp; @@ -1135,10 +1139,11 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) // extension or 0 extension, depending on the has_sign() mode // of the expression. + netvector_t*net_vec = new netvector_t(expr_type(), expr_width()-1, 0); + net_vec->set_signed(has_sign()); NetNet*net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, expr_width()); + NetNet::IMPLICIT, net_vec); net->set_line(*this); - net->data_type(expr_type()); net->local_flag(true); if (has_sign()) { NetSignExtend*pad = new NetSignExtend(scope, @@ -1149,7 +1154,6 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) connect(pad->pin(1), sub->pin(0)); connect(pad->pin(0), net->pin(0)); - net->set_signed(true); } else { @@ -1166,10 +1170,10 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, NetExpr*root) con->set_line(*this); des->add_node(con); + netvector_t*tmp_vec = new netvector_t(expr_type(), pad_width-1, 0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, pad_width); + NetNet::IMPLICIT, tmp_vec); tmp->set_line(*this); - tmp->data_type(expr_type()); tmp->local_flag(true); connect(tmp->pin(0), con->pin(0)); @@ -1221,9 +1225,9 @@ NetNet* NetETernary::synthesize(Design *des, NetScope*scope, NetExpr*root) ivl_assert(*this, csig->vector_width() == 1); unsigned width=expr_width(); - NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width); + netvector_t*osig_vec = new netvector_t(expr_type(), width-1, 0); + NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, osig_vec); osig->set_line(*this); - osig->data_type(expr_type()); osig->local_flag(true); /* Make sure the types match. */ @@ -1266,11 +1270,12 @@ NetNet* NetESignal::synthesize(Design*des, NetScope*scope, NetExpr*root) if (word_ == 0) return net_; + netvector_t*tmp_vec = new netvector_t(net_->data_type(), + net_->vector_width()-1, 0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, net_->vector_width()); + NetNet::IMPLICIT, tmp_vec); tmp->set_line(*this); tmp->local_flag(true); - tmp->data_type(net_->data_type()); // For NetExpr objects, the word index is already converted to // a canonical (lsb==0) address. Just use the index directly. @@ -1355,12 +1360,12 @@ NetNet* NetESFunc::synthesize(Design*des, NetScope*scope, NetExpr*root) net->set_line(*this); des->add_node(net); + netvector_t*osig_vec = new netvector_t(def->type, def->wid-1, 0); + osig_vec->set_signed(def->type==IVL_VT_REAL? true : false); NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, def->wid); + NetNet::WIRE, osig_vec); osig->set_line(*this); osig->local_flag(true); - osig->set_signed(def->type==IVL_VT_REAL? true : false); - osig->data_type(def->type); connect(net->pin(0), osig->pin(0)); @@ -1386,11 +1391,11 @@ NetNet* NetESFunc::synthesize(Design*des, NetScope*scope, NetExpr*root) NetNet* NetEUFunc::synthesize(Design*des, NetScope*scope, NetExpr*root) { - svector eparms (parms_.count()); + vector eparms (parms_.size()); /* Synthesize the arguments. */ bool errors = false; - for (unsigned idx = 0; idx < eparms.count(); idx += 1) { + for (unsigned idx = 0; idx < eparms.size(); idx += 1) { if (dynamic_cast (parms_[idx])) { errors = true; continue; @@ -1423,16 +1428,17 @@ NetNet* NetEUFunc::synthesize(Design*des, NetScope*scope, NetExpr*root) des->add_node(net); /* Create an output signal and connect it to the function. */ + netvector_t*osig_vec = new netvector_t(result_sig_->expr_type(), + result_sig_->vector_width()-1, 0); NetNet*osig = new NetNet(scope_, scope_->local_symbol(), NetNet::WIRE, - result_sig_->vector_width()); + osig_vec); osig->set_line(*this); osig->local_flag(true); - osig->data_type(result_sig_->expr_type()); connect(net->pin(0), osig->pin(0)); /* Connect the pins to the arguments. */ NetFuncDef*def = func_->func_def(); - for (unsigned idx = 0; idx < eparms.count(); idx += 1) { + for (unsigned idx = 0; idx < eparms.size(); idx += 1) { unsigned width = def->port(idx)->vector_width(); NetNet*tmp; if (eparms[idx]->get_signed()) { diff --git a/functor.cc b/functor.cc index 8e128dbe5..14a72c613 100644 --- a/functor.cc +++ b/functor.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -24,6 +24,8 @@ # include "functor.h" # include "netlist.h" +using namespace std; + functor_t::~functor_t() { } @@ -52,6 +54,10 @@ void functor_t::lpm_compare(Design*, NetCompare*) { } +void functor_t::lpm_concat(Design*, NetConcat*) +{ +} + void functor_t::lpm_const(Design*, NetConst*) { } @@ -84,6 +90,10 @@ void functor_t::lpm_mux(Design*, NetMux*) { } +void functor_t::lpm_part_select(Design*, NetPartSelect*) +{ +} + void functor_t::lpm_pow(Design*, NetPow*) { } @@ -185,6 +195,11 @@ void NetCompare::functor_node(Design*des, functor_t*fun) fun->lpm_compare(des, this); } +void NetConcat::functor_node(Design*des, functor_t*fun) +{ + fun->lpm_concat(des, this); +} + void NetConst::functor_node(Design*des, functor_t*fun) { fun->lpm_const(des, this); @@ -225,6 +240,11 @@ void NetMux::functor_node(Design*des, functor_t*fun) fun->lpm_mux(des, this); } +void NetPartSelect::functor_node(Design*des, functor_t*fun) +{ + fun->lpm_part_select(des, this); +} + void NetPow::functor_node(Design*des, functor_t*fun) { fun->lpm_pow(des, this); diff --git a/functor.h b/functor.h index d3b9b5088..ea0431c0d 100644 --- a/functor.h +++ b/functor.h @@ -1,7 +1,7 @@ #ifndef __functor_H #define __functor_H /* - * Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-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 @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* @@ -57,6 +57,9 @@ struct functor_t { /* This method is called for each structural comparator. */ virtual void lpm_compare(class Design*des, class NetCompare*); + /* This method is called for each structural concatenation. */ + virtual void lpm_concat(class Design*des, class NetConcat*); + /* This method is called for each structural constant. */ virtual void lpm_const(class Design*des, class NetConst*); @@ -81,6 +84,8 @@ struct functor_t { /* This method is called for each MUX. */ virtual void lpm_mux(class Design*des, class NetMux*); + virtual void lpm_part_select(class Design*des, class NetPartSelect*); + /* This method is called for each power. */ virtual void lpm_pow(class Design*des, class NetPow*); diff --git a/iverilog-vpi.sh b/iverilog-vpi.sh index c280733bd..d1554d420 100644 --- a/iverilog-vpi.sh +++ b/iverilog-vpi.sh @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Library General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., -# 59 Temple Place - Suite 330 +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Boston, MA 02111-1307, USA # @@ -28,7 +28,7 @@ SUFFIX=@SUFFIX@ # These are used for linking... LD=$CC -LDFLAGS="@SHARED@ -L@LIBDIR@" +LDFLAGS="@IVCTARGETFLAGS@ @SHARED@ -L@LIBDIR@" LDLIBS="-lveriuser$SUFFIX -lvpi$SUFFIX" CCSRC= diff --git a/ivl.def b/ivl.def index 603c116e8..d47294db9 100644 --- a/ivl.def +++ b/ivl.def @@ -63,6 +63,7 @@ ivl_expr_file ivl_expr_lineno ivl_expr_name ivl_expr_nature +ivl_expr_net_type ivl_expr_opcode ivl_expr_oper1 ivl_expr_oper2 @@ -70,6 +71,7 @@ ivl_expr_oper3 ivl_expr_parameter ivl_expr_parm ivl_expr_parms +ivl_expr_property_idx ivl_expr_repeat ivl_expr_scope ivl_expr_sel_type @@ -140,6 +142,7 @@ ivl_lpm_width ivl_lval_idx ivl_lval_mux ivl_lval_part_off +ivl_lval_property_idx ivl_lval_sel_type ivl_lval_sig ivl_lval_width @@ -166,6 +169,7 @@ ivl_parameter_basename ivl_parameter_expr ivl_parameter_file ivl_parameter_lineno +ivl_parameter_local ivl_path_condit ivl_path_delay @@ -175,10 +179,21 @@ ivl_path_source ivl_path_source_negedge ivl_path_source_posedge +ivl_process_analog +ivl_process_attr_cnt +ivl_process_attr_val +ivl_process_file +ivl_process_lineno +ivl_process_scope +ivl_process_stmt +ivl_process_type + ivl_scope_attr_cnt ivl_scope_attr_val ivl_scope_basename ivl_scope_children +ivl_scope_class +ivl_scope_classes ivl_scope_def ivl_scope_def_file ivl_scope_def_lineno @@ -194,6 +209,10 @@ ivl_scope_logs ivl_scope_log ivl_scope_lpms ivl_scope_lpm +ivl_scope_mod_module_ports +ivl_scope_mod_module_port_name +ivl_scope_mod_module_port_type +ivl_scope_mod_module_port_width ivl_scope_mod_port ivl_scope_name ivl_scope_param @@ -228,6 +247,7 @@ ivl_signal_local ivl_signal_lsb ivl_signal_msb ivl_signal_name +ivl_signal_net_type ivl_signal_nex ivl_signal_npath ivl_signal_packed_dimensions @@ -240,18 +260,6 @@ ivl_signal_signed ivl_signal_type ivl_signal_width -ivl_path_delay -ivl_path_source - -ivl_process_analog -ivl_process_attr_cnt -ivl_process_attr_val -ivl_process_file -ivl_process_lineno -ivl_process_scope -ivl_process_stmt -ivl_process_type - ivl_statement_type ivl_stmt_block_count @@ -296,6 +304,16 @@ ivl_switch_scope ivl_switch_type ivl_switch_width +ivl_type_base +ivl_type_element +ivl_type_name +ivl_type_packed_dimensions +ivl_type_packed_lsb +ivl_type_packed_msb +ivl_type_prop_name +ivl_type_prop_type +ivl_type_properties + ivl_udp_init ivl_udp_file ivl_udp_lineno diff --git a/ivl_assert.h b/ivl_assert.h index ebf473754..6c4f9c0b9 100644 --- a/ivl_assert.h +++ b/ivl_assert.h @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __ivl_assert_h diff --git a/ivl_target.h b/ivl_target.h index fddcf86f5..9a3343d08 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1,7 +1,7 @@ #ifndef __ivl_target_H #define __ivl_target_H /* - * 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 @@ -16,17 +16,24 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include +/* Re the _CLASS define: clang++ wants this to be class to match the + * definition, but clang (the C) compiler needs it to be a struct + * since class is not defined in C. They are effecively both pointers + * to an object so everything works out. */ + #ifdef __cplusplus #define _BEGIN_DECL extern "C" { #define _END_DECL } +#define _CLASS class #else #define _BEGIN_DECL #define _END_DECL +#define _CLASS struct #endif #ifndef __GNUC__ @@ -157,21 +164,8 @@ typedef struct ivl_array_s *ivl_array_t; typedef struct ivl_branch_s *ivl_branch_t; typedef struct ivl_delaypath_s*ivl_delaypath_t; typedef struct ivl_design_s *ivl_design_t; -/* clang++ wants this to be class to match the definition, but clang - * (the C) compiler needs it to be a struct since class is not defined - * in C. They are effecively both pointers to an object so everything - * works out. */ -#ifdef __cplusplus -typedef class ivl_discipline_s*ivl_discipline_t; -#else -typedef struct ivl_discipline_s*ivl_discipline_t; -#endif -/* See the comments above. */ -#ifdef __cplusplus -typedef class netenum_t *ivl_enumtype_t; -#else -typedef struct netenum_t *ivl_enumtype_t; -#endif +typedef _CLASS ivl_discipline_s*ivl_discipline_t; +typedef _CLASS netenum_t *ivl_enumtype_t; typedef struct ivl_event_s *ivl_event_t; typedef struct ivl_expr_s *ivl_expr_t; typedef struct ivl_island_s *ivl_island_t; @@ -180,12 +174,7 @@ typedef struct ivl_lval_s *ivl_lval_t; typedef struct ivl_net_const_s*ivl_net_const_t; typedef struct ivl_net_logic_s*ivl_net_logic_t; typedef struct ivl_udp_s *ivl_udp_t; -/* See the comments above. */ -#ifdef __cplusplus -typedef class ivl_nature_s *ivl_nature_t; -#else -typedef struct ivl_nature_s *ivl_nature_t; -#endif +typedef _CLASS ivl_nature_s *ivl_nature_t; typedef struct ivl_net_probe_s*ivl_net_probe_t; typedef struct ivl_nexus_s *ivl_nexus_t; typedef struct ivl_nexus_ptr_s*ivl_nexus_ptr_t; @@ -193,9 +182,11 @@ typedef struct ivl_parameter_s*ivl_parameter_t; typedef struct ivl_process_s *ivl_process_t; typedef struct ivl_scope_s *ivl_scope_t; typedef struct ivl_signal_s *ivl_signal_t; +typedef struct ivl_port_info_s*ivl_port_info_t; typedef struct ivl_switch_s *ivl_switch_t; typedef struct ivl_memory_s *ivl_memory_t; //XXXX __attribute__((deprecated)); typedef struct ivl_statement_s*ivl_statement_t; +typedef const _CLASS ivl_type_s*ivl_type_t; /* * These are types that are defined as enumerations. These have @@ -233,7 +224,10 @@ typedef enum ivl_expr_type_e { IVL_EX_ENUMTYPE = 21, IVL_EX_EVENT = 17, IVL_EX_MEMORY = 4, + IVL_EX_NEW = 23, + IVL_EX_NULL = 22, IVL_EX_NUMBER = 5, + IVL_EX_PROPERTY = 24, IVL_EX_REALNUM = 16, IVL_EX_SCOPE = 6, IVL_EX_SELECT = 7, @@ -363,7 +357,7 @@ typedef enum ivl_scope_type_e { /* Signals (ivl_signal_t) that are ports into the scope that contains them have a port type. Otherwise, they are port IVL_SIP_NONE. */ -typedef enum ivl_signal_port_e { +typedef enum OUT { IVL_SIP_NONE = 0, IVL_SIP_INPUT = 1, IVL_SIP_OUTPUT= 2, @@ -406,6 +400,8 @@ typedef enum ivl_statement_type_e { IVL_ST_FORCE = 14, IVL_ST_FOREVER = 15, IVL_ST_FORK = 16, + IVL_ST_FORK_JOIN_ANY = 28, + IVL_ST_FORK_JOIN_NONE = 29, IVL_ST_FREE = 26, IVL_ST_RELEASE = 17, IVL_ST_REPEAT = 18, @@ -432,6 +428,8 @@ typedef enum ivl_variable_type_e { IVL_VT_BOOL = 3, IVL_VT_LOGIC = 4, IVL_VT_STRING = 5, + IVL_VT_DARRAY = 6, /* Array (esp. dynamic array) */ + IVL_VT_CLASS = 7, /* SystemVerilog class instances */ IVL_VT_VECTOR = IVL_VT_LOGIC /* For compatibility */ } ivl_variable_type_t; @@ -770,6 +768,11 @@ extern unsigned ivl_event_lineno(ivl_event_t net); * Get the data type of the expression node. This uses the variable * type enum to express the type of the expression node. * + * ivl_expr_net_type + * This is used in some cases to carry more advanced type + * descriptions. Over the long run, all type informatino will be + * moved into the ivl_type_t type description method. + * * ivl_expr_width * This method returns the bit width of the expression at this * node. It can be applied to any expression node, and returns the @@ -802,6 +805,22 @@ extern unsigned ivl_event_lineno(ivl_event_t net); * * - IVL_EX_BINARY * + * - IVL_EX_PROPERTY + * This expression represents the property select from a class + * type, for example "foo.property" where "foo" is a class handle and + * "property" is the name of one of the properties of the class. The + * ivl_expr_signal function returns the ivl_signal_t for "foo" and the + * data_type for the signal will be IVL_VT_CLASS. + * + * The ivl_signal_net_type(sig) for the "foo" signal will be a class + * type and from there you can get access to the type information. + * + * Elaboration reduces the properties of a class to a vector numbered + * from 0 to the number of properties. The ivl_expr_property_idx() + * function gets the index of the selected property into the property + * table. That number can be passed to ivl_type_prop_*() functions to + * get details about the property. + * * - IVL_EX_SELECT * This expression takes two operands, oper1 is the expression to * select from, and oper2 is the selection base. The ivl_expr_width @@ -810,6 +829,14 @@ extern unsigned ivl_event_lineno(ivl_event_t net); * conversion from signal units to vector units, so the result of * ivl_expr_oper1 should range from 0 to ivl_expr_width(). * + * This exprsesion is also used to implement string substrings. If the + * sub-expression (oper1) is IVL_VT_STRING, then the base expression + * (oper2) is a charaster address, with 0 the first address of the + * string, 1 the second, and so on. This is OPPOSITE how a part select + * of a string cast to a vector works, to be aware. The size of the + * expression is an even multiple of 8, and is 8 times the number of + * characters to pick. + * * - IVL_EX_SIGNAL * This expression references a signal vector. The ivl_expr_signal * function gets a handle for the signal that is referenced. The @@ -839,6 +866,7 @@ extern unsigned ivl_event_lineno(ivl_event_t net); */ extern ivl_expr_type_t ivl_expr_type(ivl_expr_t net); +extern ivl_type_t ivl_expr_net_type(ivl_expr_t net); extern ivl_variable_type_t ivl_expr_value(ivl_expr_t net); extern const char*ivl_expr_file(ivl_expr_t net); extern unsigned ivl_expr_lineno(ivl_expr_t net); @@ -855,7 +883,7 @@ extern uint64_t ivl_expr_delay_val(ivl_expr_t net); extern double ivl_expr_dvalue(ivl_expr_t net); /* IVL_EX_ENUMTYPE */ extern ivl_enumtype_t ivl_expr_enumtype(ivl_expr_t net); - /* IVL_EX_SIGNAL, IVL_EX_SFUNC, IVL_EX_VARIABLE */ + /* IVL_EX_PROPERTY IVL_EX_SIGNAL IVL_EX_SFUNC IVL_EX_VARIABLE */ extern const char* ivl_expr_name(ivl_expr_t net); /* IVL_EX_BACCESS */ extern ivl_nature_t ivl_expr_nature(ivl_expr_t net); @@ -879,9 +907,11 @@ extern unsigned ivl_expr_repeat(ivl_expr_t net); extern ivl_select_type_t ivl_expr_sel_type(ivl_expr_t net); /* IVL_EX_EVENT */ extern ivl_event_t ivl_expr_event(ivl_expr_t net); + /* IVL_EX_PROPERTY */ +extern int ivl_expr_property_idx(ivl_expr_t net); /* IVL_EX_SCOPE */ extern ivl_scope_t ivl_expr_scope(ivl_expr_t net); - /* IVL_EX_SIGNAL */ + /* IVL_EX_PROPERTY IVL_EX_SIGNAL */ extern ivl_signal_t ivl_expr_signal(ivl_expr_t net); /* any expression */ extern int ivl_expr_signed(ivl_expr_t net); @@ -1419,6 +1449,11 @@ extern const char*ivl_lpm_string(ivl_lpm_t net); * ivl_expr_t that represents the index expression. Otherwise, it * returns 0. * + * ivl_lval_property_idx + * If the l-value is a class object, this is the name of a property + * to select from the object. If this property is not present (<0) + * then the l-value represents the class object itself. + * * SEMANTIC NOTES * The ivl_lval_width is not necessarily the same as the width of the * signal or memory word it represents. It is the width of the vector @@ -1444,6 +1479,7 @@ extern ivl_expr_t ivl_lval_mux(ivl_lval_t net); /* XXXX Obsolete? */ extern ivl_expr_t ivl_lval_idx(ivl_lval_t net); extern ivl_expr_t ivl_lval_part_off(ivl_lval_t net); extern ivl_select_type_t ivl_lval_sel_type(ivl_lval_t net); +extern int ivl_lval_property_idx(ivl_lval_t net); extern ivl_signal_t ivl_lval_sig(ivl_lval_t net); @@ -1566,6 +1602,10 @@ extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net); * Return the value of the parameter. This should be a simple * constant expression, an IVL_EX_STRING or IVL_EX_NUMBER. * + * ivl_parameter_local + * Return whether parameter was local (localparam, implicit genvar etc) + * or not. + * * ivl_parameter_file * ivl_parameter_lineno * Returns the file and line where this parameter is defined @@ -1573,7 +1613,7 @@ extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net); extern const char* ivl_parameter_basename(ivl_parameter_t net); extern ivl_scope_t ivl_parameter_scope(ivl_parameter_t net); extern ivl_expr_t ivl_parameter_expr(ivl_parameter_t net); - +extern int ivl_parameter_local(ivl_parameter_t net); extern const char* ivl_parameter_file(ivl_parameter_t net); extern unsigned ivl_parameter_lineno(ivl_parameter_t net); @@ -1719,6 +1759,8 @@ extern ivl_statement_t ivl_scope_def(ivl_scope_t net); extern const char* ivl_scope_def_file(ivl_scope_t net); extern unsigned ivl_scope_def_lineno(ivl_scope_t net); +extern unsigned ivl_scope_classes(ivl_scope_t net); +extern ivl_type_t ivl_scope_class(ivl_scope_t net, unsigned idx); extern unsigned ivl_scope_enumerates(ivl_scope_t net); extern ivl_enumtype_t ivl_scope_enumerate(ivl_scope_t net, unsigned idx); extern unsigned ivl_scope_events(ivl_scope_t net); @@ -1736,6 +1778,12 @@ extern const char* ivl_scope_basename(ivl_scope_t net); extern unsigned ivl_scope_params(ivl_scope_t net); extern ivl_parameter_t ivl_scope_param(ivl_scope_t net, unsigned idx); extern ivl_scope_t ivl_scope_parent(ivl_scope_t net); + +extern unsigned ivl_scope_mod_module_ports(ivl_scope_t net); +extern const char *ivl_scope_mod_module_port_name(ivl_scope_t net, unsigned idx ); +extern ivl_signal_port_t ivl_scope_mod_module_port_type(ivl_scope_t net, unsigned idx ); +extern unsigned ivl_scope_mod_module_port_width(ivl_scope_t net, unsigned idx ); + extern unsigned ivl_scope_ports(ivl_scope_t net); extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx); extern ivl_nexus_t ivl_scope_mod_port(ivl_scope_t net, unsigned idx); @@ -1876,6 +1924,7 @@ 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_module_port_index(ivl_signal_t net); extern int ivl_signal_signed(ivl_signal_t net); extern int ivl_signal_integer(ivl_signal_t net); extern int ivl_signal_local(ivl_signal_t net); @@ -1884,6 +1933,7 @@ extern unsigned ivl_signal_npath(ivl_signal_t net); extern ivl_delaypath_t ivl_signal_path(ivl_signal_t net, unsigned idx); extern ivl_signal_type_t ivl_signal_type(ivl_signal_t net); extern ivl_variable_type_t ivl_signal_data_type(ivl_signal_t net); +extern ivl_type_t ivl_signal_net_type(ivl_signal_t net); extern const char* ivl_signal_name(ivl_signal_t net); extern const char* ivl_signal_basename(ivl_signal_t net); extern const char* ivl_signal_attr(ivl_signal_t net, const char*key); @@ -1971,7 +2021,7 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net); * Statements that have event arguments (TRIGGER and WAIT) make * those event objects available through these methods. * - * ivl_stmt_lval +* ivl_stmt_lval * ivl_stmt_lvals * Return the number of l-values for an assignment statement, or * the specific l-value. If there is more than 1 l-value, then the @@ -2069,11 +2119,11 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net); * triggers. The statement waits even if the sub-statement is nul. */ - /* IVL_ST_BLOCK, IVL_ST_FORK */ + /* IVL_ST_BLOCK, IVL_ST_FORK, IVL_ST_FORK_JOIN_ANY, IVL_ST_FORK_JOIN_NONE */ extern unsigned ivl_stmt_block_count(ivl_statement_t net); - /* IVL_ST_BLOCK, IVL_ST_FORK */ + /* IVL_ST_BLOCK, IVL_ST_FORK, IVL_ST_FORK_JOIN_ANY, IVL_ST_FORK_JOIN_NONE */ extern ivl_scope_t ivl_stmt_block_scope(ivl_statement_t net); - /* IVL_ST_BLOCK, IVL_ST_FORK */ + /* IVL_ST_BLOCK, IVL_ST_FORK, IVL_ST_FORK_JOIN_ANY, IVL_ST_FORK_JOIN_NONE */ extern ivl_statement_t ivl_stmt_block_stmt(ivl_statement_t net, unsigned i); /* IVL_ST_UTASK IVL_ST_DISABLE */ extern ivl_scope_t ivl_stmt_call(ivl_statement_t net); @@ -2172,6 +2222,31 @@ extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx); extern const char* ivl_switch_file(ivl_switch_t net); extern unsigned ivl_switch_lineno(ivl_switch_t net); +/* TYPES + * + * ivl_type_base + * This returns the base type for the type. See the + * ivl_variable_type_t definition for the various base types. + * + * ivl_type_element + * Return the type of the element of an array. This is only valid + * for array types. + * + * SEMANTIC NOTES + * + * Class types have names and properties. + */ +extern ivl_variable_type_t ivl_type_base(ivl_type_t net); +extern ivl_type_t ivl_type_element(ivl_type_t net); +extern unsigned ivl_type_packed_dimensions(ivl_type_t net); +extern int ivl_type_packed_lsb(ivl_type_t net, unsigned dim); +extern int ivl_type_packed_msb(ivl_type_t net, unsigned dim); +extern const char* ivl_type_name(ivl_type_t net); +extern int ivl_type_properties(ivl_type_t net); +extern const char* ivl_type_prop_name(ivl_type_t net, int idx); +extern ivl_type_t ivl_type_prop_type(ivl_type_t net, int idx); + + #if defined(__MINGW32__) || defined (__CYGWIN32__) # define DLLEXPORT __declspec(dllexport) #else diff --git a/ivl_target_priv.h b/ivl_target_priv.h index 8de0787ab..195071f5f 100644 --- a/ivl_target_priv.h +++ b/ivl_target_priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "ivl_target.h" diff --git a/ivlpp/Makefile.in b/ivlpp/Makefile.in index 44b800e4b..ffcafe6a9 100644 --- a/ivlpp/Makefile.in +++ b/ivlpp/Makefile.in @@ -14,9 +14,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/ivlpp/globals.h b/ivlpp/globals.h index 2c7e89600..db7d660a5 100644 --- a/ivlpp/globals.h +++ b/ivlpp/globals.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/ivlpp/ivlpp.txt b/ivlpp/ivlpp.txt index 38a0b39f2..fe6071f53 100644 --- a/ivlpp/ivlpp.txt +++ b/ivlpp/ivlpp.txt @@ -14,7 +14,7 @@ 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 + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. THE IVL PREPROCESSOR diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 348f78ba3..90843829a 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1,7 +1,7 @@ %option prefix="yy" %{ /* - * 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 @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -260,6 +260,7 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif) * string. */ \" { string_enter = YY_START; BEGIN(CSTRING); ECHO; } +\\\\ | \\\" | \\` { ECHO; } \r\n | diff --git a/ivlpp/main.c b/ivlpp/main.c index d7fedab32..bc8014d38 100644 --- a/ivlpp/main.c +++ b/ivlpp/main.c @@ -14,7 +14,7 @@ const char COPYRIGHT[] = * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/lexor.lex b/lexor.lex index 01a891437..0bf05178a 100644 --- a/lexor.lex +++ b/lexor.lex @@ -19,7 +19,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -192,6 +192,7 @@ TU [munpf] "++" { return K_INCR; } "--" {return K_DECR; } "'{" { return K_LP; } +"::" { return K_SCOPE_RES; } /* Watch out for the tricky case of (*). Cannot parse this as "(*" and ")", but since I know that this is really ( * ), replace it @@ -325,7 +326,15 @@ TU [munpf] \\[^ \t\b\f\r\n]+ { yylval.text = strdupnew(yytext+1); - return IDENTIFIER; } + if (gn_system_verilog()) { + if (data_type_t*type = pform_test_type_identifier(yylval.text)) { + delete[]yylval.text; + yylval.data_type = type; + return TYPE_IDENTIFIER; + } + } + return IDENTIFIER; + } \$([a-zA-Z0-9$_]+) { /* The 1364-1995 timing checks. */ diff --git a/lexor_keyword.h b/lexor_keyword.h index 8e7f05a79..dcd090188 100644 --- a/lexor_keyword.h +++ b/lexor_keyword.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ extern int lexor_keyword_code (const char*str, unsigned len); diff --git a/libmisc/LineInfo.cc b/libmisc/LineInfo.cc index 047cbf4bb..753b24970 100644 --- a/libmisc/LineInfo.cc +++ b/libmisc/LineInfo.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "LineInfo.h" diff --git a/libmisc/LineInfo.h b/libmisc/LineInfo.h index 357360fad..5f3dff9f5 100644 --- a/libmisc/LineInfo.h +++ b/libmisc/LineInfo.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "StringHeap.h" diff --git a/libmisc/StringHeap.cc b/libmisc/StringHeap.cc index 1e8d8fac5..6c30bafa7 100644 --- a/libmisc/StringHeap.cc +++ b/libmisc/StringHeap.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "StringHeap.h" @@ -24,6 +24,7 @@ # include #ifdef CHECK_WITH_VALGRIND +# include "ivl_alloc.h" static char **string_pool = NULL; static unsigned string_pool_count = 0; #endif diff --git a/libmisc/StringHeap.h b/libmisc/StringHeap.h index fe47156fe..f803e8a77 100644 --- a/libmisc/StringHeap.h +++ b/libmisc/StringHeap.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/libveriuser/Makefile.in b/libveriuser/Makefile.in index 557c12fa0..e6d843927 100644 --- a/libveriuser/Makefile.in +++ b/libveriuser/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh @@ -44,6 +43,10 @@ else INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif +LDRELOCFLAGS = @LDRELOCFLAGS@ + +LDTARGETFLAGS = @LDTARGETFLAGS@ + CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ @@ -87,7 +90,7 @@ stamp-config-h: $(srcdir)/config.h.in ../config.status config.h: stamp-config-h libveriuser.o: $O - $(LD) -r -o $@ $O + $(LD) $(LDTARGETFLAGS) -r -o $@ $O libveriuser.a: libveriuser.o rm -f $@ diff --git a/libveriuser/a_close.c b/libveriuser/a_close.c index 75ca20ca1..062c48b88 100644 --- a/libveriuser/a_close.c +++ b/libveriuser/a_close.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_close.c,v 1.4 2003/06/17 16:55:07 steve Exp $" -#endif # include # include "priv.h" @@ -29,25 +26,3 @@ void acc_close(void) fprintf(pli_trace, "acc_close()\n"); } } - -/* - * $Log: a_close.c,v $ - * Revision 1.4 2003/06/17 16:55:07 steve - * 1) setlinebuf() for vpi_trace - * 2) Addes error checks for trace file opens - * 3) removes now extraneous flushes - * 4) fixes acc_next() bug - * - * Revision 1.3 2003/05/18 00:16:35 steve - * Add PLI_TRACE tracing of PLI1 modules. - * - * Add tf_isetdelay and friends, and add - * callback return values for acc_vcl support. - * - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/05/23 03:46:42 steve - * Add the acc_user.h header file. - * - */ diff --git a/libveriuser/a_compare_handles.c b/libveriuser/a_compare_handles.c index 2725717c5..3bc125bde 100644 --- a/libveriuser/a_compare_handles.c +++ b/libveriuser/a_compare_handles.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2003 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_compare_handles.c,v 1.3 2004/02/18 02:51:59 steve Exp $" -#endif # include # include @@ -27,22 +24,3 @@ PLI_INT32 acc_compare_handles(handle handle1, handle handle2) { return handle1 == handle2; } - -/* - * $Log: a_compare_handles.c,v $ - * Revision 1.3 2004/02/18 02:51:59 steve - * Fix type mismatches of various VPI functions. - * - * Revision 1.2 2003/08/26 16:26:02 steve - * ifdef idents correctly. - * - * Revision 1.1 2003/06/04 01:56:20 steve - * 1) Adds configure logic to clean up compiler warnings - * 2) adds acc_compare_handle, acc_fetch_range, acc_next_scope and - * tf_isetrealdelay, acc_handle_scope - * 3) makes acc_next reentrant - * 4) adds basic vpiWire type support - * 5) fills in some acc_object_of_type() and acc_fetch_{full}type() - * 6) add vpiLeftRange/RigthRange to signals - * - */ diff --git a/libveriuser/a_configure.c b/libveriuser/a_configure.c index 8f0df446f..c6d242e5d 100644 --- a/libveriuser/a_configure.c +++ b/libveriuser/a_configure.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/libveriuser/a_fetch_argc.c b/libveriuser/a_fetch_argc.c index 85e0fd295..eadeef4bb 100644 --- a/libveriuser/a_fetch_argc.c +++ b/libveriuser/a_fetch_argc.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_fetch_argc.c,v 1.2 2002/08/12 01:35:02 steve Exp $" -#endif # include # include @@ -37,13 +34,3 @@ int acc_fetch_argc(void) /* return argc */ return vpi_vlog_info.argc; } - -/* - * $Log: a_fetch_argc.c,v $ - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/11 15:19:12 steve - * Add acc_fetch_argc/argv/version (mruff) - * - */ diff --git a/libveriuser/a_fetch_argv.c b/libveriuser/a_fetch_argv.c index 77cdb982d..1f447a8a1 100644 --- a/libveriuser/a_fetch_argv.c +++ b/libveriuser/a_fetch_argv.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_fetch_argv.c,v 1.2 2002/08/12 01:35:02 steve Exp $" -#endif # include # include @@ -37,13 +34,3 @@ char **acc_fetch_argv(void) /* return argc */ return vpi_vlog_info.argv; } - -/* - * $Log: a_fetch_argv.c,v $ - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/11 15:19:12 steve - * Add acc_fetch_argc/argv/version (mruff) - * - */ diff --git a/libveriuser/a_fetch_dir.c b/libveriuser/a_fetch_dir.c index 580b97c02..52db2f704 100644 --- a/libveriuser/a_fetch_dir.c +++ b/libveriuser/a_fetch_dir.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_fetch_dir.c,v 1.1 2003/10/10 02:57:45 steve Exp $" -#endif # include # include @@ -42,12 +39,3 @@ PLI_INT32 acc_fetch_direction(handle obj) return accInout; } - - -/* - * $Log: a_fetch_dir.c,v $ - * Revision 1.1 2003/10/10 02:57:45 steve - * Some PLI1 stubs. - * - */ - diff --git a/libveriuser/a_fetch_fullname.c b/libveriuser/a_fetch_fullname.c index bc4ab8946..848c702d9 100644 --- a/libveriuser/a_fetch_fullname.c +++ b/libveriuser/a_fetch_fullname.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_fetch_fullname.c,v 1.5 2003/05/29 02:21:45 steve Exp $" -#endif #include #include @@ -41,27 +38,3 @@ char* acc_fetch_defname(handle object) { return __acc_newstring(vpi_get_str(vpiDefName, object)); } - -/* - * $Log: a_fetch_fullname.c,v $ - * Revision 1.5 2003/05/29 02:21:45 steve - * Implement acc_fetch_defname and its infrastructure in vvp. - * - * Revision 1.4 2003/03/13 05:07:46 steve - * Declaration warnings. - * - * Revision 1.3 2003/02/17 06:39:47 steve - * Add at least minimal implementations for several - * acc_ functions. Add support for standard ACC - * string handling. - * - * Add the _pli_types.h header file to carry the - * IEEE1364-2001 standard PLI type declarations. - * - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/07 02:58:58 steve - * Add a bunch of acc/tf functions. (mruff) - * - */ diff --git a/libveriuser/a_fetch_location.c b/libveriuser/a_fetch_location.c index 9b5d62290..1e078a6a3 100644 --- a/libveriuser/a_fetch_location.c +++ b/libveriuser/a_fetch_location.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_fetch_location.c,v 1.1 2003/02/17 06:39:47 steve Exp $" -#endif #include #include @@ -29,16 +26,3 @@ int acc_fetch_location(p_location loc, handle obj) loc->filename = ""; return 1; } - -/* - * $Log: a_fetch_location.c,v $ - * Revision 1.1 2003/02/17 06:39:47 steve - * Add at least minimal implementations for several - * acc_ functions. Add support for standard ACC - * string handling. - * - * Add the _pli_types.h header file to carry the - * IEEE1364-2001 standard PLI type declarations. - * - */ - diff --git a/libveriuser/a_fetch_param.c b/libveriuser/a_fetch_param.c index 309289c5d..5993a47da 100644 --- a/libveriuser/a_fetch_param.c +++ b/libveriuser/a_fetch_param.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/libveriuser/a_fetch_range.c b/libveriuser/a_fetch_range.c index 6be4debb3..efa3e77cb 100644 --- a/libveriuser/a_fetch_range.c +++ b/libveriuser/a_fetch_range.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2003 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_fetch_range.c,v 1.2 2004/02/18 02:51:59 steve Exp $" -#endif #include #include @@ -32,19 +29,3 @@ PLI_INT32 acc_fetch_range(handle object, int *msb, int *lsb) *lsb = vpi_get(vpiRightRange, object); return 0; } - -/* - * $Log: a_fetch_range.c,v $ - * Revision 1.2 2004/02/18 02:51:59 steve - * Fix type mismatches of various VPI functions. - * - * Revision 1.1 2003/06/04 01:56:20 steve - * 1) Adds configure logic to clean up compiler warnings - * 2) adds acc_compare_handle, acc_fetch_range, acc_next_scope and - * tf_isetrealdelay, acc_handle_scope - * 3) makes acc_next reentrant - * 4) adds basic vpiWire type support - * 5) fills in some acc_object_of_type() and acc_fetch_{full}type() - * 6) add vpiLeftRange/RigthRange to signals - * - */ diff --git a/libveriuser/a_fetch_tfarg.c b/libveriuser/a_fetch_tfarg.c index 771122b99..036100958 100644 --- a/libveriuser/a_fetch_tfarg.c +++ b/libveriuser/a_fetch_tfarg.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/libveriuser/a_fetch_time.c b/libveriuser/a_fetch_time.c index 236b86665..d14e7c779 100644 --- a/libveriuser/a_fetch_time.c +++ b/libveriuser/a_fetch_time.c @@ -14,12 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_fetch_time.c,v 1.1 2003/03/13 04:35:09 steve Exp $" -#endif - #include #include @@ -30,11 +26,3 @@ void acc_fetch_timescale_info(handle obj, p_timescale_info info) info->precision = vpi_get(vpiTimePrecision, 0); info->unit = vpi_get(vpiTimeUnit, obj); } - -/* - * $Log: a_fetch_time.c,v $ - * Revision 1.1 2003/03/13 04:35:09 steve - * Add a bunch of new acc_ and tf_ functions. - * - */ - diff --git a/libveriuser/a_fetch_type.c b/libveriuser/a_fetch_type.c index 2a61f7422..f1820cb0a 100644 --- a/libveriuser/a_fetch_type.c +++ b/libveriuser/a_fetch_type.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/libveriuser/a_fetch_type_str.c b/libveriuser/a_fetch_type_str.c index 403aa6dbe..e8cefae4d 100644 --- a/libveriuser/a_fetch_type_str.c +++ b/libveriuser/a_fetch_type_str.c @@ -14,14 +14,13 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include - const char* acc_fetch_type_str(PLI_INT32 type) { switch (type) { diff --git a/libveriuser/a_fetch_value.c b/libveriuser/a_fetch_value.c index c7525f02f..6f783971e 100644 --- a/libveriuser/a_fetch_value.c +++ b/libveriuser/a_fetch_value.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/libveriuser/a_handle_by_name.c b/libveriuser/a_handle_by_name.c index 0a2cd42b6..c6a96c878 100644 --- a/libveriuser/a_handle_by_name.c +++ b/libveriuser/a_handle_by_name.c @@ -1,5 +1,5 @@ -/* vi:sw=6 - * Copyright (c) 2003 Michael Ruff (mruff at chiaro.com) +/* + * Copyright (c) 2003-2012 Michael Ruff (mruff at chiaro.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 @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_handle_by_name.c,v 1.2 2003/06/17 16:55:07 steve Exp $" -#endif # include # include @@ -31,12 +28,11 @@ */ handle acc_handle_by_name(const char*obj_name, handle scope) { - vpiHandle sys_h; vpiHandle res; /* if no scope provided, use tasks scope */ if (!scope) { - sys_h = vpi_handle(vpiSysTfCall, 0 /* NULL */); + vpiHandle sys_h = vpi_handle(vpiSysTfCall, 0 /* NULL */); scope = vpi_handle(vpiScope, sys_h); } @@ -50,16 +46,3 @@ handle acc_handle_by_name(const char*obj_name, handle scope) return res; } - -/* - * $Log: a_handle_by_name.c,v $ - * Revision 1.2 2003/06/17 16:55:07 steve - * 1) setlinebuf() for vpi_trace - * 2) Addes error checks for trace file opens - * 3) removes now extraneous flushes - * 4) fixes acc_next() bug - * - * Revision 1.1 2003/05/24 03:02:04 steve - * Add implementation of acc_handle_by_name. - * - */ diff --git a/libveriuser/a_handle_hiconn.c b/libveriuser/a_handle_hiconn.c index 567a0d00a..2b54647ea 100644 --- a/libveriuser/a_handle_hiconn.c +++ b/libveriuser/a_handle_hiconn.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_handle_hiconn.c,v 1.1 2003/10/10 02:57:45 steve Exp $" -#endif # include # include @@ -42,12 +39,3 @@ handle acc_handle_hiconn(handle obj) return 0; } - - -/* - * $Log: a_handle_hiconn.c,v $ - * Revision 1.1 2003/10/10 02:57:45 steve - * Some PLI1 stubs. - * - */ - diff --git a/libveriuser/a_handle_object.c b/libveriuser/a_handle_object.c index baaad1d09..b92bd7171 100644 --- a/libveriuser/a_handle_object.c +++ b/libveriuser/a_handle_object.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_handle_object.c,v 1.2 2003/12/17 15:45:07 steve Exp $" -#endif #include #include @@ -52,14 +49,3 @@ char* acc_set_scope(handle ref, ...) return acc_fetch_fullname(ref); } - -/* - * $Log: a_handle_object.c,v $ - * Revision 1.2 2003/12/17 15:45:07 steve - * Add acc_set_scope function. - * - * Revision 1.1 2003/03/13 04:35:09 steve - * Add a bunch of new acc_ and tf_ functions. - * - */ - diff --git a/libveriuser/a_handle_parent.c b/libveriuser/a_handle_parent.c index 3592f0201..b3e435eff 100644 --- a/libveriuser/a_handle_parent.c +++ b/libveriuser/a_handle_parent.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_handle_parent.c,v 1.2 2003/06/04 01:56:20 steve Exp $" -#endif #include #include @@ -34,25 +31,7 @@ handle acc_handle_parent(handle obj) return scope; } - handle acc_handle_scope(handle obj) { return vpi_handle(vpiScope, obj); } - -/* - * $Log: a_handle_parent.c,v $ - * Revision 1.2 2003/06/04 01:56:20 steve - * 1) Adds configure logic to clean up compiler warnings - * 2) adds acc_compare_handle, acc_fetch_range, acc_next_scope and - * tf_isetrealdelay, acc_handle_scope - * 3) makes acc_next reentrant - * 4) adds basic vpiWire type support - * 5) fills in some acc_object_of_type() and acc_fetch_{full}type() - * 6) add vpiLeftRange/RigthRange to signals - * - * Revision 1.1 2003/03/13 04:35:09 steve - * Add a bunch of new acc_ and tf_ functions. - * - */ - diff --git a/libveriuser/a_handle_simulated_net.c b/libveriuser/a_handle_simulated_net.c index 2d07d1ab5..19e0fde1f 100644 --- a/libveriuser/a_handle_simulated_net.c +++ b/libveriuser/a_handle_simulated_net.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_handle_simulated_net.c,v 1.1 2003/10/10 02:57:46 steve Exp $" -#endif # include # include @@ -35,12 +32,3 @@ handle acc_handle_simulated_net(handle obj) return obj; } - - -/* - * $Log: a_handle_simulated_net.c,v $ - * Revision 1.1 2003/10/10 02:57:46 steve - * Some PLI1 stubs. - * - */ - diff --git a/libveriuser/a_handle_tfarg.c b/libveriuser/a_handle_tfarg.c index c25eba401..4f92116bf 100644 --- a/libveriuser/a_handle_tfarg.c +++ b/libveriuser/a_handle_tfarg.c @@ -1,5 +1,5 @@ -/* vi:sw=6 - * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) +/* + * Copyright (c) 2002-2012 Michael Ruff (mruff at chiaro.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 @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_handle_tfarg.c,v 1.6 2004/10/04 01:10:56 steve Exp $" -#endif #include #include @@ -28,9 +25,11 @@ */ handle acc_handle_tfarg(int n) { - vpiHandle sys_h, sys_i, rtn_h = 0; + vpiHandle rtn_h = 0; if (n > 0) { + vpiHandle sys_h, sys_i; + sys_h = vpi_handle(vpiSysTfCall, 0 /* NULL */); sys_i = vpi_iterate(vpiArgument, sys_h); @@ -55,30 +54,3 @@ handle acc_handle_tfinst(void) { return vpi_handle(vpiSysTfCall, 0); } - -/* - * $Log: a_handle_tfarg.c,v $ - * Revision 1.6 2004/10/04 01:10:56 steve - * Clean up spurious trailing white space. - * - * Revision 1.5 2003/03/18 01:21:49 steve - * Fix warning about uninitialized variable. - * - * Revision 1.4 2003/03/14 04:58:50 steve - * Free the iterator when Im done. - * - * Revision 1.3 2003/02/17 06:39:47 steve - * Add at least minimal implementations for several - * acc_ functions. Add support for standard ACC - * string handling. - * - * Add the _pli_types.h header file to carry the - * IEEE1364-2001 standard PLI type declarations. - * - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/02 19:03:58 steve - * Add acc_handle_tfarg and acc_next_topmode - * - */ diff --git a/libveriuser/a_initialize.c b/libveriuser/a_initialize.c index 8f7c7209e..ef3ccc60a 100644 --- a/libveriuser/a_initialize.c +++ b/libveriuser/a_initialize.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_initialize.c,v 1.2 2002/08/12 01:35:02 steve Exp $" -#endif # include @@ -30,13 +27,3 @@ int acc_initialize() return 1; } - -/* - * $Log: a_initialize.c,v $ - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/05/23 03:46:42 steve - * Add the acc_user.h header file. - * - */ diff --git a/libveriuser/a_next.c b/libveriuser/a_next.c index 2ee5e0685..8b9589fc2 100644 --- a/libveriuser/a_next.c +++ b/libveriuser/a_next.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/libveriuser/a_next_bit.c b/libveriuser/a_next_bit.c index 13ba06a5f..cc9316c05 100644 --- a/libveriuser/a_next_bit.c +++ b/libveriuser/a_next_bit.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_next_bit.c,v 1.1 2003/10/10 02:57:46 steve Exp $" -#endif # include # include @@ -42,12 +39,3 @@ handle acc_next_bit(handle ref, handle bit) return 0; } - - -/* - * $Log: a_next_bit.c,v $ - * Revision 1.1 2003/10/10 02:57:46 steve - * Some PLI1 stubs. - * - */ - diff --git a/libveriuser/a_next_port.c b/libveriuser/a_next_port.c index dc08aeaec..e0950b3fa 100644 --- a/libveriuser/a_next_port.c +++ b/libveriuser/a_next_port.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_next_port.c,v 1.1 2003/10/10 02:57:46 steve Exp $" -#endif # include # include @@ -42,12 +39,3 @@ handle acc_next_port(handle ref, handle bit) return 0; } - - -/* - * $Log: a_next_port.c,v $ - * Revision 1.1 2003/10/10 02:57:46 steve - * Some PLI1 stubs. - * - */ - diff --git a/libveriuser/a_next_topmod.c b/libveriuser/a_next_topmod.c index f49506ec2..2d1c3a7b9 100644 --- a/libveriuser/a_next_topmod.c +++ b/libveriuser/a_next_topmod.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_next_topmod.c,v 1.2 2002/08/12 01:35:02 steve Exp $" -#endif #include #include @@ -46,13 +43,3 @@ handle acc_next_topmod(handle prev_topmod) last = vpi_scan(mod_i); return last; } - -/* - * $Log: a_next_topmod.c,v $ - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/02 19:03:58 steve - * Add acc_handle_tfarg and acc_next_topmode - * - */ diff --git a/libveriuser/a_object_of_type.c b/libveriuser/a_object_of_type.c index d5883ab84..4a05119fd 100644 --- a/libveriuser/a_object_of_type.c +++ b/libveriuser/a_object_of_type.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/libveriuser/a_product_version.c b/libveriuser/a_product_version.c index 0ca267f90..191b78730 100644 --- a/libveriuser/a_product_version.c +++ b/libveriuser/a_product_version.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_product_version.c,v 1.2 2002/08/12 01:35:02 steve Exp $" -#endif # include # include @@ -31,13 +28,3 @@ char *acc_product_version(void) return info.version; } - -/* - * $Log: a_product_version.c,v $ - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/05/30 02:06:05 steve - * Implement acc_product_version. - * - */ diff --git a/libveriuser/a_set_value.c b/libveriuser/a_set_value.c index 672d25833..3259ae7fd 100644 --- a/libveriuser/a_set_value.c +++ b/libveriuser/a_set_value.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/libveriuser/a_vcl.c b/libveriuser/a_vcl.c index aa2c96df4..e4f4d7725 100644 --- a/libveriuser/a_vcl.c +++ b/libveriuser/a_vcl.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/libveriuser/a_version.c b/libveriuser/a_version.c index 9ec6f0e2e..7cb354ac1 100644 --- a/libveriuser/a_version.c +++ b/libveriuser/a_version.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: a_version.c,v 1.2 2002/08/12 01:35:02 steve Exp $" -#endif # include # include @@ -31,13 +28,3 @@ char *acc_version(void) return info.version; } - -/* - * $Log: a_version.c,v $ - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/11 15:19:12 steve - * Add acc_fetch_argc/argv/version (mruff) - * - */ diff --git a/libveriuser/asynch.c b/libveriuser/asynch.c index 0273ed9d8..969f34e60 100644 --- a/libveriuser/asynch.c +++ b/libveriuser/asynch.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: asynch.c,v 1.3 2003/04/23 15:01:29 steve Exp $" -#endif # include @@ -39,16 +36,3 @@ int tf_asynchoff(void) async_misctf_enable = 0; return 0; } - -/* - * $Log: asynch.c,v $ - * Revision 1.3 2003/04/23 15:01:29 steve - * Add tf_synchronize and tf_multiply_long. - * - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/04 01:40:03 steve - * Add asynchon and asynchoff - * - */ diff --git a/libveriuser/config.h.in b/libveriuser/config.h.in index 4d3b3e825..3496f7134 100644 --- a/libveriuser/config.h.in +++ b/libveriuser/config.h.in @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # define SIZEOF_UNSIGNED_LONG_LONG 0 diff --git a/libveriuser/delay.c b/libveriuser/delay.c index f33fcb1e4..2aa47b3ce 100644 --- a/libveriuser/delay.c +++ b/libveriuser/delay.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: delay.c,v 1.3 2003/06/17 16:55:07 steve Exp $" -#endif #include #include @@ -78,23 +75,3 @@ int tf_setdelay(PLI_INT32 delay) { return tf_isetdelay(delay, tf_getinstance()); } - -/* - * $Log: delay.c,v $ - * Revision 1.3 2003/06/17 16:55:07 steve - * 1) setlinebuf() for vpi_trace - * 2) Addes error checks for trace file opens - * 3) removes now extraneous flushes - * 4) fixes acc_next() bug - * - * Revision 1.2 2003/05/28 02:42:43 steve - * compiler warnings. - * - * Revision 1.1 2003/05/18 00:16:35 steve - * Add PLI_TRACE tracing of PLI1 modules. - * - * Add tf_isetdelay and friends, and add - * callback return values for acc_vcl support. - * - */ - diff --git a/libveriuser/exprinfo.c b/libveriuser/exprinfo.c index 1cd4f65d5..314b3d5fb 100644 --- a/libveriuser/exprinfo.c +++ b/libveriuser/exprinfo.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: exprinfo.c,v 1.1 2003/10/10 02:57:46 steve Exp $" -#endif # include # include @@ -41,13 +38,3 @@ struct t_tfexprinfo* tf_exprinfo(PLI_INT32 a, struct t_tfexprinfo*ip) } return 0; } - - - -/* - * $Log: exprinfo.c,v $ - * Revision 1.1 2003/10/10 02:57:46 steve - * Some PLI1 stubs. - * - */ - diff --git a/libveriuser/finish.c b/libveriuser/finish.c index 1f31ce4d6..e69d339d4 100644 --- a/libveriuser/finish.c +++ b/libveriuser/finish.c @@ -14,16 +14,12 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: finish.c,v 1.2 2002/08/12 01:35:02 steve Exp $" -#endif # include # include - /* * Implement tf_dofinish and tf_dostop using vpi functions. */ @@ -38,14 +34,3 @@ int tf_dostop(void) vpi_control(vpiStop, 0); return 0; } - -/* - * $Log: finish.c,v $ - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/05/19 05:21:00 steve - * Start the libveriuser library. - * - */ - diff --git a/libveriuser/getcstringp.c b/libveriuser/getcstringp.c index a5786d26f..1d8662bdc 100644 --- a/libveriuser/getcstringp.c +++ b/libveriuser/getcstringp.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: getcstringp.c,v 1.3 2003/03/13 04:35:09 steve Exp $" -#endif #include #include @@ -31,16 +28,3 @@ char *tf_getcstringp(int n) char*res = acc_fetch_tfarg_str(n); return res; } - -/* - * $Log: getcstringp.c,v $ - * Revision 1.3 2003/03/13 04:35:09 steve - * Add a bunch of new acc_ and tf_ functions. - * - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/07 02:58:59 steve - * Add a bunch of acc/tf functions. (mruff) - * - */ diff --git a/libveriuser/getinstance.c b/libveriuser/getinstance.c index dbd613b97..b887e86be 100644 --- a/libveriuser/getinstance.c +++ b/libveriuser/getinstance.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: getinstance.c,v 1.5 2005/09/20 18:34:01 steve Exp $" -#endif #include #include @@ -30,25 +27,3 @@ PLI_BYTE8* tf_getinstance(void) { return (PLI_BYTE8 *)vpi_handle(vpiSysTfCall, 0 /* NULL */); } - -/* - * $Log: getinstance.c,v $ - * Revision 1.5 2005/09/20 18:34:01 steve - * Clean up compiler warnings. - * - * Revision 1.4 2003/05/18 00:16:35 steve - * Add PLI_TRACE tracing of PLI1 modules. - * - * Add tf_isetdelay and friends, and add - * callback return values for acc_vcl support. - * - * Revision 1.3 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.2 2002/06/03 21:52:59 steve - * Fix return type of tf_getinstance. - * - * Revision 1.1 2002/06/02 18:54:59 steve - * Add tf_getinstance function. - * - */ diff --git a/libveriuser/getlongp.c b/libveriuser/getlongp.c index db6c764a5..b3930cb13 100644 --- a/libveriuser/getlongp.c +++ b/libveriuser/getlongp.c @@ -1,5 +1,5 @@ -/* vi:sw=6 - * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) +/* + * Copyright (c) 2002-2012 Michael Ruff (mruff at chiaro.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 @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: getlongp.c,v 1.3 2003/03/15 05:42:39 steve Exp $" -#endif #include #include @@ -34,7 +31,6 @@ int tf_getlongp(int *highvalue, int n) vpiHandle sys_h, sys_i, arg_h = 0; s_vpi_value value; int len, rtn; - char *str, **end = 0; assert(highvalue); assert(n > 0); @@ -56,31 +52,19 @@ int tf_getlongp(int *highvalue, int n) /* convert string to int(s) */ len = strlen(value.value.str); if (len > 8) { + char *str; /* low word */ str = value.value.str + (len - 8); - rtn = (int) strtoul(str, end, 16); + rtn = (int) strtoul(str, 0, 16); /* high word */ *str = '\0'; - *highvalue = (int) strtoul(value.value.str, end, 16); + *highvalue = (int) strtoul(value.value.str, 0, 16); } else { *highvalue = 0; - rtn = (int) strtoul(value.value.str, end, 16); + rtn = (int) strtoul(value.value.str, 0, 16); } vpi_free_object(sys_i); return rtn; } - -/* - * $Log: getlongp.c,v $ - * Revision 1.3 2003/03/15 05:42:39 steve - * free argument iterators. - * - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/07 02:58:59 steve - * Add a bunch of acc/tf functions. (mruff) - * - */ diff --git a/libveriuser/getp.c b/libveriuser/getp.c index 75d42b853..a32852bfd 100644 --- a/libveriuser/getp.c +++ b/libveriuser/getp.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/libveriuser/getsimtime.c b/libveriuser/getsimtime.c index 716480f4d..646cbf491 100644 --- a/libveriuser/getsimtime.c +++ b/libveriuser/getsimtime.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include @@ -29,6 +29,15 @@ * some TF time routines implemented using VPI interface */ +// On some platforms (e.g. MinGW), pow() may not always generate an +// exact integer result when supplied with integer operands. Converting +// the result to an integer before we use it seems to be enough to work +// round this issue. +static ivl_u64_t pow10u(PLI_INT32 val) +{ + return (ivl_u64_t)pow(10, val); +} + static ivl_u64_t scale(int high, int low, void*obj) { vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); @@ -36,8 +45,8 @@ scale(int high, int low, void*obj) { scaled = high; scaled = (scaled << 32) | low; - scaled /= pow(10, vpi_get(vpiTimeUnit,obj ? (vpiHandle)obj : hand) - - vpi_get(vpiTimePrecision,0)); + scaled /= pow10u(vpi_get(vpiTimeUnit,obj ? (vpiHandle)obj : hand) - + vpi_get(vpiTimePrecision,0)); return scaled; } diff --git a/libveriuser/io_print.c b/libveriuser/io_print.c index 575f6bfc5..f72cb6405 100644 --- a/libveriuser/io_print.c +++ b/libveriuser/io_print.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: io_print.c,v 1.4 2002/12/19 21:37:04 steve Exp $" -#endif # include # include @@ -70,22 +67,3 @@ PLI_INT32 tf_message(PLI_INT32 level, char*facility, vpi_printf("\n"); return 0; } - - -/* - * $Log: io_print.c,v $ - * Revision 1.4 2002/12/19 21:37:04 steve - * Add tf_message, tf_get/setworkarea, and - * ty_typep functions, along with defines - * related to these functions. - * - * Revision 1.3 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.2 2002/05/30 02:10:08 steve - * Add tf_error and tf_warning from mruff - * - * Revision 1.1 2002/05/23 03:35:42 steve - * Add the io_printf function to libveriuser. - * - */ diff --git a/libveriuser/math.c b/libveriuser/math.c index 7456873ca..e218ea84b 100644 --- a/libveriuser/math.c +++ b/libveriuser/math.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: math.c,v 1.3 2003/06/13 19:23:42 steve Exp $" -#endif # include # include @@ -54,23 +51,3 @@ void tf_long_to_real(PLI_INT32 low, PLI_INT32 high, double *real) a = (a << 32) | low; *real = (double)a; } - -/* - * $Log: math.c,v $ - * Revision 1.3 2003/06/13 19:23:42 steve - * Add a bunch more PLI1 routines. - * - * Revision 1.2 2003/06/04 01:56:20 steve - * 1) Adds configure logic to clean up compiler warnings - * 2) adds acc_compare_handle, acc_fetch_range, acc_next_scope and - * tf_isetrealdelay, acc_handle_scope - * 3) makes acc_next reentrant - * 4) adds basic vpiWire type support - * 5) fills in some acc_object_of_type() and acc_fetch_{full}type() - * 6) add vpiLeftRange/RigthRange to signals - * - * Revision 1.1 2003/04/23 15:01:29 steve - * Add tf_synchronize and tf_multiply_long. - * - */ - diff --git a/libveriuser/mc_scan_plusargs.c b/libveriuser/mc_scan_plusargs.c index d92eb1844..59ea48a70 100644 --- a/libveriuser/mc_scan_plusargs.c +++ b/libveriuser/mc_scan_plusargs.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: mc_scan_plusargs.c,v 1.3 2002/08/12 01:35:02 steve Exp $" -#endif # include # include @@ -66,16 +63,3 @@ char *mc_scan_plusargs(char *plusarg) /* didn't find it yet */ return (char *)0; } - -/* - * $Log: mc_scan_plusargs.c,v $ - * Revision 1.3 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.2 2002/05/24 21:46:21 steve - * Only match plusargs. - * - * Revision 1.1 2002/05/24 20:29:07 steve - * Implement mc_scan_plusargs. - * - */ diff --git a/libveriuser/nodeinfo.c b/libveriuser/nodeinfo.c index 6f2736767..d421c7ae5 100644 --- a/libveriuser/nodeinfo.c +++ b/libveriuser/nodeinfo.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: nodeinfo.c,v 1.1 2003/10/10 02:57:46 steve Exp $" -#endif # include # include @@ -41,13 +38,3 @@ struct t_tfnoeinfo* tf_nodeinfo(PLI_INT32 a, struct t_tfnodeinfo*ip) } return 0; } - - - -/* - * $Log: nodeinfo.c,v $ - * Revision 1.1 2003/10/10 02:57:46 steve - * Some PLI1 stubs. - * - */ - diff --git a/libveriuser/nump.c b/libveriuser/nump.c index 61ac6d803..c1449cae2 100644 --- a/libveriuser/nump.c +++ b/libveriuser/nump.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: nump.c,v 1.3 2003/05/28 03:38:05 steve Exp $" -#endif #include #include @@ -46,16 +43,3 @@ int tf_nump(void) vpiHandle sys_h = vpi_handle(vpiSysTfCall, 0 /* NULL */); return tf_inump(sys_h); } - -/* - * $Log: nump.c,v $ - * Revision 1.3 2003/05/28 03:38:05 steve - * Implement tf_inump - * - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/05/30 02:12:17 steve - * Add tf_nump from mruff. - * - */ diff --git a/libveriuser/priv.c b/libveriuser/priv.c index cd3355617..ef06e78f9 100644 --- a/libveriuser/priv.c +++ b/libveriuser/priv.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: priv.c,v 1.3 2003/05/18 00:16:35 steve Exp $" -#endif # include "priv.h" # include @@ -55,25 +52,3 @@ char* __acc_newstring(const char*txt) return res; } - -/* - * $Log: priv.c,v $ - * Revision 1.3 2003/05/18 00:16:35 steve - * Add PLI_TRACE tracing of PLI1 modules. - * - * Add tf_isetdelay and friends, and add - * callback return values for acc_vcl support. - * - * Revision 1.2 2003/03/13 05:07:46 steve - * Declaration warnings. - * - * Revision 1.1 2003/02/17 06:39:47 steve - * Add at least minimal implementations for several - * acc_ functions. Add support for standard ACC - * string handling. - * - * Add the _pli_types.h header file to carry the - * IEEE1364-2001 standard PLI type declarations. - * - */ - diff --git a/libveriuser/priv.h b/libveriuser/priv.h index 36c1faeec..0fdabeb8b 100644 --- a/libveriuser/priv.h +++ b/libveriuser/priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/libveriuser/putlongp.c b/libveriuser/putlongp.c index 9d05bd4aa..1093d9507 100644 --- a/libveriuser/putlongp.c +++ b/libveriuser/putlongp.c @@ -1,4 +1,4 @@ -/* vi:sw=6 +/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) * * This source code is free software; you can redistribute it @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: putlongp.c,v 1.4 2004/09/10 23:13:05 steve Exp $" -#endif #include #include @@ -62,19 +59,3 @@ void tf_putlongp(int n, int lowvalue, int highvalue) vpi_free_object(sys_i); } - -/* - * $Log: putlongp.c,v $ - * Revision 1.4 2004/09/10 23:13:05 steve - * Compile cleanup of C code. - * - * Revision 1.3 2003/03/15 05:42:39 steve - * free argument iterators. - * - * Revision 1.2 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.1 2002/06/07 16:21:13 steve - * Add tf_putlongp and tf_putp. - * - */ diff --git a/libveriuser/putp.c b/libveriuser/putp.c index be58cf7ee..1a6e71b39 100644 --- a/libveriuser/putp.c +++ b/libveriuser/putp.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/libveriuser/spname.c b/libveriuser/spname.c index ff785177b..bb00d0deb 100644 --- a/libveriuser/spname.c +++ b/libveriuser/spname.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: spname.c,v 1.4 2003/06/17 16:55:08 steve Exp $" -#endif #include #include @@ -51,29 +48,3 @@ char *tf_mipname(void) { return tf_imipname(vpi_handle(vpiSysTfCall,0)); } - -/* - * $Log: spname.c,v $ - * Revision 1.4 2003/06/17 16:55:08 steve - * 1) setlinebuf() for vpi_trace - * 2) Addes error checks for trace file opens - * 3) removes now extraneous flushes - * 4) fixes acc_next() bug - * - * Revision 1.3 2003/05/29 03:46:21 steve - * Add tf_getp/putp support for integers - * and real valued arguments. - * - * Add tf_mipname function. - * - * Revision 1.2 2003/05/18 00:16:35 steve - * Add PLI_TRACE tracing of PLI1 modules. - * - * Add tf_isetdelay and friends, and add - * callback return values for acc_vcl support. - * - * Revision 1.1 2003/03/13 04:35:09 steve - * Add a bunch of new acc_ and tf_ functions. - * - */ - diff --git a/libveriuser/typep.c b/libveriuser/typep.c index 0ddb93a12..23fbc6eb8 100644 --- a/libveriuser/typep.c +++ b/libveriuser/typep.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: typep.c,v 1.2 2003/03/13 05:07:46 steve Exp $" -#endif #include #include diff --git a/libveriuser/veriusertfs.c b/libveriuser/veriusertfs.c index dc8d350df..114dcf45d 100644 --- a/libveriuser/veriusertfs.c +++ b/libveriuser/veriusertfs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2011 Michael Ruff (mruff at chiaro.com) + * Copyright (c) 2002-2012 Michael Ruff (mruff at chiaro.com) * Michael Runyan (mrunyan at chiaro.com) * * This source code is free software; you can redistribute it @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* @@ -184,7 +184,6 @@ static PLI_INT32 compiletf(char *data) p_tfcell tf; s_cb_data cb_data; vpiHandle call_h, arg_i, arg_h; - p_pli_data dp; int rtn = 0; /* cast back from opaque */ @@ -221,7 +220,7 @@ static PLI_INT32 compiletf(char *data) cb_data.reason = cbValueChange; while ((arg_h = vpi_scan(arg_i)) != NULL) { /* replicate user_data for each instance */ - dp = calloc(1, sizeof(s_pli_data)); + p_pli_data dp = calloc(1, sizeof(s_pli_data)); memcpy(dp, cb_data.user_data, sizeof(s_pli_data)); dp->paramvc = paramvc++; cb_data.user_data = (char *)dp; diff --git a/libveriuser/workarea.c b/libveriuser/workarea.c index 4be46d70a..30c14dab1 100644 --- a/libveriuser/workarea.c +++ b/libveriuser/workarea.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/link_const.cc b/link_const.cc index 5cd3d7f5f..867e71b92 100644 --- a/link_const.cc +++ b/link_const.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 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 @@ -14,13 +14,14 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include "netlist.h" # include "netmisc.h" +# include "ivl_assert.h" /* * Scan the link for drivers. If there are only constant drivers, then @@ -35,7 +36,6 @@ bool Nexus::drivers_constant() const return true; for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) { - const NetNet*sig; Link::DIR cur_dir; cur_dir = cur->get_dir(); @@ -56,6 +56,7 @@ bool Nexus::drivers_constant() const outside world. */ if (cur_dir == Link::PASSIVE) { + const NetNet*sig; const NetPins*obj = cur->get_obj(); const NetObj*as_obj = dynamic_cast(obj); @@ -172,3 +173,46 @@ verinum::V Nexus::driven_value() const return val; } + +verinum Nexus::driven_vector() const +{ + const Link*cur = list_; + + verinum val; + + for (cur = first_nlink() ; cur ; cur = cur->next_nlink()) { + + const NetConst*obj; + const NetNet*sig; + if ((obj = dynamic_cast(cur->get_obj()))) { + ivl_assert(*obj, cur->get_pin() == 0); + val = obj->value(); + + } else if ((sig = dynamic_cast(cur->get_obj()))) { + + // If we find an attached SUPPLY0/1, the we know + // from that what the driven value is. Stop now. + if (sig->type() == NetNet::SUPPLY0) { + driven_ = V0; + return verinum(verinum::V0, sig->vector_width()); + } + if (sig->type() == NetNet::SUPPLY1) { + driven_ = V1; + return verinum(verinum::V1, sig->vector_width()); + } + + // If we find an attached TRI0/1, then this is a + // good guess for the driven value, but keep + // looking for something better. + if (sig->type() == NetNet::TRI0) { + val = verinum(verinum::V0, sig->vector_width()); + } + if (sig->type() == NetNet::TRI1) { + val = verinum(verinum::V1, sig->vector_width()); + } + } + } + + return val; +} + diff --git a/load_module.cc b/load_module.cc index 91d9241fb..665b865e9 100644 --- a/load_module.cc +++ b/load_module.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/macosx.txt b/macosx.txt index 5e58f253e..6248533b8 100644 --- a/macosx.txt +++ b/macosx.txt @@ -37,13 +37,13 @@ quite similar. then just make sure the distributed lexor_keyword.cc is newer than lexor_keyword.gperf, and use that. -3) If working with a CVS snapshot, you must run autoconf in several - directories. This is aided by the 'autoconf.sh' script at the +3) If working with source from git, you must run autoconf in the top + directory. This is simplified by the 'autoconf.sh' script at the top of the source tree: sh ./autoconf.sh - This will also run the gperf command, so make sure you'd completed + This will also run the gperf command, so make sure you've completed step #2 first. 4) Configure, build and install the Icarus Verilog sources as normal. diff --git a/main.cc b/main.cc index 2b8066576..5c2bb207d 100644 --- a/main.cc +++ b/main.cc @@ -1,5 +1,5 @@ const char COPYRIGHT[] = - "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 @@ -15,7 +15,7 @@ const char COPYRIGHT[] = * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -784,7 +784,17 @@ int main(int argc, char*argv[]) #if defined(TRAP_SIGINT_FOR_DEBUG) signal(SIGINT, &signals_handler); #endif - + if( ::getenv("IVL_WAIT_FOR_DEBUGGER") != 0 ) { + fprintf( stderr, "Waiting for debugger...\n"); + bool debugger_release = false; + while( !debugger_release ) { +#if defined(__MINGW32__) + Sleep(1000); +#else + sleep(1); +#endif + } + } library_suff.push_back(strdup(".v")); // Start the module list with the base system module. @@ -839,6 +849,8 @@ int main(int argc, char*argv[]) cout << COPYRIGHT << endl << endl; cout << NOTICE << endl; + cout << " FLAGS DLL " << flags["DLL"] << endl; + dll_target_obj.test_version(flags["DLL"]); return 0; diff --git a/mingw.txt b/mingw.txt index af1c61489..b5dc25307 100644 --- a/mingw.txt +++ b/mingw.txt @@ -173,7 +173,7 @@ where we will work from now on. Under certain cases, you may need to "preconfigure" the Icarus Verilog source tree. You should only need to do this if you are getting the -Icarus Verilog source tree from CVS, or you are using an existing +Icarus Verilog source tree from git, or you are using an existing source tree that you've patched to cause configure.in files to change. NOTE: If you are building from a fresh, bundled source tree that diff --git a/named.h b/named.h index 77ad68f62..c10367a9f 100644 --- a/named.h +++ b/named.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "StringHeap.h" diff --git a/net_analog.cc b/net_analog.cc index 9482aa7f4..ebe36d169 100644 --- a/net_analog.cc +++ b/net_analog.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/net_assign.cc b/net_assign.cc index 286f4cd30..d4fefa69c 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -14,12 +14,15 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include "netlist.h" +# include "netclass.h" +# include "netdarray.h" +# include "ivl_assert.h" /* * NetAssign @@ -84,14 +87,72 @@ ivl_select_type_t NetAssign_::select_type() const unsigned NetAssign_::lwidth() const { + // If the signal is a class type, then the situation is either + // "a.b" or "a.b.". If this is "a.b" (no + // member/property reference, then return width==1. If this is + // "a.b.", then get the type of the property + // and return the width of that. + if (const netclass_t*class_type = sig_->class_type()) { + if (member_.nil()) + return 1; + + const ivl_type_s*ptype = class_type->get_property(member_); + ivl_assert(*sig_, ptype); + + return ptype->packed_width(); + } + + if (netdarray_t*darray = sig_->darray_type()) { + if (word_ == 0) + return 1; + else + return darray->element_width(); + } + return lwid_; } ivl_variable_type_t NetAssign_::expr_type() const { + if (const netclass_t*class_type = sig_->class_type()) { + if (member_.nil()) + return sig_->data_type(); + + const ivl_type_s*tmp = class_type->get_property(member_); + return tmp->base_type(); + } + + if (netdarray_t*darray = sig_->darray_type()) { + if (word_ == 0) + return IVL_VT_DARRAY; + else + return darray->element_base_type(); + } + return sig_->data_type(); } +const ivl_type_s* NetAssign_::net_type() const +{ + if (const netclass_t*class_type = sig_->class_type()) { + if (member_.nil()) + return sig_->net_type(); + + const ivl_type_s*tmp = class_type->get_property(member_); + ivl_assert(*sig_, tmp); + return tmp; + } + + if (dynamic_cast (sig_->net_type())) { + if (word_ == 0) + return sig_->net_type(); + + return 0; + } + + return 0; +} + netenum_t*NetAssign_::enumeration() const { netenum_t*tmp = 0; @@ -133,6 +194,12 @@ void NetAssign_::set_part(NetExpr*base, unsigned wid, sel_type_ = sel_type; } +void NetAssign_::set_property(const perm_string&mname) +{ + ivl_assert(*sig_, sig_->class_type()); + member_ = mname; +} + /* */ void NetAssign_::turn_sig_to_wire_on_release() diff --git a/net_design.cc b/net_design.cc index 3ed2fef8c..a32ff236a 100644 --- a/net_design.cc +++ b/net_design.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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -101,10 +101,11 @@ uint64_t Design::scale_to_precision(uint64_t val, return val; } -NetScope* Design::make_root_scope(perm_string root) +NetScope* Design::make_root_scope(perm_string root, bool program_block) { NetScope *root_scope_; - root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE); + root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE, + false, program_block); /* This relies on the fact that the basename return value is permallocated. */ root_scope_->set_module_name(root_scope_->basename()); @@ -162,6 +163,26 @@ NetScope* Design::find_scope(const std::list&path) const return 0; } +/* + * This method locates a scope in the design, given its rooted + * hierarchical name. Each component of the key is used to scan one + * more step down the tree until the name runs out or the search + * fails. + */ +NetScope* Design::find_scope(const hname_t&path) const +{ + for (list::const_iterator scope = root_scopes_.begin() + ; scope != root_scopes_.end(); ++ scope ) { + + NetScope*cur = *scope; + if (path.peek_name() == cur->basename()) + return cur; + + } + + return 0; +} + /* * This is a relative lookup of a scope by name. The starting point is * the scope parameter within which I start looking for the scope. If @@ -196,7 +217,7 @@ NetScope* Design::find_scope(NetScope*scope, const std::list&path, if (cur == 0) break; } tmp.pop_front(); - } while (!tmp.empty()); + } while (! tmp.empty()); if (cur) return cur; } @@ -205,6 +226,43 @@ NetScope* Design::find_scope(NetScope*scope, const std::list&path, return find_scope(path); } +/* + * This is a relative lookup of a scope by name. The starting point is + * the scope parameter within which I start looking for the scope. If + * I do not find the scope within the passed scope, start looking in + * parent scopes until I find it, or I run out of parent scopes. + */ +NetScope* Design::find_scope(NetScope*scope, const hname_t&path, + NetScope::TYPE type) const +{ + assert(scope); + + for ( ; scope ; scope = scope->parent()) { + + NetScope*cur = scope; + + /* If we are looking for a module or we are not + * looking at the last path component check for + * a name match (second line). */ + if (cur->type() == NetScope::MODULE + && (type == NetScope::MODULE) + && cur->module_name()==path.peek_name()) { + + /* Up references may match module name */ + + } else { + cur = cur->child( path ); + } + + if (cur) return cur; + } + + // Last chance. Look for the name starting at the root. + listpath_list; + path_list.push_back(path); + return find_scope(path_list); +} + /* * This method runs through the scope, noticing the defparam * statements that were collected during the elaborate_scope pass and @@ -303,11 +361,9 @@ void NetScope::run_defparams_later(Design*des) target_scopes.insert(targ_scope); } - // All the scopes that this defparam set touched should have - // their parameters re-evaluated. - for (set::iterator cur = target_scopes.begin() - ; cur != target_scopes.end() ; ++ cur ) - (*cur)->evaluate_parameters(des); + // The scopes that this defparam set touched will be + // re-evaluated later it a top_defparams work item. So do not + // do the evaluation now. // If there are some scopes that still have missing scopes, // then save them back into the defparams_later list for a @@ -370,7 +426,8 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) if (range_flag) lv_width = (msb >= lsb) ? 1 + msb - lsb : 1 + lsb - msb; - NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width, true); + NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width, true, + (*cur).second.is_annotatable); if (! expr) return; @@ -491,7 +548,8 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) PExpr*val_expr = (*cur).second.val_expr; NetScope*val_scope = (*cur).second.val_scope; - NetExpr*expr = elab_and_eval(des, val_scope, val_expr, -1, true); + NetExpr*expr = elab_and_eval(des, val_scope, val_expr, -1, true, + (*cur).second.is_annotatable); if (! expr) return; diff --git a/net_event.cc b/net_event.cc index b3b200398..3c31521d4 100644 --- a/net_event.cc +++ b/net_event.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/net_expr.cc b/net_expr.cc index b632693fa..fcb6db1a7 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -14,15 +14,47 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include "netlist.h" # include "netenum.h" +# include "netclass.h" +# include "netdarray.h" # include "compiler.h" # include "netmisc.h" # include +# include "ivl_assert.h" + +NetExpr::NetExpr(unsigned w) +: net_type_(0), width_(w), signed_flag_(false) +{ +} + +NetExpr::NetExpr(ivl_type_t t) +: net_type_(t), width_(0), signed_flag_(false) +{ +} + +NetExpr::~NetExpr() +{ +} + +ivl_type_t NetExpr::net_type() const +{ + return net_type_; +} + +void NetExpr::cast_signed(bool flag) +{ + cast_signed_base_(flag); +} + +bool NetExpr::has_width() const +{ + return true; +} /* * the grand default data type is a logic vector. @@ -184,18 +216,23 @@ bool NetEBShift::has_width() const return left_->has_width(); } -NetEConcat::NetEConcat(unsigned cnt, unsigned r) -: parms_(cnt), repeat_(r) +NetEConcat::NetEConcat(unsigned cnt, unsigned r, ivl_variable_type_t vt) +: parms_(cnt), repeat_(r), expr_type_(vt) { expr_width(0); } NetEConcat::~NetEConcat() { - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) delete parms_[idx]; } +ivl_variable_type_t NetEConcat::expr_type() const +{ + return expr_type_; +} + bool NetEConcat::has_width() const { return true; @@ -203,7 +240,7 @@ bool NetEConcat::has_width() const void NetEConcat::set(unsigned idx, NetExpr*e) { - assert(idx < parms_.count()); + assert(idx < parms_.size()); assert(parms_[idx] == 0); parms_[idx] = e; expr_width( expr_width() + repeat_ * e->expr_width() ); @@ -284,6 +321,48 @@ netenum_t* NetENetenum::netenum() const return netenum_; } +NetENew::NetENew(ivl_type_t t) +: obj_type_(t), size_(0) +{ +} + +NetENew::NetENew(ivl_type_t t, NetExpr*size) +: obj_type_(t), size_(size) +{ +} + +NetENew::~NetENew() +{ +} + +ivl_variable_type_t NetENew::expr_type() const +{ + return size_ ? IVL_VT_DARRAY : IVL_VT_CLASS; +} + +NetENull::NetENull() +{ +} + +NetENull::~NetENull() +{ +} + +NetEProperty::NetEProperty(NetNet*net, perm_string pnam) +: net_(net) +{ + const netclass_t*use_type = dynamic_cast(net->net_type()); + assert(use_type); + + pidx_ = use_type->property_idx_from_name(pnam); + ivl_type_t prop_type = use_type->get_prop_type(pidx_); + expr_width(prop_type->packed_width()); +} + +NetEProperty::~NetEProperty() +{ +} + NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid, ivl_select_type_t sel_type) : expr_(exp), base_(base), sel_type_(sel_type) @@ -312,6 +391,32 @@ ivl_select_type_t NetESelect::select_type() const return sel_type_; } +ivl_variable_type_t NetESelect::expr_type() const +{ + ivl_variable_type_t type = expr_->expr_type(); + + // Special case: If the sub-expression is an IVL_VT_STRING, + // then this node is representing a character select. The + // width is the width of a byte, and the data type is BOOL. + if (type == IVL_VT_STRING && expr_width()==8) + return IVL_VT_BOOL; + + if (type != IVL_VT_DARRAY) + return type; + + ivl_assert(*this, type == IVL_VT_DARRAY); + + // Special case: If the expression is a DARRAY, then the + // sub-expression must be a NetESignal and the type of the + // NetESelect expression is the element type of the arrayed signal. + NetESignal*sig = dynamic_cast(expr_); + ivl_assert(*this, sig); + const netarray_t*array_type = dynamic_cast (sig->sig()->net_type()); + ivl_assert(*this, array_type); + + return array_type->element_type()->base_type(); +} + bool NetESelect::has_width() const { return true; @@ -325,11 +430,27 @@ NetESFunc::NetESFunc(const char*n, ivl_variable_type_t t, expr_width(width); } +NetESFunc::NetESFunc(const char*n, ivl_type_t rtype, unsigned np) +: NetExpr(rtype), name_(0), type_(IVL_VT_NO_TYPE), enum_type_(0), parms_(np) +{ + name_ = lex_strings.add(n); + expr_width(rtype->packed_width()); + // FIXME: For now, assume that all uses of this constructor + // are for the IVL_VT_DARRAY type. Eventually, the type_ + // member will go away. + if (dynamic_cast(rtype)) + type_ = IVL_VT_DARRAY; + else if (dynamic_cast(rtype)) + type_ = IVL_VT_CLASS; + else + ivl_assert(*this, 0); +} + NetESFunc::NetESFunc(const char*n, netenum_t*enum_type, unsigned np) : name_(0), type_(enum_type->base_type()), enum_type_(enum_type), parms_(np) { name_ = lex_strings.add(n); - expr_width(enum_type->base_width()); + expr_width(enum_type->packed_width()); } NetESFunc::~NetESFunc() diff --git a/net_func.cc b/net_func.cc index 3347635f8..40838751f 100644 --- a/net_func.cc +++ b/net_func.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/net_func_eval.cc b/net_func_eval.cc new file mode 100644 index 000000000..69020c2db --- /dev/null +++ b/net_func_eval.cc @@ -0,0 +1,441 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "netlist.h" +# include "netmisc.h" +# include "compiler.h" +# include +# include "ivl_assert.h" + +using namespace std; + +NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector&args) const +{ + // Make the context map; + map::iterator ptr; + mapcontext_map; + + if (debug_eval_tree) { + cerr << loc.get_fileline() << ": debug: " + << "Evaluate function " << scope_->basename() << endl; + } + + // Put the return value into the map... + context_map[scope_->basename()] = 0; + + // Load the input ports into the map... + ivl_assert(loc, ports_.size() == args.size()); + for (size_t idx = 0 ; idx < ports_.size() ; idx += 1) { + perm_string aname = ports_[idx]->name(); + context_map[aname] = args[idx]; + + if (debug_eval_tree) { + cerr << loc.get_fileline() << ": debug: " + << " input " << aname << " = " << *args[idx] << endl; + } + } + + // Ask the scope to collect definitions for local values. This + // fills in the context_map with local variables held by the scope. + scope_->evaluate_function_find_locals(loc, context_map); + + // Perform the evaluation + bool flag = statement_->evaluate_function(loc, context_map); + + // Extract the result... + ptr = context_map.find(scope_->basename()); + NetExpr*res = ptr->second; + context_map.erase(ptr); + + + // Cleanup the rest of the context. + for (ptr = context_map.begin() ; ptr != context_map.end() ; ++ptr) { + delete ptr->second; + } + + // Done. + if (flag) + return res; + + delete res; + return 0; +} + +void NetScope::evaluate_function_find_locals(const LineInfo&loc, + map&context_map) const +{ + for (map::const_iterator cur = signals_map_.begin() + ; cur != signals_map_.end() ; ++cur) { + + const NetNet*tmp = cur->second; + // Skip ports, which are handled elsewhere. + if (tmp->port_type() != NetNet::NOT_A_PORT) + continue; + + context_map[tmp->name()] = 0; + + if (debug_eval_tree) { + cerr << loc.get_fileline() << ": debug: " + << " (local) " << tmp->name() << endl; + } + } +} + +NetExpr* NetExpr::evaluate_function(const LineInfo&, + map&) const +{ + cerr << get_fileline() << ": sorry: I don't know how to evaluate this expression at compile time." << endl; + cerr << get_fileline() << ": : Expression type:" << typeid(*this).name() << endl; + + return 0; +} + +bool NetProc::evaluate_function(const LineInfo&, + map&) const +{ + cerr << get_fileline() << ": sorry: I don't know how to evaluate this statement at compile time." << endl; + cerr << get_fileline() << ": : Statement type:" << typeid(*this).name() << endl; + + return false; +} + +bool NetAssign::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + if (l_val_count() != 1) { + cerr << get_fileline() << ": sorry: I don't know how to evaluate " + "concatenated l-values here." << endl; + return false; + } + + const NetAssign_*lval = l_val(0); + + map::iterator ptr = context_map.find(lval->name()); + ivl_assert(*this, ptr != context_map.end()); + + // Do not support having l-values that are unpacked arrays. + ivl_assert(loc, lval->word() == 0); + + // Evaluate the r-value expression. + NetExpr*rval_result = rval()->evaluate_function(loc, context_map); + if (rval_result == 0) + return false; + + if (const NetExpr*base_expr = lval->get_base()) { + NetExpr*base_result = base_expr->evaluate_function(loc, context_map); + if (base_result == 0) { + delete rval_result; + return false; + } + + NetEConst*base_const = dynamic_cast(base_result); + ivl_assert(loc, base_const); + + long base = base_const->value().as_long(); + + listprefix (0); + base = lval->sig()->sb_to_idx(prefix, base); + + if (ptr->second == 0) + ptr->second = make_const_x(lval->sig()->vector_width()); + + ivl_assert(loc, base + lval->lwidth() <= ptr->second->expr_width()); + + NetEConst*ptr_const = dynamic_cast(ptr->second); + verinum lval_v = ptr_const->value(); + NetEConst*rval_const = dynamic_cast(rval_result); + verinum rval_v = cast_to_width(rval_const->value(), lval->lwidth()); + + for (unsigned idx = 0 ; idx < rval_v.len() ; idx += 1) + lval_v.set(idx+base, rval_v[idx]); + + delete base_result; + delete rval_result; + rval_result = new NetEConst(lval_v); + } + + if (ptr->second) + delete ptr->second; + + if (debug_eval_tree) { + cerr << get_fileline() << ": debug: " + << "NetAssign::evaluate_function: " << lval->name() + << " = " << *rval_result << endl; + } + + ptr->second = rval_result; + + return true; +} + +/* + * Evaluating a NetBlock in a function is a simple matter of + * evaluating the statements in order. + */ +bool NetBlock::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + bool flag = true; + NetProc*cur = last_; + do { + cur = cur->next_; + bool cur_flag = cur->evaluate_function(loc, context_map); + flag = flag && cur_flag; + } while (cur != last_); + + return flag; +} + +bool NetCondit::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + NetExpr*cond = expr_->evaluate_function(loc, context_map); + if (cond == 0) + return false; + + NetEConst*cond_const = dynamic_cast (cond); + ivl_assert(loc, cond_const); + + long val = cond_const->value().as_long(); + delete cond; + + if (val) + // The condition is true, so evaluate the if clause + return (if_ == 0) || if_->evaluate_function(loc, context_map); + else + // The condition is false, so evaluate the else clause + return (else_ == 0) || else_->evaluate_function(loc, context_map); +} + +bool NetWhile::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + bool flag = true; + + if (debug_eval_tree) { + cerr << get_fileline() << ": debug: NetWhile::evaluate_function: " + << "Start loop" << endl; + } + + while (flag) { + // Evaluate the condition expression to try and get the + // condition for the loop. + NetExpr*cond = cond_->evaluate_function(loc, context_map); + if (cond == 0) { + flag = false; + break; + } + + NetEConst*cond_const = dynamic_cast (cond); + ivl_assert(loc, cond_const); + + long val = cond_const->value().as_long(); + delete cond; + + // If the condition is false, then break. + if (val == 0) + break; + + // The condition is true, so evaluate the statement + // another time. + bool tmp_flag = proc_->evaluate_function(loc, context_map); + if (! tmp_flag) + flag = false; + } + + if (debug_eval_tree) { + cerr << get_fileline() << ": debug: NetWhile::evaluate_function: " + << "Done loop" << endl; + } + + return flag; +} + +NetExpr* NetEBComp::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + NetExpr*lval = left_->evaluate_function(loc, context_map); + NetExpr*rval = right_->evaluate_function(loc, context_map); + + if (lval == 0 || rval == 0) { + delete lval; + delete rval; + return 0; + } + + NetEConst*res = eval_arguments_(lval, rval); + delete lval; + delete rval; + return res; +} + +NetExpr* NetEBAdd::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + NetExpr*lval = left_->evaluate_function(loc, context_map); + NetExpr*rval = right_->evaluate_function(loc, context_map); + + if (lval == 0 || rval == 0) { + delete lval; + delete rval; + return 0; + } + + NetExpr*res = eval_arguments_(lval, rval); + delete lval; + delete rval; + return res; +} + +NetExpr* NetEBMult::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + NetExpr*lval = left_->evaluate_function(loc, context_map); + NetExpr*rval = right_->evaluate_function(loc, context_map); + + if (lval == 0 || rval == 0) { + delete lval; + delete rval; + return 0; + } + + NetExpr*res = eval_arguments_(lval, rval); + delete lval; + delete rval; + return res; +} + +NetExpr* NetEBShift::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + NetExpr*lval = left_->evaluate_function(loc, context_map); + NetExpr*rval = right_->evaluate_function(loc, context_map); + + if (lval == 0 || rval == 0) { + delete lval; + delete rval; + return 0; + } + + NetEConst*res = eval_arguments_(lval, rval); + delete lval; + delete rval; + return res; +} + +NetExpr* NetEConst::evaluate_function(const LineInfo&, + map&) const +{ + NetEConst*res = new NetEConst(value_); + res->set_line(*this); + return res; +} + +NetExpr* NetESelect::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + NetExpr*sub_exp = expr_->evaluate_function(loc, context_map); + ivl_assert(loc, sub_exp); + + NetEConst*sub_const = dynamic_cast (sub_exp); + ivl_assert(loc, sub_exp); + + verinum sub = sub_const->value(); + delete sub_exp; + + long base = 0; + if (base_) { + NetExpr*base_val = base_->evaluate_function(loc, context_map); + ivl_assert(loc, base_val); + + NetEConst*base_const = dynamic_cast(base_val); + ivl_assert(loc, base_const); + + base = base_const->value().as_long(); + delete base_val; + } else { + sub = pad_to_width(sub, expr_width()); + } + + verinum res (verinum::Vx, expr_width()); + for (unsigned idx = 0 ; idx < res.len() ; idx += 1) + res.set(idx, sub[base+idx]); + + NetEConst*res_const = new NetEConst(res); + return res_const; +} + +NetExpr* NetESignal::evaluate_function(const LineInfo&, + map&context_map) const +{ + if (word_) { + cerr << get_fileline() << ": sorry: I don't know how to evaluate signal word selects at compile time." << endl; + return 0; + } + + map::iterator ptr = context_map.find(name()); + if (ptr == context_map.end()) { + cerr << get_fileline() << ": error: Cannot evaluate " << name() + << " in this context." << endl; + return 0; + } + + return ptr->second->dup_expr(); +} + +NetExpr* NetETernary::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + auto_ptr cval (cond_->evaluate_function(loc, context_map)); + + switch (const_logical(cval.get())) { + + case C_0: + return false_val_->evaluate_function(loc, context_map); + case C_1: + return true_val_->evaluate_function(loc, context_map); + case C_X: + break; + default: + cerr << get_fileline() << ": error: Condition expression is not constant here." << endl; + return 0; + } + + NetExpr*tval = true_val_->evaluate_function(loc, context_map); + NetExpr*fval = false_val_->evaluate_function(loc, context_map); + + NetExpr*res = blended_arguments_(tval, fval); + delete tval; + delete fval; + return res; +} + +NetExpr* NetEUFunc::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + NetFuncDef*def = func_->func_def(); + ivl_assert(*this, def); + + vectorargs(parms_.size()); + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) + args[idx] = parms_[idx]->evaluate_function(loc, context_map); + + NetExpr*res = def->evaluate_function(*this, args); + return res; +} diff --git a/net_link.cc b/net_link.cc index 0d99acd90..0bd45a9ce 100644 --- a/net_link.cc +++ b/net_link.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/net_modulo.cc b/net_modulo.cc index 7a5167824..43efa806b 100644 --- a/net_modulo.cc +++ b/net_modulo.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/net_nex_input.cc b/net_nex_input.cc index 712ef37b0..d75b3c7c1 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2011 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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -56,7 +56,7 @@ NexusSet* NetEConcat::nex_input(bool rem_out) { if (parms_[0] == NULL) return NULL; NexusSet*result = parms_[0]->nex_input(rem_out); - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { if (parms_[idx] == NULL) { delete result; return NULL; @@ -96,6 +96,21 @@ NexusSet* NetENetenum::nex_input(bool) return new NexusSet; } +NexusSet* NetENew::nex_input(bool) +{ + return new NexusSet; +} + +NexusSet* NetENull::nex_input(bool) +{ + return new NexusSet; +} + +NexusSet* NetEProperty::nex_input(bool) +{ + return new NexusSet; +} + NexusSet* NetEScope::nex_input(bool) { return new NexusSet; @@ -159,7 +174,7 @@ NexusSet* NetESignal::nex_input(bool rem_out) delete tmp; if (warn_sens_entire_arr) { cerr << get_fileline() << ": warning: @* is sensitive to all " - << net_->array_count() << " words in array '" + << net_->unpacked_count() << " words in array '" << name() << "'." << endl; } } @@ -188,7 +203,7 @@ NexusSet* NetETernary::nex_input(bool rem_out) NexusSet* NetEUFunc::nex_input(bool rem_out) { NexusSet*result = new NexusSet; - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { NexusSet*tmp = parms_[idx]->nex_input(rem_out); result->add(*tmp); delete tmp; @@ -257,7 +272,7 @@ NexusSet* NetBlock::nex_input(bool rem_out) if (last_ == 0) return new NexusSet; - if (type_ == PARA) { + if (type_ != SEQU) { cerr << get_fileline() << ": internal error: Sorry, " << "I don't know how to synthesize fork/join blocks." << endl; @@ -397,13 +412,13 @@ NexusSet* NetRepeat::nex_input(bool rem_out) */ NexusSet* NetSTask::nex_input(bool rem_out) { - if (parms_.count() == 0) + if (parms_.empty()) return new NexusSet; NexusSet*result; if (parms_[0]) result = parms_[0]->nex_input(rem_out); else result = new NexusSet; - for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) { if (parms_[idx]) { NexusSet*tmp = parms_[idx]->nex_input(rem_out); result->add(*tmp); diff --git a/net_nex_output.cc b/net_nex_output.cc index 35d3f4b52..9a61a54ae 100644 --- a/net_nex_output.cc +++ b/net_nex_output.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/net_proc.cc b/net_proc.cc index 83487dd91..d9412fa9d 100644 --- a/net_proc.cc +++ b/net_proc.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/net_scope.cc b/net_scope.cc index a1231055b..6a5771636 100644 --- a/net_scope.cc +++ b/net_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 @@ -14,13 +14,14 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include "compiler.h" # include "netlist.h" +# include "netclass.h" # include "netenum.h" # include # include @@ -38,8 +39,8 @@ class PExpr; * in question. */ -NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t) -: type_(t), name_(n), up_(up) +NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bool prog) +: type_(t), name_(n), nested_module_(nest), program_block_(prog), up_(up) { events_ = 0; lcounter_ = 0; @@ -114,13 +115,15 @@ void NetScope::set_line(perm_string file, perm_string def_file, def_lineno_ = def_lineno; } -void NetScope::set_parameter(perm_string key, PExpr*val, - ivl_variable_type_t type__, +void NetScope::set_parameter(perm_string key, bool is_annotatable, + PExpr*val, ivl_variable_type_t type__, PExpr*msb, PExpr*lsb, bool signed_flag, + bool local_flag, NetScope::range_t*range_list, const LineInfo&file_line) { param_expr_t&ref = parameters[key]; + ref.is_annotatable = is_annotatable; ref.msb_expr = msb; ref.lsb_expr = lsb; ref.val_expr = val; @@ -129,6 +132,7 @@ void NetScope::set_parameter(perm_string key, PExpr*val, ref.msb = 0; ref.lsb = 0; ref.signed_flag = signed_flag; + ref.local_flag = local_flag; ivl_assert(file_line, ref.range == 0); ref.range = range_list; ref.val = 0; @@ -137,6 +141,28 @@ void NetScope::set_parameter(perm_string key, PExpr*val, ivl_assert(file_line, type__ != IVL_VT_NO_TYPE); } +/* + * This is a simplified version of set_parameter, for use when the + * parameter value is already known. It is currently only used to + * add a genvar to the parameter list. + */ +void NetScope::set_parameter(perm_string key, NetExpr*val, + const LineInfo&file_line) +{ + param_expr_t&ref = parameters[key]; + ref.is_annotatable = false; + ref.msb_expr = 0; + ref.lsb_expr = 0; + ref.val_expr = 0; + ref.val_scope = this; + ref.type = IVL_VT_BOOL; + ref.msb = 0; + ref.lsb = 0; + ref.signed_flag = false; + ref.val = val; + ref.set_line(file_line); +} + bool NetScope::auto_name(const char*prefix, char pad, const char* suffix) { // Find the current reference to myself in the parent scope. @@ -188,26 +214,17 @@ bool NetScope::replace_parameter(perm_string key, PExpr*val, NetScope*scope) return flag; } -/* - * This is not really complete (msb, lsb, sign). It is currently only - * used to add a genvar to the local parameter list. - */ -NetExpr* NetScope::set_localparam(perm_string key, NetExpr*val, - const LineInfo&file_line) +bool NetScope::make_parameter_unannotatable(perm_string key) { - param_expr_t&ref = localparams[key]; - NetExpr* res = ref.val; - ref.msb_expr = 0; - ref.lsb_expr = 0; - ref.val_expr = 0; - ref.val_scope = this; - ref.type = IVL_VT_BOOL; - ref.msb = 0; - ref.lsb = 0; - ref.signed_flag = false; - ref.val = val; - ref.set_line(file_line); - return res; + bool flag = false; + + if (parameters.find(key) != parameters.end()) { + param_expr_t&ref = parameters[key]; + flag = ref.is_annotatable; + ref.is_annotatable = false; + } + + return flag; } /* @@ -242,16 +259,6 @@ const NetExpr* NetScope::get_parameter(Design*des, return idx->second.val; } - idx = localparams.find(key); - if (idx != localparams.end()) { - if (idx->second.val_expr) - evaluate_parameter_(des, idx); - - msb = idx->second.msb; - lsb = idx->second.lsb; - return idx->second.val; - } - map::const_iterator eidx; eidx = enum_names_.find(key); @@ -271,9 +278,6 @@ NetScope::param_ref_t NetScope::find_parameter(perm_string key) idx = parameters.find(key); if (idx != parameters.end()) return idx; - idx = localparams.find(perm_string::literal(key)); - if (idx != localparams.end()) return idx; - // To get here the parameter must already exist, so we should // never get here. assert(0); @@ -364,23 +368,51 @@ perm_string NetScope::module_name() const return module_name_; } -void NetScope::add_module_port(NetNet*port) +void NetScope::set_num_ports(unsigned int num_ports) { - assert(type_ == MODULE); - ports_.push_back(port); + assert(type_ == MODULE); + assert(ports_.empty()); + ports_.resize( num_ports ); } -unsigned NetScope::module_ports() const +void NetScope::add_module_port_net(NetNet*subport) { assert(type_ == MODULE); - return ports_.size(); + port_nets.push_back(subport); } -NetNet* NetScope::module_port(unsigned idx) const + +void NetScope::add_module_port_info( unsigned idx, perm_string name, PortType::Enum ptype, + unsigned long width ) { assert(type_ == MODULE); - assert(idx < ports_.size()); - return ports_[idx]; + PortInfo &info = ports_[idx]; + info.name = name; + info.type = ptype; + info.width = width; +} + + +unsigned NetScope::module_port_nets() const +{ + assert(type_ == MODULE); + return port_nets.size(); +} + + +const std::vector & NetScope::module_port_info() const +{ + assert(type_ == MODULE); + return ports_; +} + + + +NetNet* NetScope::module_port_net(unsigned idx) const +{ + assert(type_ == MODULE); + assert(idx < port_nets.size()); + return port_nets[idx]; } void NetScope::time_unit(int val) @@ -520,6 +552,20 @@ netenum_t*NetScope::enumeration_for_name(perm_string name) return tmp->enumeration(); } +void NetScope::add_class(netclass_t*net_class) +{ + classes_[net_class->get_name()] = net_class; +} + +netclass_t*NetScope::find_class(perm_string name) +{ + map::const_iterator cur = classes_.find(name); + if (cur == classes_.end()) + return 0; + else + return cur->second; +} + /* * This method locates a child scope by name. The name is the simple * name of the child, no hierarchy is searched. diff --git a/net_tran.cc b/net_tran.cc index e170bb3fc..7a1476096 100644 --- a/net_tran.cc +++ b/net_tran.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/net_udp.cc b/net_udp.cc index e9ca4e0bd..0ed83d49a 100644 --- a/net_udp.cc +++ b/net_udp.cc @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/netclass.cc b/netclass.cc new file mode 100644 index 000000000..6561d824e --- /dev/null +++ b/netclass.cc @@ -0,0 +1,86 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "netclass.h" +# include + +using namespace std; + +netclass_t::netclass_t(perm_string name) +: name_(name) +{ +} + +netclass_t::~netclass_t() +{ +} + +bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype) +{ + map::const_iterator cur; + cur = properties_.find(pname); + if (cur != properties_.end()) + return false; + + prop_t tmp; + tmp.name = pname; + tmp.type = ptype; + property_table_.push_back(tmp); + + properties_[pname] = property_table_.size()-1; + return true; +} + +ivl_variable_type_t netclass_t::base_type() const +{ + return IVL_VT_CLASS; +} + +const ivl_type_s* netclass_t::get_property(perm_string pname) const +{ + map::const_iterator cur; + cur = properties_.find(pname); + if (cur == properties_.end()) + return 0; + + assert(property_table_.size() > cur->second); + return property_table_[cur->second].type; +} + +int netclass_t::property_idx_from_name(perm_string pname) const +{ + map::const_iterator cur; + cur = properties_.find(pname); + if (cur == properties_.end()) + return -1; + + return cur->second; +} + +const char*netclass_t::get_prop_name(size_t idx) const +{ + assert(idx < property_table_.size()); + return property_table_[idx].name; +} + +ivl_type_t netclass_t::get_prop_type(size_t idx) const +{ + assert(idx < property_table_.size()); + return property_table_[idx].type; +} diff --git a/netclass.h b/netclass.h new file mode 100644 index 000000000..bfbb0285d --- /dev/null +++ b/netclass.h @@ -0,0 +1,64 @@ +#ifndef __netclass_H +#define __netclass_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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "LineInfo.h" +# include "ivl_target.h" +# include "nettypes.h" +# include + +class netclass_t : public ivl_type_s { + public: + netclass_t(perm_string class_name); + ~netclass_t(); + + // Set the property of the class during elaboration. Set the + // name and type, and return true. If the name is already + // present, then return false. + bool set_property(perm_string pname, ivl_type_s*ptype); + + // As an ivl_type_s object, the netclass is always an + // ivl_VT_CLASS object. + ivl_variable_type_t base_type() const; + + // This is the name of the class type + inline perm_string get_name() const { return name_; } + + const ivl_type_s* get_property(perm_string pname) const; + + inline size_t get_properties(void) const { return properties_.size(); } + const char*get_prop_name(size_t idx) const; + ivl_type_t get_prop_type(size_t idx) const; + + int property_idx_from_name(perm_string pname) const; + + private: + perm_string name_; + // Map properrty names to property table index. + std::map properties_; + // Vector of properties. + struct prop_t { + perm_string name; + ivl_type_s* type; + }; + std::vector property_table_; +}; + +#endif diff --git a/netdarray.cc b/netdarray.cc new file mode 100644 index 000000000..b1845831a --- /dev/null +++ b/netdarray.cc @@ -0,0 +1,36 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "netdarray.h" + +using namespace std; + +netdarray_t::netdarray_t(ivl_type_t vec) +: netarray_t(vec) +{ +} + +netdarray_t::~netdarray_t() +{ +} + +ivl_variable_type_t netdarray_t::base_type(void) const +{ + return IVL_VT_DARRAY; +} diff --git a/netdarray.h b/netdarray.h new file mode 100644 index 000000000..8068896dd --- /dev/null +++ b/netdarray.h @@ -0,0 +1,50 @@ +#ifndef __netdarray_H +#define __netdarray_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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "nettypes.h" +# include "ivl_target.h" + +class netdarray_t : public netarray_t { + + public: + explicit netdarray_t(ivl_type_t vec); + ~netdarray_t(); + + // This is the "base_type()" virtual method of the + // nettype_base_t. The ivl_target api expects this to return + // IVL_VT_DARRAY for dynamic arrays? + ivl_variable_type_t base_type() const; + + // This is the base_type() of the element of the array. We + // need this in some cases in order to get the base type of + // the element, and not the IVL_VT_DARRAY of the array itself. + inline ivl_variable_type_t element_base_type() const { return element_type()->base_type(); } + + // This is a convenience function for getting the width of an + // element. Strictly speaking it's not necessary. + inline unsigned long element_width(void) const { return element_type()->packed_width(); } + + std::ostream& debug_dump(std::ostream&) const; + + private: +}; + +#endif diff --git a/netenum.cc b/netenum.cc index 99dd26f9b..614a9618a 100644 --- a/netenum.cc +++ b/netenum.cc @@ -14,13 +14,15 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "netenum.h" # include "compiler.h" # include +using namespace std; + netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag, long msb, long lsb, size_t name_count) : base_type_(btype), signed_flag_(signed_flag), msb_(msb), lsb_(lsb), @@ -32,6 +34,27 @@ netenum_t::~netenum_t() { } +bool netenum_t::get_signed() const +{ + return signed_flag_; +} + +long netenum_t::packed_width() const +{ + if (msb_ >= lsb_) + return msb_ - lsb_ + 1; + else + return lsb_ - msb_ + 1; +} + +vector netenum_t::slice_dimensions() const +{ + vector tmp (1); + tmp[0] = netrange_t(msb_, lsb_); + return tmp; +} + + bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val) { std::pair::iterator, bool> res; diff --git a/netenum.h b/netenum.h index 81080f9e3..80704bd0c 100644 --- a/netenum.h +++ b/netenum.h @@ -16,10 +16,11 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "ivl_target.h" +# include "nettypes.h" # include "verinum.h" # include "StringHeap.h" # include "LineInfo.h" @@ -28,7 +29,7 @@ class NetScope; -class netenum_t : public LineInfo { +class netenum_t : public LineInfo, public ivl_type_s { public: explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag, @@ -36,8 +37,9 @@ class netenum_t : public LineInfo { ~netenum_t(); ivl_variable_type_t base_type() const; - unsigned base_width() const; - bool has_sign() const; + long packed_width() const; + std::vector slice_dimensions() const; + bool get_signed() const; // The size() is the number of enumeration literals. size_t size() const; @@ -72,16 +74,6 @@ class netenum_t : public LineInfo { inline ivl_variable_type_t netenum_t::base_type() const { return base_type_; } -inline unsigned netenum_t::base_width() const -{ - if (msb_ >= lsb_) - return msb_ - lsb_ + 1; - else - return lsb_ - msb_ + 1; -} - inline size_t netenum_t::size() const { return names_.size(); } -inline bool netenum_t::has_sign() const { return signed_flag_; } - #endif diff --git a/netlist.cc b/netlist.cc index ef0b6c1a6..cdc76e35b 100644 --- a/netlist.cc +++ b/netlist.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -27,7 +27,12 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netclass.h" +# include "netdarray.h" +# include "netenum.h" +# include "netparray.h" # include "netstruct.h" +# include "netvector.h" # include "ivl_assert.h" @@ -447,40 +452,18 @@ const Link& NetDelaySrc::condit_pin() const return pin(pin_count()-1); } -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), struct_type_(0), discipline_(0), - dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) +PortType::Enum PortType::merged( Enum lhs, Enum rhs ) { - 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) { - case REG: - case INTEGER: - case IMPLICIT_REG: - dir = Link::OUTPUT; - break; - case SUPPLY0: - dir = Link::OUTPUT; - break; - case SUPPLY1: - dir = Link::OUTPUT; - break; - default: - break; - } - - pin(0).set_dir(dir); - - s->add_signal(this); + if( lhs == NOT_A_PORT || rhs == NOT_A_PORT ) + return NOT_A_PORT; + if( lhs == PIMPLICIT ) + return rhs; + if( rhs == PIMPLICIT ) + return lhs; + if( lhs == rhs ) { + return lhs; + } + return PINOUT; } void NetNet::initialize_dir_(Link::DIR dir) @@ -495,68 +478,76 @@ void NetNet::initialize_dir_(Link::DIR dir) } } -NetNet::NetNet(NetScope*s, perm_string n, Type t, - 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), struct_type_(0), discipline_(0), - dimensions_(0), s0_(0), e0_(0), - eref_count_(0), lref_count_(0) +static unsigned calculate_count(const list&unpacked) { - packed_dims_ = packed; - assert(s); + unsigned long sum = 1; + for (list::const_iterator cur = unpacked.begin() + ; cur != unpacked.end() ; ++cur) { + // Special case: If there are any undefined dimensions, + // then give up on trying to create pins for the net. + if (! cur->defined()) + return 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; + sum *= cur->width(); } - initialize_dir_(dir); - - s->add_signal(this); -} - -static unsigned calculate_count(long s, long e) -{ - unsigned long r; - if (s >= e) { - r = s - e; - } else { - r = e - s; - } - if (r >= UINT_MAX) { + if (sum >= UINT_MAX) return 0; + + return sum; +} + +template static unsigned calculate_count(T*type) +{ + long wid = type->packed_width(); + if (wid >= 0) + return wid; + else + return 1; +} + +void NetNet::calculate_slice_widths_from_packed_dims_(void) +{ + ivl_assert(*this, net_type_); + slice_dims_ = net_type_->slice_dimensions(); + + // Special case: There are no actual packed dimensions, so + // build up a fake dimension of "1". + if (slice_dims_.empty()) { + slice_wids_.resize(1); + slice_wids_[0] = net_type_->packed_width(); + return; + } + + slice_wids_.resize(slice_dims_.size()); + + ivl_assert(*this, ! slice_wids_.empty()); + slice_wids_[0] = netrange_width(slice_dims_); + vector::const_iterator cur = slice_dims_.begin(); + for (size_t idx = 1 ; idx < slice_wids_.size() ; idx += 1) { + slice_wids_[idx] = slice_wids_[idx-1] / cur->width(); } - return r + 1; } NetNet::NetNet(NetScope*s, perm_string n, Type t, - const list&packed, long array_s, long array_e) -: NetObj(s, n, calculate_count(array_s, array_e)), + const list&unpacked, ivl_type_s*use_net_type) +: NetObj(s, n, calculate_count(unpacked)), 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_(0), - discipline_(0), - dimensions_(1), s0_(array_s), e0_(array_e), + local_flag_(false), net_type_(use_net_type), + discipline_(0), unpacked_dims_(unpacked.size()), eref_count_(0), lref_count_(0) { - packed_dims_ = packed; + calculate_slice_widths_from_packed_dims_(); + size_t idx = 0; + for (list::const_iterator cur = unpacked.begin() + ; cur != unpacked.end() ; ++cur, idx += 1) { + unpacked_dims_[idx] = *cur; + } + assert(idx == unpacked_dims_.size()); + ivl_assert(*this, s); if (pin_count() == 0) { - cerr << "Array too big [" << array_s << ":" << array_e << "]" << endl; + cerr << "Invalid array dimensions: " << unpacked << endl; ivl_assert(*this, 0); } @@ -582,15 +573,6 @@ 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 @@ -599,13 +581,71 @@ static unsigned calculate_count(netstruct_t*type) 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), + local_flag_(false), net_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)); + //XXXX packed_dims_.push_back(netrange_t(calculate_count(ty)-1, 0)); + calculate_slice_widths_from_packed_dims_(); + 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(NetScope*s, perm_string n, Type t, netdarray_t*ty) +: NetObj(s, n, 1), + type_(t), port_type_(NOT_A_PORT), + local_flag_(false), net_type_(ty), + discipline_(0), + eref_count_(0), lref_count_(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(NetScope*s, perm_string n, Type t, netvector_t*ty) +: NetObj(s, n, 1), + type_(t), port_type_(NOT_A_PORT), + local_flag_(false), net_type_(ty), + discipline_(0), + eref_count_(0), lref_count_(0) +{ + calculate_slice_widths_from_packed_dims_(); Link::DIR dir = Link::PASSIVE; switch (t) { @@ -693,64 +733,103 @@ void NetNet::port_type(NetNet::PortType t) port_type_ = t; } -ivl_variable_type_t NetNet::data_type() const +int NetNet::get_module_port_index() const { - return data_type_; + return port_index_; } -void NetNet::data_type(ivl_variable_type_t t) +void NetNet::set_module_port_index(unsigned idx) { - data_type_ = t; + port_index_ = idx; + assert( port_index_ >= 0 ); +} + +ivl_variable_type_t NetNet::data_type() const +{ + if (net_type_==0) + return IVL_VT_LOGIC; + else + return net_type_->base_type(); } bool NetNet::get_signed() const { - if (data_type_ == IVL_VT_REAL) - return true; + if (net_type_==0) + return false; else - return signed_; -} - -void NetNet::set_signed(bool flag) -{ - signed_ = flag; + return net_type_->get_signed(); } bool NetNet::get_isint() const { - return isint_; -} - -void NetNet::set_isint(bool flag) -{ - isint_ = flag; + if (netvector_t*vec = dynamic_cast (net_type_)) + return vec->get_isint(); + else + return false; } bool NetNet::get_scalar() const { - return is_scalar_; -} - -void NetNet::set_scalar(bool flag) -{ - is_scalar_ = flag; + if (netvector_t*vec = dynamic_cast (net_type_)) + return vec->get_scalar(); + else + return false; } netenum_t*NetNet::enumeration(void) const { - return enumeration_; + return dynamic_cast (net_type_); } -void NetNet::set_enumeration(netenum_t*es) +const netstruct_t*NetNet::struct_type(void) const { - ivl_assert(*this, struct_type_ == 0); - ivl_assert(*this, enumeration_ == 0); - enumeration_ = es; + const ivl_type_s*cur_type = net_type_; + while (cur_type) { + if (const netdarray_t*da = dynamic_cast (cur_type)) { + cur_type = da->element_type(); + continue; + } + if (const netparray_t*da = dynamic_cast (cur_type)) { + cur_type = da->element_type(); + continue; + } + if (const netstruct_t*st = dynamic_cast (cur_type)) + return st; + else + return 0; + } + + assert(0); + return 0; } -netstruct_t*NetNet::struct_type(void) const +netdarray_t* NetNet::darray_type(void) const { - return struct_type_; + return dynamic_cast (net_type_); +} + +netclass_t* NetNet::class_type(void) const +{ + return dynamic_cast (net_type_); +} + +/* + * "depth" is the number of index expressions that the user is using + * to index this identifer. So consider if Net was declared like so: + * + * reg [5:0][3:0] foo; + * + * In this case, slice_width(2) == 1 (slice_width(N) where N is the + * number of dimensions will always be 1.) and represents + * $bits(foo[a][b]). Then, slice_width(1)==4 ($bits(foo[a]) and slice_width(0)==24. + */ +unsigned long NetNet::slice_width(size_t depth) const +{ + if (depth > slice_wids_.size()) + return 0; + if (depth == slice_wids_.size()) + return 1; + return slice_wids_[depth]; } ivl_discipline_t NetNet::get_discipline() const @@ -764,61 +843,45 @@ void NetNet::set_discipline(ivl_discipline_t dis) discipline_ = dis; } -unsigned long NetNet::vector_width(const list&packed) -{ - 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; -} - bool NetNet::sb_is_valid(const list&indices, long sb) const { - 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); + ivl_assert(*this, indices.size()+1 == packed_dims().size()); + assert(packed_dims().size() == 1); + const netrange_t&rng = packed_dims().back(); + if (rng.get_msb() >= rng.get_lsb()) + return (sb <= rng.get_msb()) && (sb >= rng.get_lsb()); else - return (sb <= rng.lsb) && (sb >= rng.msb); + return (sb <= rng.get_lsb()) && (sb >= rng.get_msb()); } long NetNet::sb_to_idx(const list&indices, long sb) const { - ivl_assert(*this, indices.size()+1 == packed_dims_.size()); + ivl_assert(*this, indices.size()+1 == packed_dims().size()); - list::const_iterator pcur = packed_dims_.end(); + vector::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; + if (pcur->get_msb() >= pcur->get_lsb()) + acc_off = sb - pcur->get_lsb(); else - acc_off = pcur->lsb - sb; + acc_off = pcur->get_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) { + if (! indices.empty()) { list::const_iterator icur = indices.end(); do { -- icur; -- pcur; long tmp_off; - if (pcur->msb >= pcur->lsb) - tmp_off = *icur - pcur->lsb; + if (pcur->get_msb() >= pcur->get_lsb()) + tmp_off = *icur - pcur->get_lsb(); else - tmp_off = pcur->lsb - *icur; + tmp_off = pcur->get_lsb() - *icur; acc_off += tmp_off * acc_wid; acc_wid *= pcur->width(); @@ -831,99 +894,20 @@ long NetNet::sb_to_idx(const list&indices, long sb) const bool NetNet::sb_to_slice(const list&indices, long sb, long&loff, unsigned long&lwid) const { - ivl_assert(*this, indices.size() < packed_dims_.size()); + ivl_assert(*this, indices.size() < packed_dims().size()); + return prefix_to_slice(packed_dims(), indices, sb, loff, lwid); +} - 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(); +unsigned NetNet::unpacked_count() const +{ + unsigned c = 1; + for (size_t idx = 0 ; idx < unpacked_dims_.size() ; idx += 1) { + c *= unpacked_dims_[idx].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 - 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_; -} - -long NetNet::array_first() const -{ - if (s0_ <= e0_) - return s0_; - else - return e0_; -} - -bool NetNet::array_addr_swapped() const -{ - if (s0_ <= e0_) - return false; - else - return true; -} - -unsigned NetNet::array_count() const -{ - unsigned c = calculate_count(s0_, e0_); - ivl_assert(*this, c > 0); return c; } -bool NetNet::array_index_is_valid(long sb) const -{ - if (sb < s0_ && sb < e0_) - return false; - if (sb > e0_ && sb > s0_) - return false; - return true; -} - -unsigned NetNet::array_index_to_address(long sb) const -{ - if (s0_ <= e0_) - return sb - s0_; - else - return sb - e0_; -} - void NetNet::incr_eref() { eref_count_ += 1; @@ -946,7 +930,7 @@ unsigned NetNet::peek_eref() const */ bool NetNet::test_part_lref(unsigned pmsb, unsigned plsb) { - if (lref_mask_.size() == 0) + if (lref_mask_.empty()) lref_mask_.resize(vector_width()); bool rc = false; @@ -1047,11 +1031,6 @@ unsigned NetPartSelect::base() const return off_; } -NetPartSelect::dir_t NetPartSelect::dir() const -{ - return dir_; -} - NetProc::NetProc() : next_(0) { @@ -2029,47 +2008,28 @@ NetProc* NetCondit::else_clause() } NetConst::NetConst(NetScope*s, perm_string n, verinum::V v) -: NetNode(s, n, 1), width_(1) +: NetNode(s, n, 1), value_(v, 1) { pin(0).set_dir(Link::OUTPUT); - value_ = new verinum::V[1]; - value_[0] = v; - is_string_ = false; } NetConst::NetConst(NetScope*s, perm_string n, const verinum&val) -: NetNode(s, n, 1), width_(val.len()) +: NetNode(s, n, 1), value_(val) { pin(0).set_dir(Link::OUTPUT); - value_ = new verinum::V[width_]; - for (unsigned idx = 0 ; idx < width_ ; idx += 1) { - value_[idx] = val.get(idx); - } - is_string_ = val.is_string(); } NetConst::~NetConst() { - delete[]value_; } verinum::V NetConst::value(unsigned idx) const { - assert(idx < width_); + assert(idx < width()); return value_[idx]; } -unsigned NetConst::width() const -{ - return width_; -} - -bool NetConst::is_string() const -{ - return is_string_; -} - -NetFuncDef::NetFuncDef(NetScope*s, NetNet*result, const svector&po) +NetFuncDef::NetFuncDef(NetScope*s, NetNet*result, const vector&po) : scope_(s), statement_(0), result_sig_(result), ports_(po) { } @@ -2102,12 +2062,12 @@ NetScope*NetFuncDef::scope() unsigned NetFuncDef::port_count() const { - return ports_.count(); + return ports_.size(); } const NetNet* NetFuncDef::port(unsigned idx) const { - assert(idx < ports_.count()); + assert(idx < ports_.size()); return ports_[idx]; } @@ -2117,7 +2077,7 @@ const NetNet* NetFuncDef::return_sig() const } NetSTask::NetSTask(const char*na, ivl_sfunc_as_task_t sfat, - const svector&pa) + const vector&pa) : name_(0), sfunc_as_task_(sfat), parms_(pa) { name_ = lex_strings.add(na); @@ -2126,7 +2086,7 @@ NetSTask::NetSTask(const char*na, ivl_sfunc_as_task_t sfat, NetSTask::~NetSTask() { - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) delete parms_[idx]; /* The name_ string is perm-allocated in lex_strings. */ @@ -2144,7 +2104,7 @@ ivl_sfunc_as_task_t NetSTask::sfunc_as_task() const unsigned NetSTask::nparms() const { - return parms_.count(); + return parms_.size(); } const NetExpr* NetSTask::parm(unsigned idx) const @@ -2153,7 +2113,7 @@ const NetExpr* NetSTask::parm(unsigned idx) const } NetEUFunc::NetEUFunc(NetScope*scope, NetScope*def, NetESignal*res, - svector&p, bool nc) + vector&p, bool nc) : scope_(scope), func_(def), result_sig_(res), parms_(p), need_const_(nc) { expr_width(result_sig_->expr_width()); @@ -2161,7 +2121,7 @@ NetEUFunc::NetEUFunc(NetScope*scope, NetScope*def, NetESignal*res, NetEUFunc::~NetEUFunc() { - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) delete parms_[idx]; } #if 0 @@ -2177,12 +2137,12 @@ const NetESignal*NetEUFunc::result_sig() const unsigned NetEUFunc::parm_count() const { - return parms_.count(); + return parms_.size(); } const NetExpr* NetEUFunc::parm(unsigned idx) const { - assert(idx < parms_.count()); + assert(idx < parms_.size()); return parms_[idx]; } @@ -2251,25 +2211,6 @@ const NetScope* NetFree::scope() const return scope_; } -NetExpr::NetExpr(unsigned w) -: width_(w), signed_flag_(false) -{ -} - -NetExpr::~NetExpr() -{ -} - -void NetExpr::cast_signed(bool flag) -{ - cast_signed_base_(flag); -} - -bool NetExpr::has_width() const -{ - return true; -} - /* * Create a bitwise operator node from the opcode and the left and * right expressions. @@ -2409,7 +2350,7 @@ const NetScope* NetEScope::scope() const } NetESignal::NetESignal(NetNet*n) -: NetExpr(n->vector_width()), net_(n), word_(0) +: NetExpr(n->vector_width()), net_(n), enum_type_(n->enumeration()), word_(0) { net_->incr_eref(); set_line(*n); @@ -2434,6 +2375,11 @@ perm_string NetESignal::name() const return net_->name(); } +netenum_t* NetESignal::enumeration() const +{ + return enum_type_; +} + const NetExpr* NetESignal::word_index() const { return word_; @@ -2461,21 +2407,24 @@ NetNet* NetESignal::sig() */ long NetESignal::lsi() const { - const list&packed = net_->packed_dims(); + const vector&packed = net_->packed_dims(); ivl_assert(*this, packed.size() == 1); - return packed.back().lsb; + return packed.back().get_lsb(); } long NetESignal::msi() const { - const list&packed = net_->packed_dims(); + const vector&packed = net_->packed_dims(); ivl_assert(*this, packed.size() == 1); - return packed.back().msb; + return packed.back().get_msb(); } ivl_variable_type_t NetESignal::expr_type() const { - return net_->data_type(); + if (net_->darray_type()) + return IVL_VT_DARRAY; + else + return net_->data_type(); } /* diff --git a/netlist.h b/netlist.h index a99a41730..9e1bf3d31 100644 --- a/netlist.h +++ b/netlist.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* @@ -28,6 +28,7 @@ # include # include # include +# include # include # include # include @@ -35,6 +36,7 @@ # include "ivl_target_priv.h" # include "pform_types.h" # include "config.h" +# include "nettypes.h" # include "verinum.h" # include "verireal.h" # include "StringHeap.h" @@ -74,8 +76,12 @@ class NetEvTrig; class NetEvWait; class PExpr; class PFunction; +class netclass_t; +class netdarray_t; +class netparray_t; class netenum_t; class netstruct_t; +class netvector_t; struct target; struct functor_t; @@ -373,6 +379,7 @@ class Nexus { /* Given the nexus has constant drivers, this method returns the value that has been driven. */ verinum::V driven_value() const; + verinum driven_vector() const; /* The code generator sets an ivl_nexus_t to attach code generation details to the nexus. */ @@ -554,47 +561,56 @@ class NetDelaySrc : public NetObj { * anything and they are not a data sink, per se. The pins follow the * values on the nexus. */ -class NetNet : public NetObj { + +class PortType +{ +public: + enum Enum { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT, PREF }; + + /* + * Merge Port types (used to construct a sane combined port-type + * for module ports with complex defining expressions). + * + */ + static Enum merged( Enum lhs, Enum rhs ); +}; + + + /* + * Information on actual ports (rather than port-connected signals) of + * module. + * N.b. must be POD as passed through a "C" interface in the t-dll-api. + */ +struct PortInfo +{ + PortType::Enum type; + unsigned long width; + perm_string name; +}; + + +class NetNet : public NetObj, public PortType { public: enum Type { NONE, IMPLICIT, IMPLICIT_REG, INTEGER, WIRE, TRI, TRI1, SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG, UNRESOLVED_WIRE }; - 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; } - }; + typedef PortType::Enum PortType; 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. - explicit NetNet(NetScope*s, perm_string n, Type t, unsigned width =1); - - // This form supports an array of vectors. The [ms:ls] define - // the base vector, and the [s0:e0] define the array - // dimensions. If s0==e0, then this is not an array after - // all. + // This form is the more generic form of the constructor. For + // now, the unpacked type is not burried into an ivl_type_s object. explicit NetNet(NetScope*s, perm_string n, Type t, - const std::list&packed); - explicit NetNet(NetScope*s, perm_string n, Type t, - const std::list&packed, long s0, long e0); + const std::list&unpacked, + ivl_type_s*type =0); - // This form builds a NetNet from its record definition. + // This form builds a NetNet from its record/enum/darray + // definition. They should probably be replaced with a single + // version that takes an ivl_type_s* base. explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type); + explicit NetNet(NetScope*s, perm_string n, Type t, netdarray_t*type); + explicit NetNet(NetScope*s, perm_string n, Type t, netvector_t*type); virtual ~NetNet(); @@ -604,26 +620,28 @@ class NetNet : public NetObj { PortType port_type() const; void port_type(PortType t); + // If this net net is a port (i.e. a *sub*port net of a module port) + // its port index is number of the module it connects through + int get_module_port_index() const; // -1 Not connected to port... + void set_module_port_index(unsigned idx); + ivl_variable_type_t data_type() const; - void data_type(ivl_variable_type_t t); /* If a NetNet is signed, then its value is to be treated as signed. Otherwise, it is unsigned. */ bool get_signed() const; - void set_signed(bool); /* Used to maintain original type of net since integers are implemented as 'reg signed [31:0]' in Icarus */ bool get_isint() const; - void set_isint(bool); bool get_scalar() const; - void set_scalar(bool); - void set_enumeration(netenum_t*enum_set); + inline const ivl_type_s* net_type(void) const { return net_type_; } netenum_t*enumeration(void) const; - - netstruct_t*struct_type(void) const; + const netstruct_t*struct_type(void) const; + netdarray_t*darray_type(void) const; + netclass_t*class_type(void) const; /* Attach a discipline to the net. */ ivl_discipline_t get_discipline() const; @@ -632,15 +650,15 @@ class NetNet : public NetObj { /* 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 verilog declaration. These packed dims are compressed + to represent the dimensions of all the subtypes. */ + const std::vector& packed_dims() const { return slice_dims_; } + + const std::vector& unpacked_dims() const { return unpacked_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_); } + vector or scaler that is this NetNet object. */ + inline unsigned long vector_width() const { return slice_width(0); } /* Given a prefix of indices, figure out how wide the resulting slice would be. This is a generalization of the @@ -670,18 +688,14 @@ class NetNet : public NetObj { /* This method returns 0 for scalars and vectors, and greater for arrays. The value is the number of array indices. (Currently only one array index is supported.) */ - unsigned array_dimensions() const; - long array_first() const; - bool array_addr_swapped() const; + inline unsigned unpacked_dimensions() const { return unpacked_dims_.size(); } + + /* This methor returns 0 for scalars, but vectors and other + PACKED arrays have packed dimensions. */ + inline size_t packed_dimensions() const { return slice_dims_.size(); } // This is the number of array elements. - unsigned array_count() const; - - // This method returns a 0 based address of an array entry as - // indexed by idx. The Verilog source may give index ranges - // that are not zero based. - bool array_index_is_valid(long idx) const; - unsigned array_index_to_address(long idx) const; + unsigned unpacked_count() const; bool local_flag() const { return local_flag_; } void local_flag(bool f) { local_flag_ = f; } @@ -713,30 +727,33 @@ class NetNet : public NetObj { private: Type type_ : 5; PortType port_type_ : 3; - ivl_variable_type_t data_type_ : 3; - bool signed_ : 1; - bool isint_ : 1; // original type of integer - bool is_scalar_ : 1; bool local_flag_: 1; - netenum_t*enumeration_; - netstruct_t*struct_type_; + ivl_type_s*net_type_; ivl_discipline_t discipline_; - std::list packed_dims_; - const unsigned dimensions_; - long s0_, e0_; + std::vector unpacked_dims_; + + // These are the widths of the various slice depths. There is + // one entry in this vector for each packed dimension. The + // value at N is the slice width if N indices are provided. + // + // For example: slice_wids_[0] is vector_width(). + void calculate_slice_widths_from_packed_dims_(void); + std::vector slice_dims_; + std::vector slice_wids_; 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_; + int port_index_; }; -extern std::ostream&operator << (std::ostream&out, const std::list&rlist); /* * This object type is used to contain a logical scope within a @@ -750,7 +767,7 @@ class NetScope : public Attrib { /* Create a new scope, and attach it to the given parent. The name is expected to have been permallocated. */ - NetScope(NetScope*up, const hname_t&name, TYPE t); + NetScope(NetScope*up, const hname_t&name, TYPE t, bool nest=false, bool prog=false); ~NetScope(); /* Rename the scope using the name generated by inserting as @@ -762,17 +779,17 @@ class NetScope : public Attrib { /* Parameters exist within a scope, and these methods allow one to manipulate the set. In these cases, the name is the *simple* name of the parameter, the hierarchy is implicit in - the scope. The return value from set_parameter is the - previous expression, if there was one. */ + the scope. */ struct range_t; - void set_parameter(perm_string name, PExpr*val, - ivl_variable_type_t type, + void set_parameter(perm_string name, bool is_annotatable, + PExpr*val, ivl_variable_type_t type, PExpr*msb, PExpr*lsb, bool signed_flag, + bool local_flag, NetScope::range_t*range_list, const LineInfo&file_line); - NetExpr* set_localparam(perm_string name, NetExpr*val, - const LineInfo&file_line); + void set_parameter(perm_string name, NetExpr*val, + const LineInfo&file_line); const NetExpr*get_parameter(Design*des, const char* name, @@ -789,6 +806,13 @@ class NetScope : public Attrib { exist. */ bool replace_parameter(perm_string name, PExpr*val, NetScope*scope); + /* This is used to ensure the value of a parameter cannot be + changed at run-time. This is required if a specparam is used + in an expression that must be evaluated at compile-time. + Returns true if the named parameter is a specparam and has + not already been set to be unannotatable. */ + bool make_parameter_unannotatable(perm_string name); + /* These methods set or access events that live in this scope. */ @@ -814,6 +838,9 @@ class NetScope : public Attrib { netenum_t* enumeration_for_name(perm_string name); + void add_class(netclass_t*class_type); + netclass_t* find_class(perm_string name); + /* The parent and child() methods allow users of NetScope objects to locate nearby scopes. */ NetScope* parent() { return up_; } @@ -821,6 +848,10 @@ class NetScope : public Attrib { const NetScope* parent() const { return up_; } const NetScope* child(const hname_t&name) const; + // Nested modules have slightly different scope search rules. + inline bool nested_module() const { return nested_module_; } + // Program blocks have elaboration constraints. + inline bool program_block() const { return program_block_; } TYPE type() const; void print_type(ostream&) const; @@ -831,6 +862,11 @@ class NetScope : public Attrib { NetTaskDef* task_def(); NetFuncDef* func_def(); + // This is used by the evaluate_function setup to collect + // local variables from the scope. + void evaluate_function_find_locals(const LineInfo&loc, + map&context_map) const; + void set_line(perm_string file, perm_string def_file, unsigned lineno, unsigned def_lineno); void set_line(perm_string file, unsigned lineno); @@ -884,9 +920,18 @@ class NetScope : public Attrib { perm_string module_name() const; /* If the scope is a module then it may have ports that we need * to keep track of. */ - void add_module_port(NetNet*port); - unsigned module_ports() const; - NetNet*module_port(unsigned idx) const; + + void set_num_ports(unsigned int num_ports); + void add_module_port_net(NetNet*port); + unsigned module_port_nets() const; + NetNet*module_port_net(unsigned idx) const; + + void add_module_port_info( unsigned idx, + perm_string name, // May be "" for undeclared port + PortType::Enum type, + unsigned long width ); + + const std::vector &module_port_info() const; /* Scopes have their own time units and time precision. The unit and precision are given as power of 10, i.e., -3 is @@ -955,7 +1000,9 @@ class NetScope : public Attrib { access to these things to make up the parameter lists. */ struct param_expr_t : public LineInfo { param_expr_t() : msb_expr(0), lsb_expr(0), val_expr(0), val_scope(0), - solving(false), type(IVL_VT_NO_TYPE), signed_flag(false), + solving(false), is_annotatable(false), + type(IVL_VT_NO_TYPE), signed_flag(false), + local_flag(false), msb(0), lsb(0), range(0), val(0) { } // Source expressions PExpr*msb_expr; @@ -965,9 +1012,12 @@ class NetScope : public Attrib { NetScope*val_scope; // Evaluation status bool solving; + // specparam status + bool is_annotatable; // Type information ivl_variable_type_t type; bool signed_flag; + bool local_flag; NetExpr*msb; NetExpr*lsb; // range constraints @@ -976,21 +1026,11 @@ class NetScope : public Attrib { NetExpr*val; }; mapparameters; - maplocalparams; typedef map::iterator param_ref_t; param_ref_t find_parameter(perm_string name); - struct spec_val_t { - ivl_variable_type_t type; - union { - double real_val; // type == IVL_VT_REAL - long integer; // type == IVL_VT_BOOL - }; - }; - mapspecparams; - /* Module instance arrays are collected here for access during the multiple elaboration passes. */ typedef vector scope_vec_t; @@ -1011,6 +1051,11 @@ class NetScope : public Attrib { TYPE type_; hname_t name_; + // True if the scope is a nested module/program block + bool nested_module_; + // True if the scope is a program block + bool program_block_; + perm_string file_; perm_string def_file_; unsigned lineno_; @@ -1026,7 +1071,10 @@ class NetScope : public Attrib { typedef std::map::const_iterator signals_map_iter_t; std::map signals_map_; perm_string module_name_; - vectorports_; + vector port_nets; + + vector ports_; + union { NetTaskDef*task_; NetFuncDef*func_; @@ -1041,6 +1089,8 @@ class NetScope : public Attrib { std::list enum_sets_; std::map enum_names_; + std::map classes_; + NetScope*up_; map children_; @@ -1301,6 +1351,7 @@ class NetConcat : public NetNode { void dump_node(ostream&, unsigned ind) const; bool emit_node(struct target_t*) const; + void functor_node(Design*des, functor_t*fun); private: unsigned width_; @@ -1697,11 +1748,18 @@ class NetTran : public NetNode, public IslandBranch { class NetExpr : public LineInfo { public: explicit NetExpr(unsigned w =0); + explicit NetExpr(ivl_type_t t); virtual ~NetExpr() =0; virtual void expr_scan(struct expr_scan_t*) const =0; virtual void dump(ostream&) const; + // This is the advanced description of the type. I think I + // want to replace the other type description members with + // this single method. The default for this method returns + // nil. + ivl_type_t net_type() const; + // Expressions have type. virtual ivl_variable_type_t expr_type() const; @@ -1738,6 +1796,14 @@ class NetExpr : public LineInfo { // any. This is a deep copy operation. virtual NetExpr*dup_expr() const =0; + // Evaluate the expression at compile time, a la within a + // constant function. This is used by the constant function + // evaluation function code, and the return value is an + // allocated constant, or nil if the expression cannot be + // evaluated for any reason. + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; + // Get the Nexus that are the input to this // expression. Normally this descends down to the reference to // a signal that reads from its input. @@ -1762,6 +1828,7 @@ class NetExpr : public LineInfo { void cast_signed_base_(bool flag) { signed_flag_ = flag; } private: + ivl_type_t net_type_; unsigned width_; bool signed_flag_; @@ -1799,6 +1866,9 @@ class NetEConst : public NetExpr { virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*); virtual NexusSet* nex_input(bool rem_out = true); + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; + private: verinum value_; }; @@ -1934,12 +2004,13 @@ class NetPartSelect : public NetNode { unsigned base() const; unsigned width() const; - dir_t dir() const; + inline dir_t dir() const { return dir_; } /* Is the select signal signed? */ - bool signed_flag() const { return signed_flag_; } + inline bool signed_flag() const { return signed_flag_; } virtual void dump_node(ostream&, unsigned ind) const; bool emit_node(struct target_t*tgt) const; + virtual void functor_node(Design*des, functor_t*fun); private: unsigned off_; @@ -2026,18 +2097,17 @@ class NetConst : public NetNode { explicit NetConst(NetScope*s, perm_string n, const verinum&val); ~NetConst(); + inline const verinum&value(void) const { return value_; } verinum::V value(unsigned idx) const; - unsigned width() const; - bool is_string() const; + inline unsigned width() const { return value_.len(); } + inline bool is_string() const { return value_.is_string(); } virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*, functor_t*); virtual void dump_node(ostream&, unsigned ind) const; private: - unsigned width_; - verinum::V*value_; - bool is_string_; + verinum value_; }; /* @@ -2267,6 +2337,15 @@ class NetProc : public virtual LineInfo { // target. The target returns true if OK, false for errors. virtual bool emit_proc(struct target_t*) const; + // This method is used by the NetFuncDef object to evaluate a + // constant function at compile time. The loc is the location + // of the function call, and is used for error messages. The + // ctx is a map of name to expression. This is for mapping + // identifiers to values. The function returns true if the + // processing succeeds, or false otherwise. + virtual bool evaluate_function(const LineInfo&loc, + std::map&ctx) const; + // This method is called by functors that want to scan a // process in search of matchable patterns. virtual int match_proc(struct proc_match_t*); @@ -2370,6 +2449,10 @@ class NetAssign_ { // that the expression calculates a CANONICAL bit address. void set_part(NetExpr* loff, unsigned wid, ivl_select_type_t = IVL_SEL_OTHER); + // Set the member or property name if the signal type is a + // class. + void set_property(const perm_string&name); + inline perm_string get_property(void) const { return member_; } // Get the width of the r-value that this node expects. This // method accounts for the presence of the mux, so it is not @@ -2377,6 +2460,11 @@ class NetAssign_ { unsigned lwidth() const; ivl_variable_type_t expr_type() const; + // Get the expression type of the l-value. This may be + // different from the type of the contained signal if for + // example a darray is indexed. + const ivl_type_s* net_type() const; + // Return the enumeration type of this l-value, or nil if it's // not an enumeration. netenum_t*enumeration() const; @@ -2406,6 +2494,8 @@ class NetAssign_ { NetNet *sig_; // Memory word index NetExpr*word_; + // member/property if signal is a class. + perm_string member_; bool turn_sig_to_wire_on_release_; // indexed part select base @@ -2469,6 +2559,7 @@ class NetAssign : public NetAssignBase { virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; + virtual bool evaluate_function(const LineInfo&loc, std::map&context_map) const; private: char op_; @@ -2505,7 +2596,7 @@ class NetAssignNB : public NetAssignBase { class NetBlock : public NetProc { public: - enum Type { SEQU, PARA }; + enum Type { SEQU, PARA, PARA_JOIN_ANY, PARA_JOIN_NONE }; NetBlock(Type t, NetScope*subscope); ~NetBlock(); @@ -2518,6 +2609,8 @@ class NetBlock : public NetProc { const NetProc*proc_first() const; const NetProc*proc_next(const NetProc*cur) const; + bool evaluate_function(const LineInfo&loc, + std::map&ctx) const; // synthesize as asynchronous logic, and return true. bool synth_async(Design*des, NetScope*scope, @@ -2656,6 +2749,8 @@ class NetCondit : public NetProc { virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; + virtual bool evaluate_function(const LineInfo&loc, + map&ctx) const; private: NetExpr* expr_; @@ -3004,7 +3099,7 @@ class NetFree : public NetProc { class NetFuncDef { public: - NetFuncDef(NetScope*, NetNet*result, const svector&po); + NetFuncDef(NetScope*, NetNet*result, const std::vector&po); ~NetFuncDef(); void set_proc(NetProc*st); @@ -3019,13 +3114,19 @@ class NetFuncDef { const NetNet*return_sig() const; + // When we want to evaluate the function during compile time, + // use this method to pass in the argument and get out a + // result. The result should be a constant. If the function + // cannot evaluate to a constant, this returns nil. + NetExpr* evaluate_function(const LineInfo&loc, const std::vector&args) const; + void dump(ostream&, unsigned ind) const; private: NetScope*scope_; NetProc*statement_; NetNet*result_sig_; - svectorports_; + std::vectorports_; }; /* @@ -3118,7 +3219,7 @@ class NetSTask : public NetProc { public: NetSTask(const char*na, ivl_sfunc_as_task_t sfat, - const svector&); + const std::vector&); ~NetSTask(); const char* name() const; @@ -3136,7 +3237,7 @@ class NetSTask : public NetProc { private: const char* name_; ivl_sfunc_as_task_t sfunc_as_task_; - svectorparms_; + std::vectorparms_; }; /* @@ -3187,7 +3288,7 @@ class NetTaskDef { class NetEUFunc : public NetExpr { public: - NetEUFunc(NetScope*, NetScope*, NetESignal*, svector&, bool); + NetEUFunc(NetScope*, NetScope*, NetESignal*, std::vector&, bool); ~NetEUFunc(); const NetESignal*result_sig() const; @@ -3204,13 +3305,16 @@ class NetEUFunc : public NetExpr { virtual NetEUFunc*dup_expr() const; virtual NexusSet* nex_input(bool rem_out = true); virtual NetExpr* eval_tree(); + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; + virtual NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root); private: NetScope*scope_; NetScope*func_; NetESignal*result_sig_; - svector parms_; + std::vector parms_; bool need_const_; private: // not implemented @@ -3287,6 +3391,8 @@ class NetWhile : public NetProc { virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; + virtual bool evaluate_function(const LineInfo&loc, + map&ctx) const; private: NetExpr* cond_; @@ -3444,10 +3550,14 @@ class NetEBAdd : public NetEBinary { virtual NetEBAdd* dup_expr() const; virtual NetExpr* eval_tree(); + virtual NetExpr* evaluate_function(const LineInfo&loc, + std::map&ctx) const; + virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: - NetECReal* eval_tree_real_(); + NetExpr * eval_arguments_(const NetExpr*l, const NetExpr*r) const; + NetECReal* eval_tree_real_(const NetExpr*l, const NetExpr*r) const; }; /* @@ -3523,19 +3633,23 @@ class NetEBComp : public NetEBinary { virtual NetEBComp* dup_expr() const; virtual NetEConst* eval_tree(); + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; + virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: - NetEConst* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag); + NetEConst* must_be_leeq_(const NetExpr*le, const verinum&rv, bool eq_flag) const; - NetEConst*eval_eqeq_(bool ne_flag); - NetEConst*eval_eqeq_real_(bool ne_flag); - NetEConst*eval_less_(); - NetEConst*eval_leeq_(); - NetEConst*eval_leeq_real_(NetExpr*le, NetExpr*ri, bool eq_flag); - NetEConst*eval_gt_(); - NetEConst*eval_gteq_(); - NetEConst*eval_eqeqeq_(bool ne_flag); + NetEConst*eval_arguments_(const NetExpr*le, const NetExpr*re) const; + NetEConst*eval_eqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const; + NetEConst*eval_eqeq_real_(bool ne_flag, const NetExpr*le, const NetExpr*re) const; + NetEConst*eval_less_(const NetExpr*le, const NetExpr*re) const; + NetEConst*eval_leeq_(const NetExpr*le, const NetExpr*re) const; + NetEConst*eval_leeq_real_(const NetExpr*le, const NetExpr*ri, bool eq_flag) const; + NetEConst*eval_gt_(const NetExpr*le, const NetExpr*re) const; + NetEConst*eval_gteq_(const NetExpr*le, const NetExpr*re) const; + NetEConst*eval_eqeqeq_(bool ne_flag, const NetExpr*le, const NetExpr*re) const; }; /* @@ -3590,10 +3704,13 @@ class NetEBMult : public NetEBinary { virtual NetEBMult* dup_expr() const; virtual NetExpr* eval_tree(); + virtual NetExpr* evaluate_function(const LineInfo&loc, + std::map&ctx) const; virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: - NetExpr* eval_tree_real_(); + NetExpr* eval_arguments_(const NetExpr*l, const NetExpr*r) const; + NetExpr* eval_tree_real_(const NetExpr*l, const NetExpr*r) const; }; /* @@ -3637,9 +3754,13 @@ class NetEBShift : public NetEBinary { virtual NetEBShift* dup_expr() const; virtual NetEConst* eval_tree(); + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; + virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: + NetEConst* eval_arguments_(const NetExpr*l, const NetExpr*r) const; }; @@ -3655,16 +3776,17 @@ class NetEBShift : public NetEBinary { class NetEConcat : public NetExpr { public: - NetEConcat(unsigned cnt, unsigned repeat =1); + NetEConcat(unsigned cnt, unsigned repeat, ivl_variable_type_t vt); ~NetEConcat(); // Manipulate the parameters. void set(unsigned idx, NetExpr*e); unsigned repeat() const { return repeat_; } - unsigned nparms() const { return parms_.count() ; } + unsigned nparms() const { return parms_.size() ; } NetExpr* parm(unsigned idx) const { return parms_[idx]; } + virtual ivl_variable_type_t expr_type() const; virtual NexusSet* nex_input(bool rem_out = true); virtual bool has_width() const; virtual NetEConcat* dup_expr() const; @@ -3674,8 +3796,9 @@ class NetEConcat : public NetExpr { virtual void dump(ostream&) const; private: - svectorparms_; + std::vectorparms_; unsigned repeat_; + ivl_variable_type_t expr_type_; }; @@ -3704,10 +3827,16 @@ class NetESelect : public NetExpr { const NetExpr*select() const; ivl_select_type_t select_type() const; + // The type of a NetESelect is the base type of the + // sub-expression. + virtual ivl_variable_type_t expr_type() const; + virtual NexusSet* nex_input(bool rem_out = true); virtual bool has_width() const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEConst* eval_tree(); + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; virtual NetESelect* dup_expr() const; virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root); virtual void dump(ostream&) const; @@ -3762,6 +3891,71 @@ class NetENetenum : public NetExpr { netenum_t*netenum_; }; +class NetENew : public NetExpr { + public: + // Make class object + explicit NetENew(ivl_type_t); + // dynamic array of objects. + explicit NetENew(ivl_type_t, NetExpr*); + ~NetENew(); + + inline ivl_type_t get_type() const { return obj_type_; } + inline const NetExpr*size_expr() const { return size_; } + + virtual ivl_variable_type_t expr_type() const; + + virtual void expr_scan(struct expr_scan_t*) const; + virtual NetENew* dup_expr() const; + virtual NexusSet* nex_input(bool rem_out = true); + + virtual void dump(ostream&os) const; + + private: + ivl_type_t obj_type_; + NetExpr*size_; +}; + +/* + * The NetENull node represents the SystemVerilog (null) + * expression. This is always a null class handle. + */ +class NetENull : public NetExpr { + + public: + NetENull(); + ~NetENull(); + + virtual void expr_scan(struct expr_scan_t*) const; + virtual NetENull* dup_expr() const; + virtual NexusSet* nex_input(bool rem_out = true); + + virtual void dump(ostream&os) const; +}; + +/* + * The NetEProperty represents a SystemVerilog properrty select of a + * class object. In SV, the expression would look like "a.b", where + * the "a" is the signal (the NetNet) and "b" is the property name. + */ +class NetEProperty : public NetExpr { + public: + NetEProperty(NetNet*n, perm_string pname); + ~NetEProperty(); + + inline const NetNet* get_sig() const { return net_; } + inline size_t property_idx() const { return pidx_; } + + virtual void expr_scan(struct expr_scan_t*) const; + virtual NetEProperty* dup_expr() const; + virtual NexusSet* nex_input(bool rem_out = true); + + virtual void dump(ostream&os) const; + + private: + NetNet*net_; + size_t pidx_; +}; + /* * This class is a special (and magical) expression node type that * represents scope names. These can only be found as parameters to @@ -3795,6 +3989,7 @@ class NetESFunc : public NetExpr { public: NetESFunc(const char*name, ivl_variable_type_t t, unsigned width, unsigned nprms); + NetESFunc(const char*name, ivl_type_t rtype, unsigned nprms); NetESFunc(const char*name, netenum_t*enum_type, unsigned nprms); ~NetESFunc(); @@ -3845,6 +4040,9 @@ class NetETernary : public NetExpr { virtual NetETernary* dup_expr() const; virtual NetExpr* eval_tree(); + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; + virtual ivl_variable_type_t expr_type() const; virtual NexusSet* nex_input(bool rem_out = true); virtual void expr_scan(struct expr_scan_t*) const; @@ -3855,6 +4053,8 @@ class NetETernary : public NetExpr { static bool test_operand_compat(ivl_variable_type_t tru, ivl_variable_type_t fal); private: + NetExpr* blended_arguments_(const NetExpr*t, const NetExpr*f) const; + NetExpr*cond_; NetExpr*true_val_; NetExpr*false_val_; @@ -3970,6 +4170,10 @@ class NetESignal : public NetExpr { virtual NetESignal* dup_expr() const; NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root); NexusSet* nex_input(bool rem_out = true); + netenum_t*enumeration() const; + + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; // This is the expression for selecting an array word, if this // signal refers to an array. @@ -3991,6 +4195,7 @@ class NetESignal : public NetExpr { private: NetNet*net_; + netenum_t*enum_type_; // Expression to select a word from the net. NetExpr*word_; }; @@ -4034,7 +4239,7 @@ class Design { const char* get_flag(const string&key) const; - NetScope* make_root_scope(perm_string name); + NetScope* make_root_scope(perm_string name, bool program_block); NetScope* find_root_scope(); list find_root_scopes(); @@ -4056,6 +4261,12 @@ class Design { path is taken as an absolute scope name. Otherwise, the scope is located starting at the passed scope and working up if needed. */ + NetScope* find_scope(const hname_t&path) const; + NetScope* find_scope(NetScope*, const hname_t&name, + NetScope::TYPE type = NetScope::MODULE) const; + // Note: Try to remove these versions of find_scope. Avoid + // using these in new code, use the above forms (or + // symbol_search) instead. NetScope* find_scope(const std::list&path) const; NetScope* find_scope(NetScope*, const std::list&path, NetScope::TYPE type = NetScope::MODULE) const; diff --git a/netlist.txt b/netlist.txt index b92626ca5..2c4dd800a 100644 --- a/netlist.txt +++ b/netlist.txt @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/netmisc.cc b/netmisc.cc index d6b5e6b98..978d0825a 100644 --- a/netmisc.cc +++ b/netmisc.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 @@ -14,13 +14,14 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include # include "netlist.h" +# include "netvector.h" # include "netmisc.h" # include "PExpr.h" # include "pform_types.h" @@ -30,10 +31,11 @@ NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig) { + netvector_t*zero_vec = new netvector_t(sig->data_type(), + sig->vector_width()-1, 0); NetNet*zero_net = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, sig->vector_width()); + NetNet::WIRE, zero_vec); zero_net->set_line(*sig); - zero_net->data_type(sig->data_type()); zero_net->local_flag(true); if (sig->data_type() == IVL_VT_REAL) { @@ -62,10 +64,11 @@ NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig) connect(zero_net->pin(0), adder->pin_DataA()); connect(adder->pin_DataB(), sig->pin(0)); + netvector_t*tmp_vec = new netvector_t(sig->data_type(), + sig->vector_width()-1, 0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, sig->vector_width()); + NetNet::WIRE, tmp_vec); tmp->set_line(*sig); - tmp->data_type(sig->data_type()); tmp->local_flag(true); connect(adder->pin_Result(), tmp->pin(0)); @@ -78,9 +81,9 @@ NetNet* cast_to_int2(Design*des, NetScope*scope, NetNet*src, unsigned wid) if (src->data_type() == IVL_VT_BOOL) return src; - NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid); + netvector_t*tmp_vec = new netvector_t(IVL_VT_BOOL, wid-1, 0); + NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, tmp_vec); tmp->set_line(*src); - tmp->data_type(IVL_VT_BOOL); tmp->local_flag(true); NetCastInt2*cast = new NetCastInt2(scope, scope->local_symbol(), wid); @@ -98,9 +101,9 @@ NetNet* cast_to_int4(Design*des, NetScope*scope, NetNet*src, unsigned wid) if (src->data_type() != IVL_VT_REAL) return src; - NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid); + netvector_t*tmp_vec = new netvector_t(IVL_VT_LOGIC, wid-1, 0); + NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, tmp_vec); tmp->set_line(*src); - tmp->data_type(IVL_VT_LOGIC); tmp->local_flag(true); NetCastInt4*cast = new NetCastInt4(scope, scope->local_symbol(), wid); @@ -118,9 +121,9 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src) if (src->data_type() == IVL_VT_REAL) return src; - NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE); + netvector_t*tmp_vec = new netvector_t(IVL_VT_REAL); + NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, tmp_vec); tmp->set_line(*src); - tmp->data_type(IVL_VT_REAL); tmp->local_flag(true); NetCastReal*cast = new NetCastReal(scope, scope->local_symbol(), src->get_signed()); @@ -149,6 +152,16 @@ NetExpr* cast_to_int2(NetExpr*expr) return cast; } +NetExpr* cast_to_real(NetExpr*expr) +{ + if (expr->expr_type() == IVL_VT_REAL) + return expr; + + NetECast*cast = new NetECast('r', expr, 1, true); + cast->set_line(*expr); + return cast; +} + /* * Add a signed constant to an existing expression. Generate a new * NetEBAdd node that has the input expression and an expression made @@ -180,6 +193,21 @@ static NetExpr* make_add_expr(NetExpr*expr, long val) return res; } +static NetExpr* make_add_expr(const LineInfo*loc, NetExpr*expr1, NetExpr*expr2) +{ + bool use_signed = expr1->has_sign() && expr2->has_sign(); + unsigned use_wid = expr1->expr_width(); + + if (expr2->expr_width() > use_wid) + use_wid = expr2->expr_width(); + + expr1 = pad_to_width(expr1, use_wid, *loc); + expr2 = pad_to_width(expr2, use_wid, *loc); + + NetEBAdd*tmp = new NetEBAdd('+', expr1, expr2, use_wid, use_signed); + return tmp; +} + /* * Subtract an existing expression from a signed constant. */ @@ -254,6 +282,8 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, if (is_up) offset -= wid - 1; /* Calculate the space needed for the offset. */ unsigned min_wid = num_bits(offset); + if (num_bits(soff) > min_wid) + min_wid = num_bits(soff); /* We need enough space for the larger of the offset or the * base expression. */ if (min_wid < base->expr_width()) min_wid = base->expr_width(); @@ -287,6 +317,8 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, if ((soff-offset) == 0) return base; /* Calculate the space needed for the offset. */ unsigned min_wid = num_bits(-offset); + if (num_bits(soff) > min_wid) + min_wid = num_bits(soff); /* We need enough space for the larger of the offset or the * base expression. */ if (min_wid < base->expr_width()) min_wid = base->expr_width(); @@ -320,61 +352,61 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, * vector. For now, we assert that there is only one set of dimensions. */ NetExpr *normalize_variable_base(NetExpr *base, - const list&dims, + 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); + const netrange_t&rng = dims.back(); + return normalize_variable_base(base, rng.get_msb(), rng.get_lsb(), wid, is_up); } NetExpr *normalize_variable_bit_base(const list&indices, NetExpr*base, const NetNet*reg) { - const list&packed_dims = reg->packed_dims(); + const vector&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); + const netrange_t&rng = packed_dims.back(); + long slice_off = reg->sb_to_idx(indices, rng.get_lsb()); - return normalize_variable_base(base, rng.msb, rng.lsb, 1, true, slice_off); + return normalize_variable_base(base, rng.get_msb(), rng.get_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(); + const vector&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); + const netrange_t&rng = packed_dims.back(); + long slice_off = reg->sb_to_idx(indices, rng.get_lsb()); - return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up, slice_off); + return normalize_variable_base(base, rng.get_msb(), rng.get_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(); + const vector&packed_dims = reg->packed_dims(); ivl_assert(*base, indices.size() < packed_dims.size()); - list::const_iterator pcur = packed_dims.end(); + vector::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; + if (pcur->get_msb() >= pcur->get_lsb()) + sb = pcur->get_lsb(); else - sb = pcur->msb; + sb = pcur->get_msb(); long loff; reg->sb_to_slice(indices, sb, loff, lwid); @@ -384,51 +416,213 @@ NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, return base; } -/* - * This routine generates the normalization expression needed for a variable - * array word select. - */ -NetExpr *normalize_variable_array_base(NetExpr *base, long offset, - unsigned count) +ostream& operator << (ostream&o, __IndicesManip val) { - assert(offset != 0); - /* 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 base - * expression. */ - if (min_wid < base->expr_width()) min_wid = base->expr_width(); - /* Now that we have the minimum needed width increase it by one - * to make room for the normalization calculation. */ - min_wid += 1; - /* Pad the base expression to the correct width. */ - base = pad_to_width(base, min_wid, *base); - /* If the offset is greater than zero then we need to do signed - * math to get the location value correct. */ - if (offset > 0 && ! base->has_sign()) { - /* We need this extra select to hide the signed property - * from the padding above. It will be removed automatically - * during code generation. */ - NetESelect *tmp = new NetESelect(base, 0 , min_wid); - tmp->set_line(*base); - tmp->cast_signed(true); - base = tmp; + for (list::const_iterator cur = val.val.begin() + ; cur != val.val.end() ; ++cur) { + o << "[" << *cur << "]"; } - /* Normalize the expression. */ - base = make_add_expr(base, -offset); + return o; +} - /* We should not need to do this, but .array/port does not - * handle a small signed index correctly and it is a major - * effort to fix it. For now we will just pad the expression - * enough so that any negative value when converted to - * unsigned is larger than the maximum array word. */ - if (base->has_sign()) { - unsigned range_wid = num_bits(count-1) + 1; - if (min_wid < range_wid) { - base = pad_to_width(base, range_wid, *base); +ostream& operator << (ostream&o, __IndicesManip val) +{ + for (list::const_iterator cur = val.val.begin() + ; cur != val.val.end() ; ++cur) { + o << "[" << *(*cur) << "]"; + } + return o; +} + +/* + * The src is the input index expression list from the expression, and + * the count is the number that are to be elaborated into the indices + * list. At the same time, create a indices_const list that contains + * the evaluated values for the expression, if they can be + * evaluated. This function will return "true" if all the constants + * can be evaluated. + */ +bool indices_to_expressions(Design*des, NetScope*scope, + // loc is for error messages. + const LineInfo*loc, + // src is the index list, and count is + // the number of items in the list to use. + const list&src, unsigned count, + // True if the expression MUST be constant. + bool need_const, + // These are the outputs. + list&indices, list&indices_const) +{ + ivl_assert(*loc, count <= src.size()); + + bool flag = true; + for (list::const_iterator cur = src.begin() + ; count > 0 ; ++cur, --count) { + ivl_assert(*loc, cur->sel != index_component_t::SEL_NONE); + + if (cur->sel != index_component_t::SEL_BIT) { + cerr << loc->get_fileline() << ": error: " + << "Array cannot be indexed by a range." << endl; + des->errors += 1; + } + ivl_assert(*loc, cur->msb); + + NetExpr*word_index = elab_and_eval(des, scope, cur->msb, -1, need_const); + + // If the elaboration failed, then it is most certainly + // not constant, either. + if (word_index == 0) + flag = false; + + // Track if we detect any non-constant expressions + // here. This may allow for a special case. + if (flag) { + NetEConst*word_const = dynamic_cast (word_index); + if (word_const) + indices_const.push_back(word_const->value().as_long()); + else + flag = false; + } + + indices.push_back(word_index); + } + + return flag; +} + +static void make_strides(const vector&dims, + vector&stride) +{ + stride[dims.size()-1] = 1; + for (size_t idx = stride.size()-1 ; idx > 0 ; --idx) { + long tmp = dims[idx].width(); + if (idx < stride.size()) + tmp *= stride[idx]; + stride[idx-1] = tmp; + } +} + +/* + * Take in a vector of constant indices and convert them to a single + * number that is the canonical address (zero based, 1-d) of the + * word. If any of the indices are out of bounds, return nil instead + * of an expression. + */ +NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +{ + const vector&dims = net->unpacked_dims(); + + // Make strides for each index. The stride is the distance (in + // words) to the next element in the canonical array. + vector stride (dims.size()); + make_strides(dims, stride); + + int64_t canonical_addr = 0; + + int idx = 0; + for (list::const_iterator cur = indices.begin() + ; cur != indices.end() ; ++cur, ++idx) { + long tmp = *cur; + + if (dims[idx].get_lsb() <= dims[idx].get_msb()) + tmp -= dims[idx].get_lsb(); + else + tmp -= dims[idx].get_msb(); + + // Notice of this index is out of range. + if (tmp < 0 || tmp >= (long)dims[idx].width()) { + return 0; + } + + canonical_addr += tmp * stride[idx]; + } + + NetEConst*canonical_expr = new NetEConst(verinum(canonical_addr)); + return canonical_expr; +} + +NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +{ + const vector&dims = net->unpacked_dims(); + + // Make strides for each index. The stride is the distance (in + // words) to the next element in the canonical array. + vector stride (dims.size()); + make_strides(dims, stride); + + NetExpr*canonical_expr = 0; + + int idx = 0; + for (list::const_iterator cur = indices.begin() + ; cur != indices.end() ; ++cur, ++idx) { + NetExpr*tmp = *cur; + // If the expression elaboration generated errors, then + // give up. Presumably, the error during expression + // elaboration already generated the error message. + if (tmp == 0) + return 0; + + int64_t use_base; + if (! dims[idx].defined()) + use_base = 0; + else if (dims[idx].get_lsb() <= dims[idx].get_msb()) + use_base = dims[idx].get_lsb(); + else + use_base = dims[idx].get_msb(); + + int64_t use_stride = stride[idx]; + + // Account for that we are doing arithmetic and should + // have a proper width to make sure there are no + // losses. So calculate a min_wid width. + unsigned tmp_wid; + unsigned min_wid = tmp->expr_width(); + if (use_stride != 1 && ((tmp_wid = num_bits(use_stride)) >= min_wid)) + min_wid = tmp_wid + 1; + if (use_base != 0 && ((tmp_wid = num_bits(use_base)) >= min_wid)) + min_wid = tmp_wid + 1; + if ((tmp_wid = num_bits(dims[idx].width()+1)) >= min_wid) + min_wid = tmp_wid + 1; + + tmp = pad_to_width(tmp, min_wid, *net); + + // Now generate the math to calculate the canonical address. + NetExpr*tmp_scaled = 0; + if (NetEConst*tmp_const = dynamic_cast (tmp)) { + // Special case: the index is constant, so this + // iteration can be replaced with a constant + // expression. + int64_t val = tmp_const->value().as_long(); + val -= use_base; + val *= use_stride; + // Very special case: the index is zero, so we can + // skip this iteration + if (val == 0) + continue; + tmp_scaled = new NetEConst(verinum(val)); + + } else { + tmp_scaled = tmp; + if (use_base != 0) + tmp_scaled = make_add_expr(tmp_scaled, -use_base); + if (use_stride != 1) + tmp_scaled = make_mult_expr(tmp_scaled, use_stride); + } + + if (canonical_expr == 0) { + canonical_expr = tmp_scaled; + } else { + canonical_expr = new NetEBAdd('+', canonical_expr, tmp_scaled, + canonical_expr->expr_width()+1, false); } } - return base; + // If we don't have an expression at this point, all the indices were + // constant zero. But this variant of normalize_variable_unpacked() + // is only used when at least one index is not a constant. + ivl_assert(*net, canonical_expr); + + return canonical_expr; } NetEConst* make_const_x(unsigned long wid) @@ -458,9 +652,23 @@ NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid) NetConst*res = new NetConst(scope, scope->local_symbol(), xxx); des->add_node(res); - NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid); + netvector_t*sig_vec = new netvector_t(IVL_VT_LOGIC, wid-1, 0); + NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, sig_vec); + sig->local_flag(true); + + connect(sig->pin(0), res->pin(0)); + return sig; +} + +NetNet* make_const_z(Design*des, NetScope*scope, unsigned long wid) +{ + verinum xxx (verinum::Vz, wid); + NetConst*res = new NetConst(scope, scope->local_symbol(), xxx); + des->add_node(res); + + netvector_t*sig_vec = new netvector_t(IVL_VT_LOGIC, wid-1, 0); + NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, sig_vec); sig->local_flag(true); - sig->data_type(IVL_VT_LOGIC); connect(sig->pin(0), res->pin(0)); return sig; @@ -519,7 +727,7 @@ static const char*width_mode_name(PExpr::width_mode_t mode) } NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, - int context_width, bool need_const) + int context_width, bool need_const, bool annotatable) { PExpr::width_mode_t mode = PExpr::SIZED; if ((context_width == -2) && !gn_strict_expr_width_flag) @@ -562,6 +770,8 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, unsigned flags = PExpr::NO_FLAGS; if (need_const) flags |= PExpr::NEED_CONST; + if (annotatable) + flags |= PExpr::ANNOTATABLE; NetExpr*tmp = pe->elaborate_expr(des, scope, expr_width, flags); if (tmp == 0) return 0; @@ -680,7 +890,8 @@ bool eval_as_double(double&value, NetExpr*expr) * expression if it is present. */ hname_t eval_path_component(Design*des, NetScope*scope, - const name_component_t&comp) + const name_component_t&comp, + bool&error_flag) { // No index expression, so the path component is an undecorated // name, for example "foo". @@ -718,6 +929,7 @@ hname_t eval_path_component(Design*des, NetScope*scope, return res; } +#if 1 // Darn, the expression doesn't evaluate to a constant. That's // an error to be reported. And make up a fake index value to // return to the caller. @@ -725,6 +937,8 @@ hname_t eval_path_component(Design*des, NetScope*scope, << "Scope index expression is not constant: " << *index.msb << endl; des->errors += 1; +#endif + error_flag = true; delete tmp; return hname_t (comp.name, 0); @@ -733,15 +947,20 @@ hname_t eval_path_component(Design*des, NetScope*scope, std::list eval_scope_path(Design*des, NetScope*scope, const pform_name_t&path) { + bool path_error_flag = false; list res; typedef pform_name_t::const_iterator pform_path_it; for (pform_path_it cur = path.begin() ; cur != path.end(); ++ cur ) { const name_component_t&comp = *cur; - res.push_back( eval_path_component(des,scope,comp) ); + res.push_back( eval_path_component(des,scope,comp,path_error_flag) ); } - +#if 0 + if (path_error_flag) { + cerr << "XXXXX: Errors evaluating path " << path << endl; + } +#endif return res; } @@ -972,3 +1191,85 @@ bool evaluate_index_prefix(Design*des, NetScope*scope, return true; } + +/* + * Evaluate the indices. The chain of indices are applied to the + * packed indices of a NetNet to generate a canonical expression to + * replace the exprs. + */ +NetExpr*collapse_array_exprs(Design*des, NetScope*scope, + const LineInfo*loc, NetNet*net, + const list&indices) +{ + // First elaborate all the expressions as far as possible. + list exprs; + list exprs_const; + indices_to_expressions(des, scope, loc, indices, + net->packed_dimensions(), + false, exprs, exprs_const); + ivl_assert(*loc, exprs.size() == net->packed_dimensions()); + + // Special Case: there is only 1 packed dimension, so the + // single expression should already be naturally canonical. + if (net->slice_width(1) == 1) { + return *exprs.begin(); + } + + const std::vector&pdims = net->packed_dims(); + std::vector::const_iterator pcur = pdims.begin(); + + list::iterator ecur = exprs.begin(); + NetExpr* base = 0; + for (size_t idx = 0 ; idx < net->packed_dimensions() ; idx += 1, ++pcur, ++ecur) { + unsigned cur_slice_width = net->slice_width(idx+1); + // This normalizes the expression of this index based on + // the msb/lsb values. + NetExpr*tmp = normalize_variable_base(*ecur, pcur->get_msb(), + pcur->get_lsb(), + cur_slice_width, true); + + // If this slice has width, then scale it. + if (net->slice_width(idx+1) != 1) { + unsigned min_wid = tmp->expr_width(); + if (num_bits(cur_slice_width) >= min_wid) { + min_wid = num_bits(cur_slice_width)+1; + tmp = pad_to_width(tmp, min_wid, *loc); + } + + tmp = make_mult_expr(tmp, cur_slice_width); + } + + // Now add it to the position we've accumulated so far. + if (base) { + base = make_add_expr(loc, base, tmp); + } else { + base = tmp; + } + } + + return base; +} + +/* + * Given a list of indices, treat them as packed indices and convert + * them to an expression that normalizes the list to a single index + * expression over a canonical equivilent 1-dimensional array. + */ +NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net, + const list&indices) +{ + listprefix_indices; + bool rc = evaluate_index_prefix(des, scope, prefix_indices, indices); + assert(rc); + + const index_component_t&back_index = indices.back(); + assert(back_index.sel == index_component_t::SEL_BIT); + assert(back_index.msb && !back_index.lsb); + + NetExpr*base = elab_and_eval(des, scope, back_index.msb, -1, true); + + NetExpr*res = normalize_variable_bit_base(prefix_indices, base, net); + + eval_expr(res, -1); + return res; +} diff --git a/netmisc.h b/netmisc.h index 7f34131fa..f095e1b05 100644 --- a/netmisc.h +++ b/netmisc.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "netlist.h" @@ -79,6 +79,7 @@ extern NetNet*cast_to_int2(Design*des, NetScope*scope, NetNet*src, unsigned wid) extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src); extern NetExpr*cast_to_int2(NetExpr*expr); +extern NetExpr*cast_to_real(NetExpr*expr); /* * Take the input expression and return a variation that assures that @@ -94,6 +95,10 @@ extern NetExpr*condition_reduce(NetExpr*expr); */ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w); +extern bool calculate_part(const LineInfo*li, Design*des, NetScope*scope, + const index_component_t&index, + long&off, unsigned long&wid); + /* * These functions generate an equation to normalize an expression using * the provided vector/array information. @@ -102,7 +107,7 @@ extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb, unsigned long wid, bool is_up, long slice_off =0); extern NetExpr*normalize_variable_base(NetExpr *base, - const list&dims, + const list&dims, unsigned long wid, bool is_up); /* @@ -142,8 +147,37 @@ extern NetExpr *normalize_variable_part_base(const list&indices, NetExpr*b 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); +/* + * The as_indices() manipulator is a convenient way to emit a list of + * index values in the form [<>][<>].... + */ +template struct __IndicesManip { + inline __IndicesManip(const std::list&v) : val(v) { } + const std::list&val; +}; +template inline __IndicesManip as_indices(const std::list&indices) +{ return __IndicesManip(indices); } + +extern ostream& operator << (ostream&o, __IndicesManip); +extern ostream& operator << (ostream&o, __IndicesManip); + +/* + * Given a list of index expressions, generate elaborated expressions + * and constant values, if possible. + */ +extern bool indices_to_expressions(Design*des, NetScope*scope, + // loc is for error messages. + const LineInfo*loc, + // src is the index list, and count is + // the number of items in the list to use. + const list&src, unsigned count, + // True if the expression MUST be constant. + bool need_const, + // These are the outputs. + list&indices, list&indices_const); + +extern NetExpr*normalize_variable_unpacked(const NetNet*net, list&indices); +extern NetExpr*normalize_variable_unpacked(const NetNet*net, list&indices); /* * This function takes as input a NetNet signal and adds a constant @@ -168,6 +202,7 @@ extern NetEConst*make_const_val(unsigned long val); * Make A const net */ extern NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid); +extern NetNet* make_const_z(Design*des, NetScope*scope, unsigned long wid); /* * In some cases the lval is accessible as a pointer to the head of @@ -192,7 +227,8 @@ class PExpr; extern NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width, - bool need_const =false); + bool need_const =false, + bool annotatable =false); /* * This function is a variant of elab_and_eval that elaborates and @@ -226,18 +262,14 @@ void eval_expr(NetExpr*&expr, int context_width =-1); bool eval_as_long(long&value, NetExpr*expr); bool eval_as_double(double&value, NetExpr*expr); -/* - * Evaluate the component of a scope path to get an hname_t value. Do - * the evaluation in the context of the given scope. - */ -extern hname_t eval_path_component(Design*des, NetScope*scope, - const name_component_t&comp); - /* * Evaluate an entire scope path in the context of the given scope. */ extern std::list eval_scope_path(Design*des, NetScope*scope, const pform_name_t&path); +extern hname_t eval_path_component(Design*des, NetScope*scope, + const name_component_t&comp, + bool&error_flag); /* * Return true if the data type is a type that is normally available @@ -280,4 +312,12 @@ 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); + +extern NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net, + const std::list&indices); + +extern NetExpr*collapse_array_exprs(Design*des, NetScope*scope, + const LineInfo*loc, NetNet*net, + const list&indices); + #endif diff --git a/netparray.cc b/netparray.cc new file mode 100644 index 000000000..d8779a92d --- /dev/null +++ b/netparray.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012 Picture Elements, Inc. + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "netparray.h" + +using namespace std; + +netparray_t::~netparray_t() +{ +} + +/* + * The packed width of a packed array is the packed width of the + * element times the dimension width of the array itself. + */ +long netparray_t::packed_width(void) const +{ + long cur_width = element_type()->packed_width(); + + for (vector::const_iterator cur = packed_dims_.begin() + ; cur != packed_dims_.end() ; ++cur) { + cur_width *= cur->width(); + } + + return cur_width; +} + +vector netparray_t::slice_dimensions() const +{ + vector elem_dims = element_type()->slice_dimensions(); + + vector res (packed_dims_.size() + elem_dims.size()); + + for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1) + res[idx] = packed_dims_[0]; + for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1) + res[idx+packed_dims_.size()] = elem_dims[idx]; + + return res; +} diff --git a/netparray.h b/netparray.h new file mode 100644 index 000000000..4850059b5 --- /dev/null +++ b/netparray.h @@ -0,0 +1,56 @@ +#ifndef __netarray_H +#define __netarray_H +/* + * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 "nettypes.h" +# include + +/* + * Packed arrays. + */ +class netparray_t : public netarray_t { + + public: + explicit netparray_t(const std::vector&packed, + ivl_type_t etype); + ~netparray_t(); + + public: + // Virtual methods from the ivl_type_s type... + long packed_width(void) const; + std::vector slice_dimensions() const; + + public: + inline const std::vector& packed_dimensions() const + { return packed_dims_; } + + private: + std::vector packed_dims_; + +}; + +inline netparray_t::netparray_t(const std::vector&packed, + ivl_type_t etype) +: netarray_t(etype), packed_dims_(packed) +{ +} + +#endif diff --git a/netstruct.cc b/netstruct.cc index 63b673bae..b4c372599 100644 --- a/netstruct.cc +++ b/netstruct.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "netstruct.h" @@ -66,3 +66,23 @@ long netstruct_t::packed_width(void) const return res; } + +vector netstruct_t::slice_dimensions() const +{ + vector tmp; + tmp .push_back(netrange_t(packed_width()-1, 0)); + return tmp; +} + +ivl_variable_type_t netstruct_t::base_type() const +{ + if (! packed_) + return IVL_VT_NO_TYPE; + + for (size_t idx = 0 ; idx < members_.size() ; idx += 1) { + if (members_[idx].data_type() != IVL_VT_BOOL) + return members_[idx].data_type(); + } + + return IVL_VT_BOOL; +} diff --git a/netstruct.h b/netstruct.h index b84df6a4a..9d971961e 100644 --- a/netstruct.h +++ b/netstruct.h @@ -16,21 +16,21 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "LineInfo.h" -# include +# include # include "ivl_target.h" +# include "nettypes.h" -class netstruct_t : public LineInfo { +class netstruct_t : public LineInfo, public ivl_type_s { public: struct member_t { perm_string name; ivl_variable_type_t type; - long msb; - long lsb; + std::vector packed_dims; long width() const; ivl_variable_type_t data_type() const { return type; }; // We need to keep the individual element sign information. @@ -54,6 +54,11 @@ class netstruct_t : public LineInfo { // Return the width (in bits) of the packed record, or -1 if // the record is not packed. long packed_width() const; + std::vector slice_dimensions() const; + + // Return the base type of the packed record, or + // IVL_VT_NO_TYPE if the record is not packed. + ivl_variable_type_t base_type() const; private: bool packed_; @@ -63,11 +68,6 @@ class netstruct_t : public LineInfo { 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; -} +{ return netrange_width(packed_dims); } #endif diff --git a/nettypes.cc b/nettypes.cc new file mode 100644 index 000000000..6b5797146 --- /dev/null +++ b/nettypes.cc @@ -0,0 +1,125 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "nettypes.h" +# include + +using namespace std; + +ivl_type_s::~ivl_type_s() +{ +} + +long ivl_type_s::packed_width(void) const +{ + return 1; +} + +vector ivl_type_s::slice_dimensions() const +{ + return vector(); +} + +ivl_variable_type_t ivl_type_s::base_type() const +{ + return IVL_VT_NO_TYPE; +} + +bool ivl_type_s::get_signed() const +{ + return false; +} + +netarray_t::~netarray_t() +{ +} + +ivl_variable_type_t netarray_t::base_type() const +{ + return element_type_->base_type(); +} + +unsigned long netrange_width(const vector&packed) +{ + unsigned wid = 1; + for (vector::const_iterator cur = packed.begin() + ; cur != packed.end() ; ++cur) { + unsigned use_wid = cur->width(); + wid *= use_wid; + } + + return wid; +} + +/* + * Given a netrange_t list (which represent packed dimensions) and a + * prefix of calculated index values, calculate the canonical offset + * and width of the resulting slice. In this case, the "sb" argument + * is an extra index of the prefix. + */ +bool prefix_to_slice(const std::vector&dims, + const std::list&prefix, long sb, + long&loff, unsigned long&lwid) +{ + assert(prefix.size() < dims.size()); + + size_t acc_wid = 1; + vector::const_iterator pcur = dims.end(); + for (size_t idx = prefix.size()+1 ; idx < dims.size() ; idx += 1) { + -- pcur; + acc_wid *= pcur->width(); + } + + lwid = acc_wid; + + -- pcur; + if (sb < pcur->get_msb() && sb < pcur->get_lsb()) + return false; + if (sb > pcur->get_msb() && sb > pcur->get_lsb()) + return false; + + long acc_off = 0; + if (pcur->get_msb() >= pcur->get_lsb()) + acc_off += (sb - pcur->get_lsb()) * acc_wid; + else + acc_off += (sb - pcur->get_msb()) * acc_wid; + + if (prefix.empty()) { + loff = acc_off; + return true; + } + + lwid *= pcur->width(); + + list::const_iterator icur = prefix.end(); + do { + -- pcur; + -- icur; + acc_wid *= pcur->width(); + if (pcur->get_msb() >= pcur->get_lsb()) + acc_off += (*icur - pcur->get_lsb()) * acc_wid; + else + acc_off += (*icur - pcur->get_msb()) * acc_wid; + + } while (icur != prefix.begin()); + + loff = acc_off; + + return true; +} diff --git a/nettypes.h b/nettypes.h new file mode 100644 index 000000000..df7779edb --- /dev/null +++ b/nettypes.h @@ -0,0 +1,120 @@ +#ifndef __nettypes_H +#define __nettypes_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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "ivl_target.h" +# include +# include +# include +# include +# include + +class netrange_t; + +/* + * This is a fully abstract type that is a type that can be attached + * to a NetNet object. + */ +class ivl_type_s { + public: + virtual ~ivl_type_s() =0; + virtual long packed_width(void) const; + virtual std::vector slice_dimensions() const; + + // Some types have a base variable type. + virtual ivl_variable_type_t base_type() const; + virtual bool get_signed() const; + + virtual std::ostream& debug_dump(std::ostream&) const; +}; + +/* + * There are a couple types of array types. This class represents the + * common bits of array types. + */ +class netarray_t : public ivl_type_s { + + public: + inline explicit netarray_t(ivl_type_t etype) : element_type_(etype) { } + ~netarray_t(); + + public: + // Some virtual methods have a common implementation for arrays. + ivl_variable_type_t base_type() const; + + public: + inline ivl_type_t element_type() const { return element_type_; } + + private: + ivl_type_t element_type_; +}; + +inline static std::ostream& operator << (std::ostream&out, const ivl_type_s&obj) +{ + return obj.debug_dump(out); +} + +class netrange_t { + + public: + // Create an undefined range. An undefined range is a range + // used to declare dynamic arrays, etc. + inline netrange_t() : msb_(LONG_MAX), lsb_(LONG_MAX) { } + // Create a properly defined netrange + inline netrange_t(long m, long l) : msb_(m), lsb_(l) { } + // Copy constructure. + inline netrange_t(const netrange_t&that) + : msb_(that.msb_), lsb_(that.lsb_) { } + + inline netrange_t& operator = (const netrange_t&that) + { msb_ = that.msb_; lsb_ = that.lsb_; return *this; } + + inline bool defined() const + { return msb_!=LONG_MAX || lsb_!= LONG_MAX; } + + inline unsigned long width()const + { if (!defined()) return 0; + else if (msb_ >= lsb_) return msb_-lsb_+1; + else return lsb_-msb_+1; + } + + inline long get_msb() const { assert(defined()); return msb_; } + inline long get_lsb() const { assert(defined()); return lsb_; } + + private: + long msb_; + long lsb_; +}; + +extern std::ostream&operator << (std::ostream&out, const std::list&rlist); +extern std::ostream&operator << (std::ostream&out, const std::vector&rlist); + +extern unsigned long netrange_width(const std::vector&dims); + +/* + * Take as input a list of packed dimensions and a list of prefix + * indices, and calculate the offset/width of the resulting slice into + * the packed array. + */ +extern bool prefix_to_slice(const std::vector&dims, + const std::list&prefix, long sb, + long&loff, unsigned long&lwid); + +#endif diff --git a/netvector.cc b/netvector.cc new file mode 100644 index 000000000..08c0239e8 --- /dev/null +++ b/netvector.cc @@ -0,0 +1,59 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "netvector.h" + +using namespace std; + +netvector_t netvector_t::atom2s32 (IVL_VT_BOOL, 31, 0, true); +netvector_t netvector_t::atom2u32 (IVL_VT_BOOL, 31, 0, false); +netvector_t netvector_t::atom2s16 (IVL_VT_BOOL, 16, 0, true); +netvector_t netvector_t::atom2u16 (IVL_VT_BOOL, 16, 0, false); +netvector_t netvector_t::atom2s8 (IVL_VT_BOOL, 8, 0, true); +netvector_t netvector_t::atom2u8 (IVL_VT_BOOL, 8, 0, false); + +netvector_t::netvector_t(ivl_variable_type_t type, long msb, long lsb, bool flag) +: type_(type), signed_(flag) +{ + packed_dims_.push_back(netrange_t(msb,lsb)); +} + +netvector_t::netvector_t(ivl_variable_type_t type) +: type_(type), signed_(false), isint_(false), is_scalar_(false) +{ +} + +netvector_t::~netvector_t() +{ +} + +ivl_variable_type_t netvector_t::base_type() const +{ + return type_; +} + +long netvector_t::packed_width() const +{ + return netrange_width(packed_dims_); +} + +vector netvector_t::slice_dimensions() const +{ + return packed_dims_; +} diff --git a/netvector.h b/netvector.h new file mode 100644 index 000000000..3add278fb --- /dev/null +++ b/netvector.h @@ -0,0 +1,102 @@ +#ifndef __netvector_H +#define __netvector_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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "nettypes.h" +# include "ivl_target.h" +# include + +class netvector_t : public ivl_type_s { + + public: + explicit netvector_t(const std::vector&packed, + ivl_variable_type_t type); + + // This is a variant of the vector form. Some code processes + // the list of packed ranges as a list, but we will store them + // as a vector in this constructor. + explicit netvector_t(const std::list&packed, + ivl_variable_type_t type); + + // special case: there is a single packed dimension and we + // know it in the form [:]. This step saves me + // creating a netrange_t for this single item. + explicit netvector_t(ivl_variable_type_t type, long msb, long lsb, + bool signed_flag =false); + + // Special case: scaler object--no packed dimenions at all. + explicit netvector_t(ivl_variable_type_t type); + + ~netvector_t(); + + // Vectors can be interpreted as signed or unsigned when + // handled as vectors. + inline void set_signed(bool flag) { signed_ = flag; } + inline bool get_signed(void) const { return signed_; } + + inline void set_isint(bool flag) { isint_ = flag; } + inline bool get_isint(void) const { return isint_; } + + inline void set_scalar(bool flag) { is_scalar_ = flag; } + inline bool get_scalar(void) const { return is_scalar_; } + + ivl_variable_type_t base_type() const; + const std::vector&packed_dims() const; + + long packed_width() const; + std::vector slice_dimensions() const; + + std::ostream& debug_dump(std::ostream&) const; + + public: + // Some commonly used predefined types + static netvector_t atom2s32; + static netvector_t atom2u32; + static netvector_t atom2s16; + static netvector_t atom2u16; + static netvector_t atom2s8; + static netvector_t atom2u8; + + private: + std::vector packed_dims_; + ivl_variable_type_t type_; + bool signed_ : 1; + bool isint_ : 1; // original type of integer + bool is_scalar_ : 1; +}; + +inline netvector_t::netvector_t(const std::vector&packed, + ivl_variable_type_t type) +: packed_dims_(packed), type_(type), signed_(false), isint_(false), + is_scalar_(false) +{ +} + +inline const std::vector& netvector_t::packed_dims() const +{ + return packed_dims_; +} + +inline static std::ostream& operator << (std::ostream&out, const netvector_t&obj) +{ + return obj.debug_dump(out); +} + +#endif diff --git a/nodangle.cc b/nodangle.cc index 6e01d4aba..19336fc23 100644 --- a/nodangle.cc +++ b/nodangle.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/pad_to_width.cc b/pad_to_width.cc index 2aaef768d..32ba6c61d 100644 --- a/pad_to_width.cc +++ b/pad_to_width.cc @@ -14,12 +14,13 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include "netlist.h" +# include "netvector.h" # include "netmisc.h" @@ -77,19 +78,20 @@ NetNet*pad_to_width(Design*des, NetNet*net, unsigned wid, const LineInfo&info) connect(cc->pin(2), con->pin(0)); // Make a NetNet for the NetConst to NetConcat link. + netvector_t*tmp_vec = new netvector_t(net->data_type(), + wid - net->vector_width() - 1, 0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, wid - net->vector_width()); + NetNet::WIRE, tmp_vec); tmp->set_line(info); - tmp->data_type( net->data_type() ); tmp->local_flag(true); connect(cc->pin(2), tmp->pin(0)); // Create a NetNet of the output width and connect it to the // NetConcat node output pin. + tmp_vec = new netvector_t(net->data_type(), wid-1, 0); tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, wid); + NetNet::WIRE, tmp_vec); tmp->set_line(info); - tmp->data_type( net->data_type() ); tmp->local_flag(true); connect(cc->pin(0), tmp->pin(0)); @@ -109,11 +111,11 @@ NetNet*pad_to_width_signed(Design*des, NetNet*net, unsigned wid, se->set_line(info); des->add_node(se); - NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid); + netvector_t*tmp_vec = new netvector_t(net->data_type(), wid-1, 0); + tmp_vec->set_signed(true); + NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, tmp_vec); tmp->set_line(info); tmp->local_flag(true); - tmp->data_type(net->data_type()); - tmp->set_signed(true); connect(tmp->pin(0), se->pin(0)); connect(se->pin(1), net->pin(0)); @@ -132,10 +134,10 @@ NetNet*crop_to_width(Design*des, NetNet*net, unsigned wid) ps->set_line(*net); des->add_node(ps); + netvector_t*tmp_vec = new netvector_t(net->data_type(), wid-1, 0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, wid); + NetNet::WIRE, tmp_vec); tmp->set_line(*net); - tmp->data_type(net->data_type()); tmp->local_flag(true); connect(ps->pin(0), tmp->pin(0)); diff --git a/parse.y b/parse.y index 5d67e237b..9403c3338 100644 --- a/parse.y +++ b/parse.y @@ -2,6 +2,7 @@ %{ /* * Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 @@ -16,7 +17,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -122,19 +123,6 @@ list* make_range_from_width(uint64_t wid) return rlist; } -static list* make_range_from_pair(list*rpair) -{ - pform_range_t range; - assert(rpair && rpair->size() == 2); - range.first = rpair->front(); - range.second = rpair->back(); - delete rpair; - - list*rlist = new list; - rlist->push_back(range); - return rlist; -} - static list* list_from_identifier(char*id) { list*tmp = new list; @@ -262,9 +250,12 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) current_task->set_statement(tmp); return; } + assert(s); - /* The parser assures that there is a non-empty vector. */ - assert(s && !s->empty()); + /* An empty vector represents one or more null statements. Handle + this as a simple null statement. */ + if (s->empty()) + return; /* A vector of 1 is handled as a simple statement. */ if (s->size() == 1) { @@ -297,9 +288,12 @@ static void current_function_set_statement(const YYLTYPE&loc, vector current_function->set_statement(tmp); return; } + assert(s); - /* The parser assures that there is a non-empty vector. */ - assert(s && !s->empty()); + /* An empty vector represents one or more null statements. Handle + this as a simple null statement. */ + if (s->empty()) + return; /* A vector of 1 is handled as a simple statement. */ if (s->size() == 1) { @@ -369,6 +363,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector PGBuiltin::Type gatetype; NetNet::PortType porttype; ivl_variable_type_t vartype; + PBlock::BL_TYPE join_keyword; PWire*wire; svector*wires; @@ -391,6 +386,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector data_type_t*data_type; class_type_t*class_type; + real_type_t::type_t real_type; + property_qualifier_t property_qualifier; verinum* number; @@ -413,6 +410,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %token K_PO_POS K_PO_NEG K_POW %token K_PSTAR K_STARP K_DOTSTAR %token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER +%token K_SCOPE_RES %token K_edge_descriptor /* The base tokens from 1364-1995. */ @@ -565,13 +563,17 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type struct_union_member_list %type struct_data_type +%type class_item_qualifier property_qualifier +%type property_qualifier_list property_qualifier_opt +%type random_qualifier + %type range range_opt variable_dimension %type dimensions_opt dimensions %type net_type var_type net_type_opt %type gatetype switchtype %type port_direction port_direction_opt -%type primitive_type primitive_type_opt bit_logic +%type bit_logic %type integer_vector_type %type parameter_value_opt @@ -586,13 +588,16 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type analog_statement +%type join_keyword + %type spec_polarity %type specify_path_identifiers %type specify_simple_path specify_simple_path_decl %type specify_edge_path specify_edge_path_decl -%type atom2_type non_integer_type +%type non_integer_type +%type atom2_type %type module_start module_end %token K_TAND @@ -623,13 +628,10 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %% - /* A degenerate source file can be completely empty. */ -main : source_file | ; -source_file - : description - | source_file description - ; + /* IEEE1800-2005: A.1.2 */ + /* source_text ::= [ timeunits_declaration ] { description } */ +source_text : description_list | ; assignment_pattern /* IEEE1800-2005: A.6.7.1 */ : K_LP expression_list_proper '}' @@ -656,7 +658,6 @@ class_declaration /* IEEE1800-2005: A.1.2 */ 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. @@ -765,13 +766,19 @@ class_item /* IEEE1800-2005: A.1.8 */ /* Class properties... */ | property_qualifier_opt data_type list_of_variable_decl_assignments ';' - + { pform_class_property(@2, $1, $2, $3); } /* Class methods... */ | method_qualifier_opt task_declaration + { yyerror(@2, "sorry: Class methods (tasks) not supported yet."); + yyerrok; + } | method_qualifier_opt function_declaration + { yyerror(@2, "sorry: Class methods (functions) not supported yet."); + yyerrok; + } /* Class constraints... */ @@ -804,20 +811,26 @@ class_item /* IEEE1800-2005: A.1.8 */ ; class_item_qualifier /* IEEE1800-2005 A.1.8 */ - : K_static - | K_protected - | K_local + : K_static { $$ = property_qualifier_t::set_static(); } + | K_protected { $$ = property_qualifier_t::set_protected(); } + | K_local { $$ = property_qualifier_t::set_local(); } ; class_new /* IEEE1800-2005 A.2.4 */ : K_new '(' ')' - { yyerror(@1, "sorry: class_new not implemented yet."); - $$ = 0; + { PENewClass*tmp = new PENewClass; + FILE_NAME(tmp, @1); + $$ = tmp; } | K_new '(' expression_list_proper ')' { yyerror(@1, "sorry: class_new not implemented yet."); $$ = 0; } + | K_new + { PENewClass*tmp = new PENewClass; + FILE_NAME(tmp, @1); + $$ = tmp; + } ; constraint_block_item /* IEEE1800-2005 A.1.9 */ @@ -836,7 +849,7 @@ constraint_block_item_list_opt 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.") } + { yyerror(@2, "sorry: Constraint declarations not supported."); } /* Error handling rules... */ @@ -860,7 +873,7 @@ constraint_expression_list /* */ constraint_prototype /* IEEE1800-2005: A.1.9 */ : K_static_opt K_constraint IDENTIFIER ';' - { yyerror(@2, "sorry: Constraint prototypes not supported.") } + { yyerror(@2, "sorry: Constraint prototypes not supported."); } ; constraint_set /* IEEE1800-2005 A.1.9 */ @@ -870,7 +883,14 @@ constraint_set /* IEEE1800-2005 A.1.9 */ 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); + { ivl_variable_type_t use_vtype = $1; + bool reg_flag = false; + if (use_vtype == IVL_VT_NO_TYPE) { + use_vtype = IVL_VT_LOGIC; + reg_flag = true; + } + vector_type_t*tmp = new vector_type_t(use_vtype, $2, $3); + tmp->reg_flag = reg_flag; FILE_NAME(tmp, @1); $$ = tmp; } @@ -888,11 +908,14 @@ data_type /* IEEE1800-2005: A.2.2.1 */ FILE_NAME(tmp, @1); $$ = tmp; } - | TYPE_IDENTIFIER - { $$ = $1; } + | TYPE_IDENTIFIER range_opt + { if ($2) $$ = new parray_type_t($1, $2); + else $$ = $1; + } | K_string - { yyerror(@1, "sorry: String data type not supported."); - $$ = 0; + { string_type_t*tmp = new string_type_t; + FILE_NAME(tmp, @1); + $$ = tmp; } ; @@ -907,11 +930,13 @@ data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ { $$ = $1; } | signing range_opt { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2); + tmp->implicit_flag = true; FILE_NAME(tmp, @1); $$ = tmp; } | range { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, false, $1); + tmp->implicit_flag = true; FILE_NAME(tmp, @1); $$ = tmp; } @@ -919,6 +944,37 @@ data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ { $$ = 0; } ; + + /* NOTE 1: We pull the "timeunits_declaration" into the description + here in order to be a little more flexible with where timeunits + statements may go. This may be a bad idea, but it is legacy now. */ + + /* NOTE 2: The "module" rule of the description combines the + module_declaration and program_declaration rules from the + standard description. */ + +description /* IEEE1800-2005: A.1.2 */ + : module + | udp_primitive + | config_declaration + | nature_declaration + | package_declaration + | discipline_declaration + | timeunits_declaration + | KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' + { perm_string tmp3 = lex_strings.make($3); + pform_set_type_attrib(tmp3, $5, $7); + delete[] $3; + delete[] $5; + } + ; + +description_list + : description + | description_list description + ; + + /* This implements the [ : INDENTIFIER ] part of the constructure rule documented in IEEE1800-2005: A.1.8 */ endnew_opt : ':' K_new | ; @@ -928,12 +984,14 @@ endnew_opt : ':' K_new | ; dynamic_array_new /* IEEE1800-2005: A.2.4 */ : K_new '[' expression ']' - { yyerror(@1, "sorry: Dynamic array new expression not supported."); - $$ = 0; + { $$ = new PENew($3); + FILE_NAME($$, @1); } | K_new '[' expression ']' '(' expression ')' - { yyerror(@1, "sorry: Dynamic array new expression not supported."); - $$ = 0; + { yyerror(@1, "sorry: Dynamic array new expression with initializer not supported."); + delete $6; + $$ = new PENew($3); + FILE_NAME($$, @1); } ; @@ -1076,12 +1134,21 @@ inside_expression /* IEEE1800-2005 A.8.3 */ ; integer_vector_type /* IEEE1800-2005: A.2.2.1 */ - : K_reg { $$ = IVL_VT_LOGIC; } + : K_reg { $$ = IVL_VT_NO_TYPE; } /* Usually a synonym for logic. */ | K_bit { $$ = IVL_VT_BOOL; } | K_logic { $$ = IVL_VT_LOGIC; } | K_bool { $$ = IVL_VT_BOOL; } /* Icarus Verilog xtypes extension */ ; +join_keyword /* IEEE1800-2005: A.6.3 */ + : K_join + { $$ = PBlock::BL_PAR; } + | K_join_none + { $$ = PBlock::BL_JOIN_NONE; } + | K_join_any + { $$ = PBlock::BL_JOIN_ANY; } + ; + jump_statement /* IEEE1800-2005: A.6.5 */ : K_break ';' { yyerror(@1, "sorry: break statements not supported."); @@ -1239,9 +1306,9 @@ method_qualifier_opt non_integer_type /* IEEE1800-2005: A.2.2.1 */ - : K_real { $$ = K_real; } - | K_realtime { $$ = K_real; } - | K_shortreal { $$ = K_shortreal; } + : K_real { $$ = real_type_t::REAL; } + | K_realtime { $$ = real_type_t::REAL; } + | K_shortreal { $$ = real_type_t::SHORTREAL; } ; number : BASED_NUMBER @@ -1264,6 +1331,57 @@ open_range_list /* IEEE1800-2005 A.2.11 */ | value_range ; +package_declaration /* IEEE1800-2005 A.1.2 */ + : K_package IDENTIFIER ';' + { pform_start_package_declaration(@1, $2); + } + package_item_list_opt + K_endpackage + { pform_end_package_declaration(@1); } + 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 ($8 && (strcmp($2,$8) != 0)) { + yyerror(@8, "error: End name doesn't match package name"); + } + delete[]$2; + if ($8) delete[]$8; + } + ; + +package_import_declaration /* IEEE1800-2005 A.2.1.3 */ + : K_import package_import_item_list ';' + { yyerror(@1, "sorry: Package import declarations not supported."); + } + ; + +package_import_item + : IDENTIFIER K_SCOPE_RES IDENTIFIER + | IDENTIFIER K_SCOPE_RES '*' + ; + +package_import_item_list + : package_import_item_list',' package_import_item + | package_import_item + ; + +package_item /* IEEE1800-2005 A.1.10 */ + : timeunits_declaration + | K_localparam param_type localparam_assign_list ';' + | type_declaration + | function_declaration + ; + +package_item_list + : package_item_list package_item + | package_item + ; + +package_item_list_opt : package_item_list | ; + port_direction /* IEEE1800-2005 A.1.3 */ : K_input { $$ = NetNet::PINPUT; } | K_output { $$ = NetNet::POUTPUT; } @@ -1296,18 +1414,18 @@ property_qualifier /* IEEE1800-2005 A.1.8 */ ; property_qualifier_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */ - : property_qualifier_list - | + : property_qualifier_list { $$ = $1; } + | { $$ = property_qualifier_t::set_none(); } ; property_qualifier_list /* IEEE1800-2005 A.1.8 */ - : property_qualifier_list property_qualifier - | property_qualifier + : property_qualifier_list property_qualifier { $$ = $1 | $2; } + | property_qualifier { $$ = $1; } ; random_qualifier /* IEEE1800-2005 A.1.8 */ - : K_rand - | K_randc + : K_rand { $$ = property_qualifier_t::set_rand(); } + | K_randc { $$ = property_qualifier_t::set_randc(); } ; /* real and realtime are exactly the same so save some code @@ -1691,6 +1809,17 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ } ; + /* NOTE: Icarus Verilog is a little more generous with the + timeunits declarations by allowing them to happen in multiple + places in the file. So the rule is adjusted to be invoked by the + "description" rule. This theoretically allows files to be + concatenated together and still compile. */ +timeunits_declaration /* IEEE1800-2005: A.1.2 */ + : K_timeunit TIME_LITERAL ';' + { pform_set_timeunit($2, false, false); } + | K_timeprecision TIME_LITERAL ';' + { pform_set_timeprecision($2, false, false); } + ; value_range /* IEEE1800-2005: A.8.3 */ : expression @@ -1723,7 +1852,6 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ | '[' ']' { list *tmp = new list; pform_range_t index (0,0); - yyerror("sorry: Dynamic array ranges not supported."); tmp->push_back(index); $$ = tmp; } @@ -1822,19 +1950,19 @@ block_item_decl recovering from an error. */ | data_type register_variable_list ';' - { if ($1) pform_set_data_type(@1, $1, $2, attributes_in_context); + { if ($1) pform_set_data_type(@1, $1, $2, NetNet::REG, attributes_in_context); } | K_reg data_type register_variable_list ';' - { if ($2) pform_set_data_type(@2, $2, $3, attributes_in_context); + { if ($2) pform_set_data_type(@2, $2, $3, NetNet::REG, attributes_in_context); } | K_event list_of_identifiers ';' { pform_make_events($2, @1.text, @1.first_line); } - | K_parameter parameter_assign_decl ';' - | K_localparam localparam_assign_decl ';' + | K_parameter param_type parameter_assign_list ';' + | K_localparam param_type localparam_assign_list ';' /* Blocks can have type declarations. */ @@ -1853,15 +1981,15 @@ block_item_decl yyerrok; } - | K_parameter error ';' - { yyerror(@1, "error: syntax error in parameter list."); - yyerrok; - } - | K_localparam error ';' - { yyerror(@1, "error: syntax error localparam list."); - yyerrok; - } - ; + | K_parameter error ';' + { yyerror(@1, "error: syntax error in parameter list."); + yyerrok; + } + | K_localparam error ';' + { yyerror(@1, "error: syntax error localparam list."); + yyerrok; + } + ; block_item_decls : block_item_decl @@ -1893,11 +2021,11 @@ type_declaration delete[]$3; } | K_typedef K_enum IDENTIFIER ';' - { yyerror(@1, "sorry: Enum forward declarations not supported yet.") } + { yyerror(@1, "sorry: Enum forward declarations not supported yet."); } | K_typedef K_struct IDENTIFIER ';' - { yyerror(@1, "sorry: Struct forward declarations not supported yet.") } + { yyerror(@1, "sorry: Struct forward declarations not supported yet."); } | K_typedef K_union IDENTIFIER ';' - { yyerror(@1, "sorry: Union forward declarations not supported yet.") } + { 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. @@ -2273,24 +2401,6 @@ delay_value_simple } ; -description - : module - | udp_primitive - | config_declaration - | nature_declaration - | discipline_declaration - | KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' - { perm_string tmp3 = lex_strings.make($3); - pform_set_type_attrib(tmp3, $5, $7); - delete[] $3; - delete[] $5; - } - | K_timeunit TIME_LITERAL ';' - { pform_set_timeunit($2, false, false); } - | K_timeprecision TIME_LITERAL ';' - { pform_set_timeprecision($2, false, false); } - ; - /* The discipline and nature declarations used to take no ';' after the identifier. The 2.3 LRM adds the ';', but since there are programs written to the 2.1 and 2.2 standard that don't, we @@ -2378,8 +2488,9 @@ config_rule_statement ; opt_config - : /* The use clause takse an optional :config. */ + : /* The use clause takes an optional :config. */ | ':' K_config + ; lib_cell_id : IDENTIFIER @@ -2392,6 +2503,7 @@ list_of_libraries : /* A NULL library means use the parents cell library. */ | list_of_libraries IDENTIFIER { delete[] $2; } + ; drive_strength : '(' dr_strength0 ',' dr_strength1 ')' @@ -3130,8 +3242,9 @@ expr_primary { $$ = $1; } | K_null - { yyerror("sorry: null expressions not supported yet."); - $$ = 0; + { PENull*tmp = new PENull; + FILE_NAME(tmp, @1); + $$ = tmp; } ; @@ -3467,6 +3580,7 @@ list_of_port_declarations port_declaration_context.port_net_type, port_declaration_context.var_type, port_declaration_context.sign_flag, + port_declaration_context.data_type, port_declaration_context.range, 0); delete[]$3; $$ = tmp; @@ -3484,39 +3598,19 @@ list_of_port_declarations ; port_declaration - : attribute_list_opt - K_input net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER - { Module::port_t*ptmp; - perm_string name = lex_strings.make($7); - ptmp = pform_module_port_reference(name, @2.text, - @2.first_line); - pform_module_define_port(@2, name, NetNet::PINPUT, - $3, $4, $5, $6, $1); - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.port_net_type = $3; - port_declaration_context.var_type = $4; - port_declaration_context.sign_flag = $5; - delete port_declaration_context.range; - port_declaration_context.range = $6; - delete[]$7; - $$ = ptmp; - } - | attribute_list_opt - K_input atom2_type signed_unsigned_opt IDENTIFIER + : attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - 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, - NetNet::UNRESOLVED_WIRE, IVL_VT_BOOL, - $4, use_range, $1); + ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + pform_module_define_port(@2, name, NetNet::PINPUT, $3, IVL_VT_NO_TYPE, + false, $4, 0, $1); port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.port_net_type = NetNet::UNRESOLVED_WIRE; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $4; + port_declaration_context.port_net_type = $3; + port_declaration_context.var_type = IVL_VT_NO_TYPE; + port_declaration_context.sign_flag = false; delete port_declaration_context.range; - port_declaration_context.range = use_range; + port_declaration_context.range = 0; + port_declaration_context.data_type = $4; delete[]$5; $$ = ptmp; } @@ -3527,31 +3621,31 @@ port_declaration ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::PINPUT, - NetNet::WIRE, IVL_VT_REAL, true, 0, $1); + NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1); port_declaration_context.port_type = NetNet::PINPUT; port_declaration_context.port_net_type = NetNet::WIRE; port_declaration_context.var_type = IVL_VT_REAL; port_declaration_context.sign_flag = true; delete port_declaration_context.range; port_declaration_context.range = 0; + port_declaration_context.data_type = 0; delete[]$4; $$ = ptmp; } - | attribute_list_opt - K_inout net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER + | attribute_list_opt K_inout net_type_opt data_type_or_implicit IDENTIFIER { Module::port_t*ptmp; - perm_string name = lex_strings.make($7); - ptmp = pform_module_port_reference(name, @2.text, - @2.first_line); - pform_module_define_port(@2, name, NetNet::PINOUT, - $3, $4, $5, $6, $1); + perm_string name = lex_strings.make($5); + ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + pform_module_define_port(@2, name, NetNet::PINOUT, $3, IVL_VT_NO_TYPE, + false, $4, 0, $1); port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.port_net_type = $3; - port_declaration_context.var_type = $4; - port_declaration_context.sign_flag = $5; + port_declaration_context.var_type = IVL_VT_NO_TYPE; + port_declaration_context.sign_flag = false; delete port_declaration_context.range; - port_declaration_context.range = $6; - delete[]$7; + port_declaration_context.range = 0; + port_declaration_context.data_type = $4; + delete[]$5; $$ = ptmp; } | attribute_list_opt @@ -3561,130 +3655,43 @@ port_declaration ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::PINOUT, - NetNet::WIRE, IVL_VT_REAL, true, 0, $1); + NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1); port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.port_net_type = NetNet::WIRE; port_declaration_context.var_type = IVL_VT_REAL; port_declaration_context.sign_flag = true; delete port_declaration_context.range; port_declaration_context.range = 0; + port_declaration_context.data_type = 0; delete[]$4; $$ = ptmp; } - | attribute_list_opt - K_output net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER - { Module::port_t*ptmp; - perm_string name = lex_strings.make($7); - ptmp = pform_module_port_reference(name, @2.text, - @2.first_line); - pform_module_define_port(@2, name, NetNet::POUTPUT, - $3, $4, $5, $6, $1); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.port_net_type = $3; - port_declaration_context.var_type = $4; - port_declaration_context.sign_flag = $5; - delete port_declaration_context.range; - port_declaration_context.range = $6; - delete[]$7; - $$ = ptmp; - } - | attribute_list_opt - K_output var_type primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER - { Module::port_t*ptmp; - perm_string name = lex_strings.make($7); - ptmp = pform_module_port_reference(name, @2.text, - @2.first_line); - pform_module_define_port(@2, name, NetNet::POUTPUT, - $3, $4, $5, $6, $1); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.port_net_type = $3; - port_declaration_context.var_type = $4; - port_declaration_context.sign_flag = $5; - delete port_declaration_context.range; - port_declaration_context.range = $6; - delete[]$7; - $$ = ptmp; - } - | attribute_list_opt - K_output var_type primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER '=' expression - { Module::port_t*ptmp; - perm_string name = lex_strings.make($7); - ptmp = pform_module_port_reference(name, @2.text, - @2.first_line); - pform_module_define_port(@2, name, NetNet::POUTPUT, - $3, $4, $5, $6, $1); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.port_net_type = $3; - port_declaration_context.var_type = $4; - port_declaration_context.sign_flag = $5; - delete port_declaration_context.range; - port_declaration_context.range = $6; - - pform_make_reginit(@7, name, $9); - - delete[]$7; - $$ = ptmp; - } - | attribute_list_opt - K_output net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER '=' expression - { Module::port_t*ptmp; - perm_string name = lex_strings.make($7); - NetNet::Type t = ($3 == NetNet::IMPLICIT) ? NetNet::IMPLICIT_REG : $3; - - ptmp = pform_module_port_reference(name, @2.text, - @2.first_line); - pform_module_define_port(@2, name, NetNet::POUTPUT, - t, $4, $5, $6, $1); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.port_net_type = t; - port_declaration_context.var_type = $4; - port_declaration_context.sign_flag = $5; - delete port_declaration_context.range; - port_declaration_context.range = $6; - - pform_make_reginit(@7, name, $9); - - delete[]$7; - $$ = ptmp; - } - | attribute_list_opt - K_output atom2_type signed_unsigned_opt IDENTIFIER + | attribute_list_opt K_output net_type_opt data_type_or_implicit IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - 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, - NetNet::IMPLICIT_REG, IVL_VT_BOOL, - $4, use_range, $1); + NetNet::Type use_type = $3; + if (use_type == NetNet::IMPLICIT) { + if (vector_type_t*dtype = dynamic_cast ($4)) { + if (dtype->reg_flag) + use_type = NetNet::REG; + else if (dtype->implicit_flag) + use_type = NetNet::IMPLICIT; + else + use_type = NetNet::IMPLICIT_REG; + } else if (dynamic_cast ($4)) { + use_type = NetNet::IMPLICIT_REG; + } + } + ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, IVL_VT_NO_TYPE, + false, $4, 0, $1); port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.port_net_type = NetNet::IMPLICIT_REG; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $4; + port_declaration_context.port_net_type = use_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 = use_range; - delete[]$5; - $$ = ptmp; - } - | attribute_list_opt - 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); - ptmp = pform_module_port_reference(name, @2.text, - @2.first_line); - pform_module_define_port(@2, name, NetNet::POUTPUT, - NetNet::IMPLICIT_REG, IVL_VT_BOOL, - $4, use_range, $1); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.port_net_type = NetNet::IMPLICIT_REG; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $4; - delete port_declaration_context.range; - port_declaration_context.range = use_range; - - pform_make_reginit(@5, name, $7); - + port_declaration_context.range = 0; + port_declaration_context.data_type = $4; delete[]$5; $$ = ptmp; } @@ -3695,16 +3702,47 @@ port_declaration ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::POUTPUT, - NetNet::WIRE, IVL_VT_REAL, true, 0, $1); + NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1); port_declaration_context.port_type = NetNet::POUTPUT; port_declaration_context.port_net_type = NetNet::WIRE; port_declaration_context.var_type = IVL_VT_REAL; port_declaration_context.sign_flag = true; delete port_declaration_context.range; port_declaration_context.range = 0; + port_declaration_context.data_type = 0; delete[]$4; $$ = ptmp; } + | attribute_list_opt K_output net_type_opt data_type_or_implicit IDENTIFIER '=' expression + { Module::port_t*ptmp; + perm_string name = lex_strings.make($5); + NetNet::Type use_type = $3; + if (use_type == NetNet::IMPLICIT) { + if (vector_type_t*dtype = dynamic_cast ($4)) { + if (dtype->reg_flag) + use_type = NetNet::REG; + else + use_type = NetNet::IMPLICIT_REG; + } else { + use_type = NetNet::IMPLICIT_REG; + } + } + ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, IVL_VT_NO_TYPE, + false, $4, 0, $1); + port_declaration_context.port_type = NetNet::PINOUT; + port_declaration_context.port_net_type = use_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; + port_declaration_context.data_type = $4; + + pform_make_reginit(@5, name, $7); + + delete[]$5; + $$ = ptmp; + } ; @@ -3829,7 +3867,7 @@ local_timeunit_prec_decl module : attribute_list_opt module_start IDENTIFIER - { pform_startmodule($3, @2.text, @2.first_line, $1); } + { pform_startmodule(@2, $3, $2==K_program, $1); } module_parameter_port_list_opt module_port_list_opt module_attribute_foreign ';' @@ -3871,11 +3909,7 @@ module 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; } @@ -3888,6 +3922,7 @@ module if ($15 && (strcmp($3,$15) != 0)) { yyerror(@15, "error: End name doesn't match module/program name"); } + delete[]$3; if ($15) delete[]$15; } ; @@ -3918,10 +3953,15 @@ module_attribute_foreign ; module_port_list_opt - : '(' list_of_ports ')' { $$ = $2; } - | '(' list_of_port_declarations ')' { $$ = $2; } - | { $$ = 0; } - ; + : '(' list_of_ports ')' { $$ = $2; } + | '(' list_of_port_declarations ')' { $$ = $2; } + | { $$ = 0; } + | '(' error ')' + { yyerror(@2, "Errors in port declarations."); + yyerrok; + $$ = 0; + } + ; /* Module declarations include optional ANSI style module parameter ports. These are simply advance ways to declare parameters, so @@ -3932,110 +3972,91 @@ module_parameter_port_list_opt ; module_parameter_port_list - : K_parameter parameter_assign + : K_parameter param_type parameter_assign | module_parameter_port_list ',' parameter_assign - | module_parameter_port_list ',' K_parameter parameter_assign + | module_parameter_port_list ',' K_parameter param_type parameter_assign ; module_item - /* This rule detects net declarations that possibly include a - primitive type, an optional vector range and signed flag. This - also includes an optional delay set. The values are then applied - to a list of names. If the primitive type is not specified, then - resort to the default type LOGIC. */ + /* Modules can contain further sub-module definitions. */ + : module - : attribute_list_opt net_type - primitive_type_opt unsigned_signed_opt range_opt - delay3_opt - net_variable_list ';' + | attribute_list_opt net_type data_type_or_implicit delay3_opt net_variable_list ';' - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_makewire(@2, $5, $4, $7, $2, - NetNet::NOT_A_PORT, dtype, $1); - if ($6 != 0) { - yyerror(@6, "sorry: net delays not supported."); - delete $6; - } - delete $1; - } + { data_type_t*data_type = $3; + if (data_type == 0) { + data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); + FILE_NAME(data_type, @2); + } + pform_set_data_type(@2, data_type, $5, $2, $1); + if ($4 != 0) { + yyerror(@2, "sorry: net delays not supported."); + delete $4; + } + delete $1; + } - | attribute_list_opt K_wreal delay3 net_variable_list ';' - { pform_makewire(@2, 0, true, $4, NetNet::WIRE, - NetNet::NOT_A_PORT, IVL_VT_REAL, $1); - if ($3 != 0) { - yyerror(@3, "sorry: net delays not supported."); - delete $3; - } - delete $1; - } - | attribute_list_opt K_wreal net_variable_list ';' - { pform_makewire(@2, 0, true, $3, NetNet::WIRE, - NetNet::NOT_A_PORT, IVL_VT_REAL, $1); - delete $1; - } + | attribute_list_opt K_wreal delay3 net_variable_list ';' + { real_type_t*tmpt = new real_type_t(real_type_t::REAL); + pform_set_data_type(@2, tmpt, $4, NetNet::WIRE, $1); + if ($3 != 0) { + yyerror(@3, "sorry: net delays not supported."); + delete $3; + } + delete $1; + } + + | attribute_list_opt K_wreal net_variable_list ';' + { real_type_t*tmpt = new real_type_t(real_type_t::REAL); + pform_set_data_type(@2, tmpt, $3, NetNet::WIRE, $1); + delete $1; + } /* Very similar to the rule above, but this takes a list of net_decl_assigns, which are = assignment declarations. */ - | attribute_list_opt net_type - primitive_type_opt unsigned_signed_opt range_opt - delay3_opt net_decl_assigns ';' - - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_makewire(@2, $5, $4, $6, - str_strength, $7, $2, dtype); - if ($1) { - yyerror(@2, "sorry: Attributes not supported " - "on net declaration assignments."); - delete $1; - } - } - - /* 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."); + | attribute_list_opt net_type data_type_or_implicit delay3_opt net_decl_assigns ';' + { data_type_t*data_type = $3; + if (data_type == 0) { + data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); + FILE_NAME(data_type, @2); + } + pform_makewire(@2, $4, str_strength, $5, $2, data_type); + if ($1) { + yyerror(@2, "sorry: Attributes not supported " + "on net declaration assignments."); + delete $1; + } } /* This form doesn't have the range, but does have strengths. This gives strength to the assignment drivers. */ - | attribute_list_opt net_type - primitive_type_opt unsigned_signed_opt - drive_strength net_decl_assigns ';' + | attribute_list_opt net_type data_type_or_implicit drive_strength net_decl_assigns ';' + { data_type_t*data_type = $3; + if (data_type == 0) { + data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); + FILE_NAME(data_type, @2); + } + pform_makewire(@2, 0, $4, $5, $2, data_type); + if ($1) { + yyerror(@2, "sorry: Attributes not supported " + "on net declaration assignments."); + delete $1; + } + } - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_makewire(@2, 0, $4, 0, $5, $6, $2, dtype); - if ($1) { - yyerror(@2, "sorry: Attributes not supported " - "on net declaration assignments."); - delete $1; - } - } - | attribute_list_opt K_wreal net_decl_assigns ';' - { pform_makewire(@2, 0, true, 0, str_strength, $3, - NetNet::WIRE, IVL_VT_REAL); - if ($1) { - yyerror(@2, "sorry: Attributes not supported " - "on net declaration assignments."); - delete $1; - } - } + | attribute_list_opt K_wreal net_decl_assigns ';' + { real_type_t*data_type = new real_type_t(real_type_t::REAL); + pform_makewire(@2, 0, str_strength, $3, NetNet::WIRE, data_type); + if ($1) { + yyerror(@2, "sorry: Attributes not supported " + "on net declaration assignments."); + delete $1; + } + } | K_trireg charge_strength_opt range_opt delay3_opt list_of_identifiers ';' { yyerror(@1, "sorry: trireg nets not supported."); @@ -4123,66 +4144,50 @@ module_item two/three-value delay. These rules handle the different cases. We check that the actual number of delays is correct later. */ - | attribute_list_opt gatetype gate_instance_list ';' - { pform_makegates($2, str_strength, 0, $3, $1); - } + | attribute_list_opt gatetype gate_instance_list ';' + { pform_makegates(@2, $2, str_strength, 0, $3, $1); } - | attribute_list_opt gatetype delay3 gate_instance_list ';' - { pform_makegates($2, str_strength, $3, $4, $1); - } + | attribute_list_opt gatetype delay3 gate_instance_list ';' + { pform_makegates(@2, $2, str_strength, $3, $4, $1); } - | attribute_list_opt gatetype drive_strength gate_instance_list ';' - { pform_makegates($2, $3, 0, $4, $1); - } + | attribute_list_opt gatetype drive_strength gate_instance_list ';' + { pform_makegates(@2, $2, $3, 0, $4, $1); } - | attribute_list_opt gatetype drive_strength delay3 gate_instance_list ';' - { pform_makegates($2, $3, $4, $5, $1); - } + | attribute_list_opt gatetype drive_strength delay3 gate_instance_list ';' + { pform_makegates(@2, $2, $3, $4, $5, $1); } /* The switch type gates do not support a strength. */ - | attribute_list_opt switchtype gate_instance_list ';' - { pform_makegates($2, str_strength, 0, $3, $1); - } + | attribute_list_opt switchtype gate_instance_list ';' + { pform_makegates(@2, $2, str_strength, 0, $3, $1); } - | attribute_list_opt switchtype delay3 gate_instance_list ';' - { pform_makegates($2, str_strength, $3, $4, $1); - } + | attribute_list_opt switchtype delay3 gate_instance_list ';' + { pform_makegates(@2, $2, str_strength, $3, $4, $1); } /* Pullup and pulldown devices cannot have delays, and their strengths are limited. */ - | K_pullup gate_instance_list ';' - { pform_makegates(PGBuiltin::PULLUP, pull_strength, 0, - $2, 0); - } - | K_pulldown gate_instance_list ';' - { pform_makegates(PGBuiltin::PULLDOWN, pull_strength, - 0, $2, 0); - } + | K_pullup gate_instance_list ';' + { pform_makegates(@1, PGBuiltin::PULLUP, pull_strength, 0, $2, 0); } + | K_pulldown gate_instance_list ';' + { pform_makegates(@1, PGBuiltin::PULLDOWN, pull_strength, 0, $2, 0); } - | K_pullup '(' dr_strength1 ')' gate_instance_list ';' - { pform_makegates(PGBuiltin::PULLUP, $3, 0, $5, 0); - } + | K_pullup '(' dr_strength1 ')' gate_instance_list ';' + { pform_makegates(@1, PGBuiltin::PULLUP, $3, 0, $5, 0); } - | K_pullup '(' dr_strength1 ',' dr_strength0 ')' gate_instance_list ';' - { pform_makegates(PGBuiltin::PULLUP, $3, 0, $7, 0); - } + | K_pullup '(' dr_strength1 ',' dr_strength0 ')' gate_instance_list ';' + { pform_makegates(@1, PGBuiltin::PULLUP, $3, 0, $7, 0); } - | K_pullup '(' dr_strength0 ',' dr_strength1 ')' gate_instance_list ';' - { pform_makegates(PGBuiltin::PULLUP, $5, 0, $7, 0); - } + | K_pullup '(' dr_strength0 ',' dr_strength1 ')' gate_instance_list ';' + { pform_makegates(@1, PGBuiltin::PULLUP, $5, 0, $7, 0); } - | K_pulldown '(' dr_strength0 ')' gate_instance_list ';' - { pform_makegates(PGBuiltin::PULLDOWN, $3, 0, $5, 0); - } + | K_pulldown '(' dr_strength0 ')' gate_instance_list ';' + { pform_makegates(@1, PGBuiltin::PULLDOWN, $3, 0, $5, 0); } - | K_pulldown '(' dr_strength1 ',' dr_strength0 ')' gate_instance_list ';' - { pform_makegates(PGBuiltin::PULLDOWN, $5, 0, $7, 0); - } + | K_pulldown '(' dr_strength1 ',' dr_strength0 ')' gate_instance_list ';' + { pform_makegates(@1, PGBuiltin::PULLDOWN, $5, 0, $7, 0); } - | K_pulldown '(' dr_strength0 ',' dr_strength1 ')' gate_instance_list ';' - { pform_makegates(PGBuiltin::PULLDOWN, $3, 0, $7, 0); - } + | K_pulldown '(' dr_strength0 ',' dr_strength1 ')' gate_instance_list ';' + { pform_makegates(@1, PGBuiltin::PULLDOWN, $3, 0, $7, 0); } /* This rule handles instantiations of modules and user defined primitives. These devices to not have delay lists or strengths, @@ -4191,7 +4196,7 @@ module_item | attribute_list_opt IDENTIFIER parameter_value_opt gate_instance_list ';' { perm_string tmp1 = lex_strings.make($2); - pform_make_modgates(tmp1, $3, $4); + pform_make_modgates(@2, tmp1, $3, $4); delete[]$2; if ($1) delete $1; } @@ -4296,6 +4301,12 @@ module_item pform_endgenerate(); } + | package_import_declaration + + /* 1364-2001 and later allow specparam declarations outside specify blocks. */ + + | attribute_list_opt K_specparam specparam_decl ';' + /* specify blocks are parsed but ignored. */ | K_specify K_endspecify @@ -4314,13 +4325,6 @@ module_item module items. These rules try to catch them at a point where a reasonable error message can be produced. */ - | K_module error ';' - { yyerror(@1, "error: missing endmodule or attempt to " - "nest modules."); - pform_error_nested_modules(); - yyerrok; - } - | error ';' { yyerror(@2, "error: invalid module item."); yyerrok; @@ -4363,7 +4367,7 @@ module_item { pform_set_timeprecision($2, true, true); } ; -generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); } +generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); } ; generate_case_items : generate_case_items generate_case_item @@ -4433,20 +4437,11 @@ net_decl_assigns } ; -primitive_type - : K_logic { $$ = IVL_VT_LOGIC; } - | K_bool { $$ = IVL_VT_BOOL; /* Icarus Verilog xtypes */} - | K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */} - | K_real { $$ = IVL_VT_REAL; } -; - bit_logic : K_logic { $$ = IVL_VT_LOGIC; } | K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */} ; -primitive_type_opt : primitive_type { $$ = $1; } | { $$ = IVL_VT_NO_TYPE; } ; - net_type : K_wire { $$ = NetNet::WIRE; } | K_tri { $$ = NetNet::TRI; } @@ -4470,19 +4465,15 @@ var_type : K_reg { $$ = NetNet::REG; } ; - /* In this rule we have matched the "parameter" keyword. The rule - generates a type (optional) and a list of assignments. */ - -parameter_assign_decl - : parameter_assign_list - | range - { param_active_range = $1; +param_type + : + { param_active_range = 0; param_active_signed = false; param_active_type = IVL_VT_LOGIC; } - parameter_assign_list - { param_active_range = 0; - param_active_signed = false; + | range + { param_active_range = $1; + param_active_signed = false; param_active_type = IVL_VT_LOGIC; } | K_signed @@ -4490,67 +4481,47 @@ parameter_assign_decl param_active_signed = true; param_active_type = IVL_VT_LOGIC; } - parameter_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } | K_signed range { param_active_range = $2; param_active_signed = true; param_active_type = IVL_VT_LOGIC; } - parameter_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } | K_integer { param_active_range = make_range_from_width(integer_width); param_active_signed = true; param_active_type = IVL_VT_LOGIC; } - parameter_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } | K_time { param_active_range = make_range_from_width(64); param_active_signed = false; param_active_type = IVL_VT_LOGIC; } - parameter_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } | real_or_realtime { param_active_range = 0; param_active_signed = true; param_active_type = IVL_VT_REAL; } - parameter_assign_list - { param_active_range = 0; - 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 and localparam assignment lists are broken into + separate BNF so that I can call slightly different parameter + handling code. localparams parse the same as parameters, they + just behave differently when someone tries to override them. */ + parameter_assign_list - : parameter_assign - | parameter_assign_list ',' parameter_assign - ; + : parameter_assign + | parameter_assign_list ',' parameter_assign + ; + +localparam_assign_list + : localparam_assign + | localparam_assign_list ',' localparam_assign + ; parameter_assign : IDENTIFIER '=' expression parameter_value_ranges_opt @@ -4561,6 +4532,15 @@ parameter_assign } ; +localparam_assign + : IDENTIFIER '=' expression + { PExpr*tmp = $3; + pform_set_localparam(@1, lex_strings.make($1), param_active_type, + param_active_signed, param_active_range, tmp); + delete[]$1; + } + ; + parameter_value_ranges_opt : parameter_value_ranges { $$ = $1; } | { $$ = 0; } ; parameter_value_ranges @@ -4592,103 +4572,6 @@ value_range_expression from_exclude : K_from { $$ = false; } | K_exclude { $$ = true; } ; - /* Localparam assignments and assignment lists are broken into - separate BNF so that I can call slightly different parameter - handling code. They parse the same as parameters, they just - behave differently when someone tries to override them. */ - -localparam_assign - : IDENTIFIER '=' expression - { PExpr*tmp = $3; - pform_set_localparam(@1, lex_strings.make($1), - param_active_type, - param_active_signed, - param_active_range, tmp); - delete[]$1; - } - ; - -localparam_assign_decl - : localparam_assign_list - | range - { param_active_range = $1; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } - localparam_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } - | K_signed - { param_active_range = 0; - param_active_signed = true; - param_active_type = IVL_VT_LOGIC; - } - localparam_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } - | K_signed range - { param_active_range = $2; - param_active_signed = true; - param_active_type = IVL_VT_LOGIC; - } - localparam_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } - | K_integer - { param_active_range = make_range_from_width(integer_width); - param_active_signed = true; - param_active_type = IVL_VT_LOGIC; - } - localparam_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } - | K_time - { param_active_range = make_range_from_width(64); - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } - localparam_assign_list - { param_active_range = 0; - param_active_signed = false; - param_active_type = IVL_VT_LOGIC; - } - | real_or_realtime - { param_active_range = 0; - param_active_signed = true; - param_active_type = IVL_VT_REAL; - } - localparam_assign_list - { param_active_range = 0; - 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 - : localparam_assign - | localparam_assign_list ',' localparam_assign - ; - - - /* The parameters of a module instance can be overridden by writing a list of expressions in a syntax much like a delay list. (The difference being the list can have any length.) The pform that @@ -4698,7 +4581,9 @@ localparam_assign_list Although the BNF in IEEE1364-1995 implies that parameter value lists must be in parentheses, in practice most compilers will accept simple expressions outside of parentheses if there is only - one value, so I'll accept simple numbers here. + one value, so I'll accept simple numbers here. This also catches + the case of a UDP with a single delay value, so we need to accept + real values as well as decimal ones. The parameter value by name syntax is OVI enhancement BTF-B06 as approved by WG1364 on 6/28/1998. */ @@ -4728,6 +4613,17 @@ parameter_value_opt $$ = lst; based_size = 0; } + | '#' REALTIME + { assert($2); + PEFNumber*tmp = new PEFNumber($2); + FILE_NAME(tmp, @1); + + struct parmvalue_t*lst = new struct parmvalue_t; + lst->by_order = new list; + lst->by_order->push_back(tmp); + lst->by_name = 0; + $$ = lst; + } | '#' error { yyerror(@1, "error: syntax error in parameter value " "assignment list."); @@ -4993,8 +4889,9 @@ range_opt ; dimensions_opt - : { $$ = 0; } - | dimensions { $$ = $1; } + : { $$ = 0; } + | dimensions { $$ = $1; } + ; dimensions : variable_dimension @@ -5052,19 +4949,10 @@ function_range_or_type_opt so that bit ranges can be assigned. */ register_variable : IDENTIFIER dimensions_opt - { perm_string ident_name = lex_strings.make($1); - pform_makewire(@1, ident_name, NetNet::REG, + { perm_string name = lex_strings.make($1); + pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); - if ($2 != 0) { - 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.first, index.second); - delete $2; - } + pform_set_reg_idx(name, $2); $$ = $1; } | IDENTIFIER '=' expression @@ -5096,16 +4984,7 @@ net_variable { 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) { - 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.first, index.second); - delete $2; - } + pform_set_reg_idx(name, $2); $$ = $1; } ; @@ -5126,7 +5005,7 @@ net_variable_list ; specify_item - : K_specparam specparam_list ';' + : K_specparam specparam_decl ';' | specify_simple_path_decl ';' { pform_module_specify_path($1); } @@ -5332,7 +5211,8 @@ specify_path_identifiers specparam : IDENTIFIER '=' expression { PExpr*tmp = $3; - pform_set_specparam(lex_strings.make($1), tmp); + pform_set_specparam(@1, lex_strings.make($1), + param_active_range, tmp); delete[]$1; } | IDENTIFIER '=' expression ':' expression ':' expression @@ -5370,7 +5250,8 @@ specparam cerr << " expression." << endl; min_typ_max_warn -= 1; } - pform_set_specparam(lex_strings.make($1), tmp); + pform_set_specparam(@1, lex_strings.make($1), + param_active_range, tmp); delete[]$1; } | PATHPULSE_IDENTIFIER '=' expression @@ -5385,9 +5266,17 @@ specparam ; specparam_list - : specparam - | specparam_list ',' specparam - ; + : specparam + | specparam_list ',' specparam + ; + +specparam_decl + : specparam_list + | range + { param_active_range = $1; } + specparam_list + { param_active_range = 0; } + ; spec_polarity : '+' { $$ = '+'; } @@ -5532,13 +5421,13 @@ statement_item /* This is roughly statement_item in the LRM */ need to do is remember that this is a parallel block so that the code generator can do the right thing. */ - | K_fork K_join - { PBlock*tmp = new PBlock(PBlock::BL_PAR); + | K_fork join_keyword + { PBlock*tmp = new PBlock($2); FILE_NAME(tmp, @1); $$ = tmp; } - | K_fork statement_or_null_list K_join - { PBlock*tmp = new PBlock(PBlock::BL_PAR); + | K_fork statement_or_null_list join_keyword + { PBlock*tmp = new PBlock($3); FILE_NAME(tmp, @1); tmp->set_statement(*$2); delete $2; @@ -5550,11 +5439,12 @@ statement_item /* This is roughly statement_item in the LRM */ current_block_stack.push(tmp); } block_item_decls_opt - statement_or_null_list_opt K_join + statement_or_null_list_opt join_keyword { pform_pop_scope(); assert(! current_block_stack.empty()); PBlock*tmp = current_block_stack.top(); current_block_stack.pop(); + tmp->set_join_type($7); if ($6) tmp->set_statement(*$6); delete[]$3; delete $6; @@ -5670,56 +5560,56 @@ statement_item /* This is roughly statement_item in the LRM */ $$ = tmp; } - | error '=' expression ';' - { yyerror(@2, "Syntax in assignment statement l-value."); - yyerrok; - $$ = new PNoop; - } - | lpvalue K_LE expression ';' - { PAssignNB*tmp = new PAssignNB($1,$3); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | error K_LE expression ';' - { yyerror(@2, "Syntax in assignment statement l-value."); - yyerrok; - $$ = new PNoop; - } - | lpvalue '=' delay1 expression ';' - { PExpr*del = $3->front(); $3->pop_front(); - assert($3->empty()); - PAssign*tmp = new PAssign($1,del,$4); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | lpvalue K_LE delay1 expression ';' - { PExpr*del = $3->front(); $3->pop_front(); - assert($3->empty()); - PAssignNB*tmp = new PAssignNB($1,del,$4); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | lpvalue '=' event_control expression ';' - { PAssign*tmp = new PAssign($1,0,$3,$4); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | lpvalue '=' K_repeat '(' expression ')' event_control expression ';' - { PAssign*tmp = new PAssign($1,$5,$7,$8); - FILE_NAME(tmp,@1); - tmp->set_lineno(@1.first_line); - $$ = tmp; - } - | lpvalue K_LE event_control expression ';' - { PAssignNB*tmp = new PAssignNB($1,0,$3,$4); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | lpvalue K_LE K_repeat '(' expression ')' event_control expression ';' - { PAssignNB*tmp = new PAssignNB($1,$5,$7,$8); - FILE_NAME(tmp, @1); - $$ = tmp; - } + | error '=' expression ';' + { yyerror(@2, "Syntax in assignment statement l-value."); + yyerrok; + $$ = new PNoop; + } + | lpvalue K_LE expression ';' + { PAssignNB*tmp = new PAssignNB($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | error K_LE expression ';' + { yyerror(@2, "Syntax in assignment statement l-value."); + yyerrok; + $$ = new PNoop; + } + | lpvalue '=' delay1 expression ';' + { PExpr*del = $3->front(); $3->pop_front(); + assert($3->empty()); + PAssign*tmp = new PAssign($1,del,$4); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_LE delay1 expression ';' + { PExpr*del = $3->front(); $3->pop_front(); + assert($3->empty()); + PAssignNB*tmp = new PAssignNB($1,del,$4); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue '=' event_control expression ';' + { PAssign*tmp = new PAssign($1,0,$3,$4); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue '=' K_repeat '(' expression ')' event_control expression ';' + { PAssign*tmp = new PAssign($1,$5,$7,$8); + FILE_NAME(tmp,@1); + tmp->set_lineno(@1.first_line); + $$ = tmp; + } + | lpvalue K_LE event_control expression ';' + { PAssignNB*tmp = new PAssignNB($1,0,$3,$4); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | lpvalue K_LE K_repeat '(' expression ')' event_control expression ';' + { PAssignNB*tmp = new PAssignNB($1,$5,$7,$8); + FILE_NAME(tmp, @1); + $$ = tmp; + } /* The IEEE1800 standard defines dynamic_array_new assignment as a different rule from regular assignment. That implies that the @@ -5892,12 +5782,12 @@ statement_or_null_list_opt statement_or_null_list : statement_or_null_list statement_or_null { vector*tmp = $1; - tmp->push_back($2); + if ($2) tmp->push_back($2); $$ = tmp; } | statement_or_null - { vector*tmp = new vector(1); - tmp->at(0) = $1; + { vector*tmp = new vector(0); + if ($1) tmp->push_back($1); $$ = tmp; } ; diff --git a/parse_api.h b/parse_api.h index 05e6a09a2..91b80e3d5 100644 --- a/parse_api.h +++ b/parse_api.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/parse_misc.cc b/parse_misc.cc index 241341564..4956ced6b 100644 --- a/parse_misc.cc +++ b/parse_misc.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -33,6 +33,8 @@ std::ostream& operator << (std::ostream&o, const YYLTYPE&loc) { if (loc.text) o << loc.text << ":"; + else + o << "<>:"; o << loc.first_line; return o; } diff --git a/parse_misc.h b/parse_misc.h index 037fefffe..a0a8fe817 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -35,6 +35,7 @@ struct vlltype { unsigned last_line; unsigned last_column; const char*text; + std::string get_fileline() const; }; # define YYLTYPE struct vlltype diff --git a/pform.cc b/pform.cc index ac8cb2a9b..aacaf0bbf 100644 --- a/pform.cc +++ b/pform.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -25,6 +25,7 @@ # include "parse_api.h" # include "PClass.h" # include "PEvent.h" +# include "PPackage.h" # include "PUdp.h" # include "PGenerate.h" # include "PSpec.h" @@ -41,10 +42,25 @@ # include "ivl_assert.h" # include "ivl_alloc.h" +/* + * The pform_modules is a map of the modules that have been defined in + * the top level. This should not contain nested modules/programs. + */ map pform_modules; +/* + */ map pform_primitives; +std::string vlltype::get_fileline() const +{ + ostringstream buf; + buf << (text? text : "") << ":" << first_line; + string res = buf.str(); + return res; + +} + /* * Parse configuration file with format =, where key * is the hierarchical name of a valid parameter name, and value @@ -208,7 +224,7 @@ extern int VLparse(); /* This tracks the current module being processed. There can only be exactly one module currently being parsed, since Verilog does not allow nested module definitions. */ -static Module*pform_cur_module = 0; +static listpform_cur_module; bool pform_library_flag = false; @@ -268,15 +284,46 @@ void pform_pop_scope() lexical_scope = lexical_scope->parent_scope(); } +static PScopeExtra* find_nearest_scopex(LexicalScope*scope) +{ + PScopeExtra*scopex = dynamic_cast (scope); + while (scope && !scopex) { + scope = scope->parent_scope(); + scopex = dynamic_cast (scope); + } + return scopex; +} + 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); + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); + + assert(!pform_cur_generate); + + if (scopex->classes.find(name) != scopex->classes.end()) { + cerr << class_scope->get_fileline() << ": error: duplicate " + " definition for class '" << name << "' in '" + << scopex->pscope_name() << "'." << endl; + error_count += 1; + } + scopex->classes[name] = class_scope; + lexical_scope = class_scope; return class_scope; } +PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name) +{ + PPackage*pkg_scope = new PPackage(name, lexical_scope); + FILE_NAME(pkg_scope, loc); + + lexical_scope = pkg_scope; + return pkg_scope; +} + PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) { perm_string task_name = lex_strings.make(name); @@ -284,12 +331,7 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) 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); - } + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); assert(scopex); if (pform_cur_generate) { @@ -298,7 +340,7 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) pform_cur_generate->tasks.end()) { cerr << task->get_fileline() << ": error: duplicate " "definition for task '" << name << "' in '" - << pform_cur_module->mod_name() << "' (generate)." + << pform_cur_module.front()->mod_name() << "' (generate)." << endl; error_count += 1; } @@ -341,7 +383,7 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name, pform_cur_generate->funcs.end()) { cerr << func->get_fileline() << ": error: duplicate " "definition for function '" << name << "' in '" - << pform_cur_module->mod_name() << "' (generate)." + << pform_cur_module.front()->mod_name() << "' (generate)." << endl; error_count += 1; } @@ -391,9 +433,18 @@ void pform_bind_attributes(map&attributes, delete attr; } +bool pform_in_program_block() +{ + if (pform_cur_module.empty()) + return false; + if (pform_cur_module.front()->program_block) + return true; + return false; +} + static bool pform_at_module_level() { - return (lexical_scope == pform_cur_module) + return (lexical_scope == pform_cur_module.front()) || (lexical_scope == pform_cur_generate); } @@ -449,7 +500,7 @@ data_type_t* pform_test_type_identifier(const char*txt) 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; @@ -470,15 +521,15 @@ void pform_set_default_nettype(NetNet::Type type, { pform_default_nettype = type; - if (pform_cur_module) { + if (! pform_cur_module.empty()) { cerr << file<<":"<mod_name() + << "module " << pform_cur_module.back()->mod_name() << " starts on line " - << pform_cur_module->get_fileline() << "." << endl; + << pform_cur_module.back()->get_fileline() << "." << endl; error_count += 1; } } @@ -681,14 +732,14 @@ void pform_set_timeunit(const char*txt, bool in_module, bool only_check) if (in_module) { if (!only_check) { - pform_cur_module->time_unit = val; + pform_cur_module.front()->time_unit = val; tu_decl_flag = true; tu_local_flag = true; } else if (!tu_decl_flag) { VLerror(yylloc, "error: repeat timeunit found and the " "initial module timeunit is missing."); return; - } else if (pform_cur_module->time_unit != val) { + } else if (pform_cur_module.front()->time_unit != val) { VLerror(yylloc, "error: repeat timeunit does not match " "the initial module timeunit " "declaration."); @@ -705,7 +756,7 @@ void pform_set_timeunit(const char*txt, bool in_module, bool only_check) int pform_get_timeunit() { - return pform_cur_module->time_unit; + return pform_cur_module.front()->time_unit; } void pform_set_timeprecision(const char*txt, bool in_module, bool only_check) @@ -716,14 +767,14 @@ void pform_set_timeprecision(const char*txt, bool in_module, bool only_check) if (in_module) { if (!only_check) { - pform_cur_module->time_precision = val; + pform_cur_module.front()->time_precision = val; tp_decl_flag = true; tp_local_flag = true; } else if (!tp_decl_flag) { VLerror(yylloc, "error: repeat timeprecision found and the " "initial module timeprecision is missing."); return; - } else if (pform_cur_module->time_precision != val) { + } else if (pform_cur_module.front()->time_precision != val) { VLerror(yylloc, "error: repeat timeprecision does not match " "the initial module timeprecision " "declaration."); @@ -787,43 +838,55 @@ verinum* pform_verinum_with_size(verinum*siz, verinum*val, return res; } -void pform_startmodule(const char*name, const char*file, unsigned lineno, - list*attr) +void pform_startmodule(const struct vlltype&loc, const char*name, + bool program_block, list*attr) { - assert( pform_cur_module == 0 ); + if (! pform_cur_module.empty() && !gn_system_verilog()) { + cerr << loc << ": error: Module definition " << name + << " cannot nest into module " << pform_cur_module.front()->mod_name() << "." << endl; + error_count += 1; + } + + if (gn_system_verilog() && ! pform_cur_module.empty() && + pform_cur_module.front()->program_block) { + cerr << loc << ": error: Program blocks cannot contain nested modules/program blocks." << endl; + error_count += 1; + } perm_string lex_name = lex_strings.make(name); - pform_cur_module = new Module(lex_name); + Module*cur_module = new Module(lexical_scope, lex_name); + cur_module->program_block = program_block; /* Set the local time unit/precision to the global value. */ - pform_cur_module->time_unit = pform_time_unit; - pform_cur_module->time_precision = pform_time_prec; + cur_module->time_unit = pform_time_unit; + cur_module->time_precision = pform_time_prec; tu_local_flag = tu_global_flag; tp_local_flag = tp_global_flag; /* If we have a timescale file then the time information is from * a timescale directive. */ - pform_cur_module->time_from_timescale = pform_timescale_file != 0; + cur_module->time_from_timescale = pform_timescale_file != 0; - FILE_NAME(pform_cur_module, file, lineno); - pform_cur_module->library_flag = pform_library_flag; + FILE_NAME(cur_module, loc); + cur_module->library_flag = pform_library_flag; - ivl_assert(*pform_cur_module, lexical_scope == 0); - lexical_scope = pform_cur_module; + pform_cur_module.push_front(cur_module); + + lexical_scope = cur_module; /* The generate scheme numbering starts with *1*, not zero. That's just the way it is, thanks to the standard. */ scope_generate_counter = 1; if (warn_timescale && pform_timescale_file - && (strcmp(pform_timescale_file,file) != 0)) { + && (strcmp(pform_timescale_file,loc.text) != 0)) { - cerr << pform_cur_module->get_fileline() << ": warning: " + cerr << cur_module->get_fileline() << ": warning: " << "timescale for " << name << " inherited from another file." << endl; cerr << pform_timescale_file << ":" << pform_timescale_line << ": ...: The inherited timescale is here." << endl; } - pform_bind_attributes(pform_cur_module->attributes, attr); + pform_bind_attributes(cur_module->attributes, attr); } /* @@ -833,13 +896,12 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno, */ void pform_check_timeunit_prec() { - assert(pform_cur_module); + assert(! pform_cur_module.empty()); if ((generation_flag & (GN_VER2005_SV | GN_VER2009)) && - (pform_cur_module->time_unit < pform_cur_module->time_precision)) { - VLerror("error: a timeprecision is missing or is too " - "large!"); - } else assert(pform_cur_module->time_unit >= - pform_cur_module->time_precision); + (pform_cur_module.front()->time_unit < pform_cur_module.front()->time_precision)) { + VLerror("error: a timeprecision is missing or is too large!"); + } else assert(pform_cur_module.front()->time_unit >= + pform_cur_module.front()->time_precision); } /* @@ -862,7 +924,7 @@ Module::port_t* pform_module_port_reference(perm_string name, void pform_module_set_ports(vector*ports) { - assert(pform_cur_module); + assert(! pform_cur_module.empty()); /* The parser parses ``module foo()'' as having one unconnected port, but it is really a module with no @@ -873,7 +935,7 @@ void pform_module_set_ports(vector*ports) } if (ports != 0) { - pform_cur_module->ports = *ports; + pform_cur_module.front()->ports = *ports; delete ports; } } @@ -881,34 +943,44 @@ void pform_module_set_ports(vector*ports) void pform_endmodule(const char*name, bool inside_celldefine, Module::UCDriveType uc_drive_def) { - assert(pform_cur_module); - pform_cur_module->time_from_timescale = (tu_local_flag && - tp_local_flag) || - (pform_timescale_file != 0); - perm_string mod_name = pform_cur_module->mod_name(); + assert(! pform_cur_module.empty()); + Module*cur_module = pform_cur_module.front(); + pform_cur_module.pop_front(); + + cur_module->time_from_timescale = (tu_local_flag && tp_local_flag) + || (pform_timescale_file != 0); + perm_string mod_name = cur_module->mod_name(); assert(strcmp(name, mod_name) == 0); - pform_cur_module->is_cell = inside_celldefine; - pform_cur_module->uc_drive = uc_drive_def; + cur_module->is_cell = inside_celldefine; + cur_module->uc_drive = uc_drive_def; + + // If this is a root module, then there is no parent module + // and we try to put this newly defined module into the global + // root list of modules. Otherwise, this is a nested module + // and we put it into the parent module scope to be elaborated + // if needed. + map&use_module_map = (pform_cur_module.empty()) + ? pform_modules + : pform_cur_module.front()->nested_modules; map::const_iterator test = - pform_modules.find(mod_name); + use_module_map.find(mod_name); - if (test != pform_modules.end()) { + if (test != use_module_map.end()) { ostringstream msg; msg << "Module " << name << " was already declared here: " - << (*test).second->get_fileline() << endl; + << test->second->get_fileline() << endl; VLerror(msg.str().c_str()); } else { - pform_modules[mod_name] = pform_cur_module; + use_module_map[mod_name] = cur_module; } // The current lexical scope should be this module by now, and // this module should not have a parent lexical scope. - ivl_assert(*pform_cur_module, lexical_scope == pform_cur_module); + ivl_assert(*cur_module, lexical_scope == cur_module); pform_pop_scope(); - ivl_assert(*pform_cur_module, lexical_scope == 0); + ivl_assert(*cur_module, ! pform_cur_module.empty() || lexical_scope == 0); - pform_cur_module = 0; tp_decl_flag = false; tu_decl_flag = false; tu_local_flag = false; @@ -939,7 +1011,7 @@ void pform_genvars(const struct vlltype&li, list*names) if (pform_cur_generate) pform_add_genvar(li, *cur, pform_cur_generate->genvars); else - pform_add_genvar(li, *cur, pform_cur_module->genvars); + pform_add_genvar(li, *cur, pform_cur_module.front()->genvars); } delete names; @@ -1094,7 +1166,7 @@ void pform_generate_block_name(char*name) void pform_endgenerate() { assert(pform_cur_generate != 0); - assert(pform_cur_module); + assert(! pform_cur_module.empty()); // If there is no explicit block name then generate a temporary // name. This will be replaced by the correct name later, once @@ -1118,7 +1190,7 @@ void pform_endgenerate() parent_generate->generate_schemes.push_back(pform_cur_generate); } else { assert(pform_cur_generate->scheme_type != PGenerate::GS_CASE_ITEM); - pform_cur_module->generate_schemes.push_back(pform_cur_generate); + pform_cur_module.front()->generate_schemes.push_back(pform_cur_generate); } pform_cur_generate = parent_generate; } @@ -1518,6 +1590,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, + NetNet::Type net_type, const list*range, bool signed_flag, ivl_variable_type_t dt, @@ -1529,6 +1602,19 @@ static void pform_set_net_range(perm_string name, VLerror("error: name is not a valid net."); return; } + // If this is not implicit ("implicit" meaning we don't + // know what the type is yet) then set the type now. + if (net_type != NetNet::IMPLICIT && net_type != NetNet::NONE) { + bool rc = cur->set_wire_type(net_type); + if (rc == false) { + ostringstream msg; + msg << name << " " << net_type + << " definition conflicts with " << cur->get_wire_type() + << " definition at " << cur->get_fileline() + << "."; + VLerror(msg.str().c_str()); + } + } if (range == 0) { /* This is the special case that we really mean a @@ -1546,16 +1632,17 @@ static void pform_set_net_range(perm_string name, pform_bind_attributes(cur->attributes, attr, true); } -void pform_set_net_range(list*names, - list*range, - bool signed_flag, - ivl_variable_type_t dt, - std::list*attr) +static void pform_set_net_range(list*names, + list*range, + bool signed_flag, + ivl_variable_type_t dt, + NetNet::Type net_type, + std::list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_net_range(txt, range, signed_flag, dt, SR_NET, attr); + pform_set_net_range(txt, net_type, range, signed_flag, dt, SR_NET, attr); } delete names; @@ -1574,7 +1661,7 @@ static void pform_make_event(perm_string name, const char*fn, unsigned ln) FILE_NAME(&tloc, fn, ln); cerr << tloc.get_fileline() << ": error: duplicate definition " "for named event '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << pform_cur_module.front()->mod_name() << "'." << endl; error_count += 1; } @@ -1634,15 +1721,23 @@ static void pform_makegate(PGBuiltin::Type type, if (pform_cur_generate) pform_cur_generate->add_gate(cur); else - pform_cur_module->add_gate(cur); + pform_cur_module.front()->add_gate(cur); } -void pform_makegates(PGBuiltin::Type type, +void pform_makegates(const struct vlltype&loc, + PGBuiltin::Type type, struct str_pair_t str, list*delay, svector*gates, list*attr) { + assert(! pform_cur_module.empty()); + if (pform_cur_module.front()->program_block) { + cerr << loc << ": error: Gates and switches may not be instantiated" + << " in program blocks." << endl; + error_count += 1; + } + for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) { pform_makegate(type, str, delay, (*gates)[idx], attr); } @@ -1700,7 +1795,7 @@ static void pform_make_modgate(perm_string type, if (pform_cur_generate) pform_cur_generate->add_gate(cur); else - pform_cur_module->add_gate(cur); + pform_cur_module.front()->add_gate(cur); } static void pform_make_modgate(perm_string type, @@ -1744,13 +1839,20 @@ static void pform_make_modgate(perm_string type, if (pform_cur_generate) pform_cur_generate->add_gate(cur); else - pform_cur_module->add_gate(cur); + pform_cur_module.front()->add_gate(cur); } -void pform_make_modgates(perm_string type, +void pform_make_modgates(const struct vlltype&loc, + perm_string type, struct parmvalue_t*overrides, svector*gates) { + assert(! pform_cur_module.empty()); + if (pform_cur_module.front()->program_block) { + cerr << loc << ": error: Module instantiations are not allowed" + << " in program blocks." << endl; + error_count += 1; + } for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) { lgate cur = (*gates)[idx]; @@ -1814,7 +1916,7 @@ static PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval, if (pform_cur_generate) pform_cur_generate->add_gate(cur); else - pform_cur_module->add_gate(cur); + pform_cur_module.front()->add_gate(cur); return cur; } @@ -1893,9 +1995,12 @@ void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, + data_type_t*vtype, list*range, list*attr) { + struct_type_t*struct_type = 0; + PWire*cur = pform_get_wire_in_scope(name); if (cur) { ostringstream msg; @@ -1906,6 +2011,44 @@ void pform_module_define_port(const struct vlltype&li, return; } + if (vtype) { + ivl_assert(li, data_type == IVL_VT_NO_TYPE); + ivl_assert(li, range == 0); + } + + if (vector_type_t*vec_type = dynamic_cast (vtype)) { + data_type = vec_type->base_type; + signed_flag = vec_type->signed_flag; + range = vec_type->pdims.get(); + if (vec_type->reg_flag) + type = NetNet::REG; + + } else if (atom2_type_t*atype = dynamic_cast(vtype)) { + data_type = IVL_VT_BOOL; + signed_flag = atype->signed_flag; + range = make_range_from_width(atype->type_code); + + } else if (real_type_t*rtype = dynamic_cast(vtype)) { + data_type = IVL_VT_REAL; + signed_flag = true; + range = 0; + + if (rtype->type_code != real_type_t::REAL) { + VLerror(li, "sorry: Only real (not shortreal) supported here (%s:%d).", + __FILE__, __LINE__); + } + + } else if ((struct_type = dynamic_cast(vtype))) { + data_type = struct_type->figure_packed_base_type(); + signed_flag = false; + range = 0; + + } else if (vtype) { + VLerror(li, "sorry: Given type %s not supported here (%s:%d).", + typeid(*vtype).name(), __FILE__, __LINE__); + } + + // The default type for all flavor of ports is LOGIC. if (data_type == IVL_VT_NO_TYPE) data_type = IVL_VT_LOGIC; @@ -1915,7 +2058,10 @@ void pform_module_define_port(const struct vlltype&li, cur->set_signed(signed_flag); - if (range == 0) { + if (struct_type) { + cur->set_data_type(struct_type); + + } else if (range == 0) { cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } else { @@ -2040,7 +2186,7 @@ void pform_makewire(const vlltype&li, pform_makewire(li, txt, type, pt, dt, attr); /* This has already been done for real variables. */ if (dt != IVL_VT_REAL) { - pform_set_net_range(txt, range, signed_flag, dt, rt, 0); + pform_set_net_range(txt, type, range, signed_flag, dt, rt, 0); } } @@ -2052,27 +2198,31 @@ void pform_makewire(const vlltype&li, * This form makes nets with delays and continuous assignments. */ void pform_makewire(const vlltype&li, - list*range, - bool signed_flag, list*delay, str_pair_t str, net_decl_assign_t*decls, NetNet::Type type, - ivl_variable_type_t dt) + data_type_t*data_type) { + // The decls pointer is a circularly linked list. net_decl_assign_t*first = decls->next; - decls->next = 0; + list*names = new list; + + // Go through the circularly linked list non-destructively. + do { + pform_makewire(li, first->name, type, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); + names->push_back(first->name); + first = first->next; + } while (first != decls->next); + + pform_set_data_type(li, data_type, names, type, 0); + + // This time, go through the list, deleting cells as I'm done. + first = decls->next; + decls->next = 0; while (first) { net_decl_assign_t*next = first->next; - - pform_makewire(li, first->name, type, NetNet::NOT_A_PORT, dt, 0); - /* This has already been done for real variables. */ - if (dt != IVL_VT_REAL) { - pform_set_net_range(first->name, range, signed_flag, dt, - SR_NET, 0); - } - PWire*cur = pform_get_wire_in_scope(first->name); if (cur != 0) { PEIdent*lval = new PEIdent(first->name); @@ -2242,7 +2392,7 @@ void pform_set_attrib(perm_string name, perm_string key, char*value) if (PWire*cur = lexical_scope->wires_find(name)) { cur->attributes[key] = new PEString(value); - } else if (PGate*curg = pform_cur_module->get_gate(name)) { + } else if (PGate*curg = pform_cur_module.front()->get_gate(name)) { curg->attributes[key] = new PEString(value); } else { @@ -2273,7 +2423,7 @@ void pform_set_type_attrib(perm_string name, const string&key, * This function attaches a memory index range to an existing * register. (The named wire must be a register. */ -void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r) +void pform_set_reg_idx(perm_string name, list*indices) { PWire*cur = lexical_scope->wires_find(name); if (cur == 0) { @@ -2281,7 +2431,8 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r) return; } - cur->set_memory_idx(l, r); + if (indices && !indices->empty()) + cur->set_unpacked_idx(*indices); } LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, @@ -2320,14 +2471,23 @@ void pform_set_parameter(const struct vlltype&loc, FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: duplicate definition " "for parameter '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << pform_cur_module.front()->mod_name() << "'." << endl; error_count += 1; } if (scope->localparams.find(name) != scope->localparams.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: localparam and " - "parameter in '" << pform_cur_module->mod_name() + << "parameter in '" << pform_cur_module.front()->mod_name() + << "' have the same name '" << name << "'." << endl; + error_count += 1; + } + if ((scope == pform_cur_module.front()) && + (pform_cur_module.front()->specparams.find(name) != pform_cur_module.front()->specparams.end())) { + LineInfo tloc; + FILE_NAME(&tloc, loc); + cerr << tloc.get_fileline() << ": error: specparam and " + "parameter in '" << pform_cur_module.front()->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } @@ -2353,8 +2513,8 @@ void pform_set_parameter(const struct vlltype&loc, parm.signed_flag = signed_flag; parm.range = value_range; - if (scope == pform_cur_module) - pform_cur_module->param_names.push_back(name); + if (scope == pform_cur_module.front()) + pform_cur_module.front()->param_names.push_back(name); } void pform_set_localparam(const struct vlltype&loc, @@ -2362,6 +2522,7 @@ void pform_set_localparam(const struct vlltype&loc, bool signed_flag, list*range, PExpr*expr) { LexicalScope*scope = lexical_scope; + ivl_assert(loc, scope); // Check if the localparam name is already in the dictionary. if (scope->localparams.find(name) != scope->localparams.end()) { @@ -2369,14 +2530,25 @@ void pform_set_localparam(const struct vlltype&loc, FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: duplicate definition " "for localparam '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << pform_cur_module.front()->mod_name() << "'." << endl; error_count += 1; } if (scope->parameters.find(name) != scope->parameters.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: parameter and " - "localparam in '" << pform_cur_module->mod_name() + << "localparam in '" << pform_cur_module.front()->mod_name() + << "' have the same name '" << name << "'." << endl; + error_count += 1; + } + + if ((! pform_cur_module.empty()) && + (scope == pform_cur_module.front()) && + (pform_cur_module.front()->specparams.find(name) != pform_cur_module.front()->specparams.end())) { + LineInfo tloc; + FILE_NAME(&tloc, loc); + cerr << tloc.get_fileline() << ": error: specparam and " + "localparam in '" << pform_cur_module.front()->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } @@ -2403,25 +2575,70 @@ void pform_set_localparam(const struct vlltype&loc, parm.range = 0; } -void pform_set_specparam(perm_string name, PExpr*expr) +void pform_set_specparam(const struct vlltype&loc, perm_string name, + list*range, PExpr*expr) { + assert(! pform_cur_module.empty()); + Module*scope = pform_cur_module.front(); + assert(scope == lexical_scope); + // Check if the specparam name is already in the dictionary. - if (pform_cur_module->specparams.find(name) != - pform_cur_module->specparams.end()) { - cerr << expr->get_fileline() << ": error: duplicate definition " + if (pform_cur_module.front()->specparams.find(name) != + pform_cur_module.front()->specparams.end()) { + LineInfo tloc; + FILE_NAME(&tloc, loc); + cerr << tloc.get_fileline() << ": error: duplicate definition " "for specparam '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << pform_cur_module.front()->mod_name() << "'." << endl; + error_count += 1; + } + if (scope->parameters.find(name) != scope->parameters.end()) { + LineInfo tloc; + FILE_NAME(&tloc, loc); + cerr << tloc.get_fileline() << ": error: parameter and " + "specparam in '" << pform_cur_module.front()->mod_name() + << "' have the same name '" << name << "'." << endl; + error_count += 1; + } + if (scope->localparams.find(name) != scope->localparams.end()) { + LineInfo tloc; + FILE_NAME(&tloc, loc); + cerr << tloc.get_fileline() << ": error: localparam and " + "specparam in '" << pform_cur_module.front()->mod_name() + << "' have the same name '" << name << "'." << endl; error_count += 1; } assert(expr); - pform_cur_module->specparams[name] = expr; + + Module::param_expr_t&parm = pform_cur_module.front()->specparams[name]; + FILE_NAME(&parm, loc); + + parm.expr = expr; + + parm.type = IVL_VT_LOGIC; + if (range) { + 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; + } + parm.signed_flag = false; + parm.range = 0; } void pform_set_defparam(const pform_name_t&name, PExpr*expr) { assert(expr); - pform_cur_module->defparms.push_back(make_pair(name,expr)); + if (pform_cur_generate) + pform_cur_generate->defparms.push_back(make_pair(name,expr)); + else + pform_cur_module.front()->defparms.push_back(make_pair(name,expr)); } /* @@ -2488,7 +2705,7 @@ extern void pform_module_specify_path(PSpecPath*obj) { if (obj == 0) return; - pform_cur_module->specify_paths.push_back(obj); + pform_cur_module.front()->specify_paths.push_back(obj); } @@ -2537,7 +2754,7 @@ void pform_set_port_type(const struct vlltype&li, ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; pform_set_port_type(txt, pt, li.text, li.first_line); - pform_set_net_range(txt, range, signed_flag, IVL_VT_NO_TYPE, + pform_set_net_range(txt, NetNet::NONE, range, signed_flag, IVL_VT_NO_TYPE, SR_PORT, 0); } @@ -2596,9 +2813,9 @@ void pform_set_reg_time(list*names, list*attr) delete names; } -static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_string name, list*attr) +static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_string name, NetNet::Type net_type, list*attr) { - PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_BOOL); + PWire*cur = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_BOOL); assert(cur); cur->set_signed(signed_flag); @@ -2612,74 +2829,56 @@ static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_strin pform_bind_attributes(cur->attributes, attr, true); } -static void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names, list*attr) +static void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names, NetNet::Type net_type, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_integer_2atom(width, signed_flag, txt, attr); + pform_set_integer_2atom(width, signed_flag, txt, net_type, attr); } 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, list*attr) +template static void pform_set2_data_type(const struct vlltype&li, T*data_type, perm_string name, NetNet::Type net_type, list*attr) { - if (atom2_type_t*atom2_type = dynamic_cast (data_type)) { - pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names, attr); - return; + ivl_variable_type_t base_type = data_type->figure_packed_base_type(); + if (base_type == IVL_VT_NO_TYPE) { + VLerror(li, "Compound type is not PACKED in this context."); } - if (struct_type_t*struct_type = dynamic_cast (data_type)) { - pform_set_struct_type(struct_type, names, attr); - return; - } + PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type); + net->set_data_type(data_type); + pform_bind_attributes(net->attributes, attr, true); +} - if (enum_type_t*enum_type = dynamic_cast (data_type)) { - pform_set_enum(li, enum_type, names, attr); - return; +template static void pform_set2_data_type(const struct vlltype&li, T*data_type, list*names, NetNet::Type net_type, list*attr) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur) { + pform_set2_data_type(li, data_type, *cur, net_type, attr); } - - 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, attr); - return; - } - - if (/*real_type_t*real_type =*/ dynamic_cast (data_type)) { - pform_set_net_range(names, 0, true, IVL_VT_REAL, attr); - 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, std::list*attr) + perm_string name, NetNet::Type net_type, + std::list*attr) { (void) li; // The line information is not currently needed. - PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, enum_type->base_type); + PWire*cur = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, enum_type->base_type); assert(cur); cur->set_signed(enum_type->signed_flag); assert(enum_type->range.get() != 0); assert(enum_type->range->size() == 1); - cur->set_range(*enum_type->range, SR_NET); - cur->set_enumeration(enum_type); + //XXXXcur->set_range(*enum_type->range, SR_NET); + cur->set_data_type(enum_type); pform_bind_attributes(cur->attributes, attr, true); } -void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list*names, std::list*attr) +static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, + list*names, NetNet::Type net_type, + std::list*attr) { // By definition, the base type can only be IVL_VT_LOGIC or // IVL_VT_BOOL. @@ -2699,12 +2898,69 @@ void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list::iterator cur = names->begin() ; cur != names->end() ; ++ cur) { perm_string txt = *cur; - pform_set_enum(li, enum_type, txt, attr); + pform_set_enum(li, enum_type, txt, net_type, attr); } 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, NetNet::Type net_type, list*attr) +{ + if (data_type == 0) { + VLerror(li, "internal error: data_type==0."); + assert(0); + } + + if (atom2_type_t*atom2_type = dynamic_cast (data_type)) { + pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names, net_type, attr); + return; + } + + if (struct_type_t*struct_type = dynamic_cast (data_type)) { + pform_set_struct_type(struct_type, names, net_type, attr); + return; + } + + if (enum_type_t*enum_type = dynamic_cast (data_type)) { + pform_set_enum(li, enum_type, names, net_type, attr); + 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, net_type, attr); + return; + } + + if (/*real_type_t*real_type =*/ dynamic_cast (data_type)) { + pform_set_net_range(names, 0, true, IVL_VT_REAL, net_type, attr); + return; + } + + if (class_type_t*class_type = dynamic_cast (data_type)) { + pform_set_class_type(class_type, names, net_type, attr); + return; + } + + if (parray_type_t*array_type = dynamic_cast (data_type)) { + pform_set2_data_type(li, array_type, names, net_type, attr); + return; + } + + if (string_type_t*string_type = dynamic_cast (data_type)) { + pform_set_string_type(string_type, names, net_type, attr); + return; + } + + VLerror(li, "internal error: Unexpected data_type."); + assert(0); +} + svector* pform_make_udp_input_ports(list*names) { svector*out = new svector(names->size()); @@ -2733,6 +2989,14 @@ PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, pform_bind_attributes(pp->attributes, attr); pform_put_behavior_in_scope(pp); + + ivl_assert(*st, ! pform_cur_module.empty()); + if (pform_cur_module.front()->program_block && type == IVL_PR_ALWAYS) { + cerr << st->get_fileline() << ": error: Always statements not allowed" + << " in program blocks." << endl; + error_count += 1; + } + return pp; } @@ -2774,10 +3038,3 @@ int pform_parse(const char*path, FILE*file) destroy_lexor(); return error_count; } - -void pform_error_nested_modules() -{ - assert( pform_cur_module != 0 ); - cerr << pform_cur_module->get_fileline() << ": error: original module " - "(" << pform_cur_module->mod_name() << ") defined here." << endl; -} diff --git a/pform.h b/pform.h index c907c6b95..6a76664b1 100644 --- a/pform.h +++ b/pform.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "netlist.h" @@ -59,6 +59,7 @@ class PGate; class PExpr; class PSpecPath; class PClass; +class PPackage; struct vlltype; /* @@ -130,6 +131,10 @@ extern void pform_set_default_nettype(NetNet::Type net, const char*file, unsigned lineno); + /* Return true if currently processing a program block. This can be + used to reject statements that cannot exist in program blocks. */ +extern bool pform_in_program_block(void); + /* * Look for the given wire in the current lexical scope. If the wire * (including variables of any type) cannot be found in the current @@ -145,9 +150,13 @@ extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_ty * module has been noticed in the source file and the following events * are to apply to the scope of that module. The endmodule causes the * pform to close up and finish the named module. + * + * The program_flag indicates that the module is actually a program + * block. This has implications during parse and during + * elaboration/code generation. */ -extern void pform_startmodule(const char*, const char*file, unsigned lineno, - list*attr); +extern void pform_startmodule(const struct vlltype&loc, const char*name, + bool program_block, list*attr); extern void pform_check_timeunit_prec(); extern void pform_module_set_ports(vector*); @@ -160,6 +169,7 @@ extern void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, + data_type_t*vtype, list*range, list*attr); @@ -171,8 +181,16 @@ extern void pform_endmodule(const char*, bool inside_celldefine, extern void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type); +extern void pform_class_property(const struct vlltype&loc, + property_qualifier_t pq, + data_type_t*data_type, + std::list*decls); extern void pform_end_class_declaration(void); +extern void pform_start_package_declaration(const struct vlltype&loc, + const char*type); +extern void pform_end_package_declaration(const struct vlltype&loc); + extern void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, Statement*init, @@ -193,6 +211,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 PPackage* pform_push_package_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, @@ -254,21 +273,13 @@ 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, - bool signed_flag, list*delay, str_pair_t str, net_decl_assign_t*assign_list, NetNet::Type type, - ivl_variable_type_t); + data_type_t*data_type); /* This form handles nets declared as structures. (See pform_struct_type.cc) */ extern void pform_makewire(const struct vlltype&li, @@ -289,22 +300,19 @@ extern void pform_set_port_type(const struct vlltype&li, bool signed_flag, NetNet::PortType); -extern void pform_set_net_range(list*names, - list*, - bool signed_flag, - ivl_variable_type_t, - std::list*attr); -extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); +extern void pform_set_reg_idx(perm_string name, + std::list*indices); extern void pform_set_reg_integer(list*names, list*attr); extern void pform_set_reg_time(list*names, list*attr); -//XXXXextern 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, NetNet::Type net_type, list*attr); -extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list*names, list*attr); +extern void pform_set_struct_type(struct_type_t*struct_type, std::list*names, NetNet::Type net_type, std::list*attr); -extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list*names, std::list*attr); +extern void pform_set_string_type(string_type_t*string_type, std::list*names, NetNet::Type net_type, std::list*attr); + +extern void pform_set_class_type(class_type_t*class_type, std::list*names, NetNet::Type net_type, std::list*addr); -extern void pform_set_struct_type(struct_type_t*struct_type, std::list*names, std::list*attr); /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to @@ -331,13 +339,15 @@ extern void pform_set_localparam(const struct vlltype&loc, bool signed_flag, list*range, PExpr*expr); +extern void pform_set_specparam(const struct vlltype&loc, + perm_string name, + list*range, + PExpr*expr); extern void pform_set_defparam(const pform_name_t&name, PExpr*expr); /* * Functions related to specify blocks. */ -extern void pform_set_specparam(perm_string name, PExpr*expr); - extern PSpecPath*pform_make_specify_path(const struct vlltype&li, list*src, char pol, bool full_flag, list*dst); @@ -371,13 +381,15 @@ extern void pform_make_reals(list*names, * The makegate function creates a new gate (which need not have a * name) and connects it to the specified wires. */ -extern void pform_makegates(PGBuiltin::Type type, +extern void pform_makegates(const struct vlltype&loc, + PGBuiltin::Type type, struct str_pair_t str, list*delay, svector*gates, list*attr); -extern void pform_make_modgates(perm_string type, +extern void pform_make_modgates(const struct vlltype&loc, + perm_string type, struct parmvalue_t*overrides, svector*gates); @@ -418,12 +430,6 @@ extern PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, */ extern void pform_dump(ostream&out, Module*mod); -/* - * Used to report the original module location when a nested module - * (missing endmodule) is found by the parser. - */ -extern void pform_error_nested_modules(); - /* ** pform_discipline.cc * Functions for handling the parse of natures and disciplines. These * functions are in pform_disciplines.cc diff --git a/pform_analog.cc b/pform_analog.cc index 81571dfdd..0ff9647a5 100644 --- a/pform_analog.cc +++ b/pform_analog.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/pform_class_type.cc b/pform_class_type.cc new file mode 100644 index 000000000..44f0d3555 --- /dev/null +++ b/pform_class_type.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012 Picture Elements, Inc. + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "pform.h" +# include "parse_misc.h" +# include "ivl_assert.h" + +static void pform_set_class_type(class_type_t*class_type, perm_string name, NetNet::Type net_type, list*attr) +{ + PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_CLASS); + net->set_data_type(class_type); + pform_bind_attributes(net->attributes, attr, true); +} + +void pform_set_class_type(class_type_t*class_type, list*names, NetNet::Type net_type, list*attr) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur) { + pform_set_class_type(class_type, *cur, net_type, attr); + } +} diff --git a/pform_disciplines.cc b/pform_disciplines.cc index 91f6193fe..bc738fb9d 100644 --- a/pform_disciplines.cc +++ b/pform_disciplines.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/pform_dump.cc b/pform_dump.cc index f5859b69a..bbbbc50d8 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -26,6 +26,7 @@ * module in question. */ # include "pform.h" +# include "PClass.h" # include "PEvent.h" # include "PGenerate.h" # include "PSpec.h" @@ -146,6 +147,46 @@ void data_type_t::pform_dump(ostream&out, unsigned indent) const out << setw(indent) << "" << typeid(*this).name() << endl; } +void parray_type_t::pform_dump(ostream&out, unsigned indent) const +{ + out << setw(indent) << "" << "Packed array " << "[...]" + << " of:" << endl; + base_type->pform_dump(out, indent+4); +} + +void struct_type_t::pform_dump(ostream&out, unsigned indent) const +{ + out << setw(indent) << "" << "Struct " << (packed_flag?"packed":"unpacked") + << " with " << members->size() << " members" << endl; + for (list::iterator cur = members->begin() + ; cur != members->end() ; ++ cur) { + struct_member_t*curp = *cur; + curp->pform_dump(out, indent+4); + } +} + +void class_type_t::pform_dump(ostream&out, unsigned indent) const +{ + out << setw(indent) << "" << "class " << name << " {"; + + for (map::const_iterator cur = properties.begin() + ; cur != properties.end() ; ++cur) { + out << " " << cur->first; + } + out << " }" << endl; +} + +void struct_member_t::pform_dump(ostream&out, unsigned indent) const +{ + out << setw(indent) << "" << type; + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++cur) { + decl_assignment_t*curp = *cur; + out << " " << curp->name; + } + out << ";" << endl; +} + static void dump_attributes_map(ostream&out, const map&attributes, int ind) @@ -233,6 +274,21 @@ void PEFNumber::dump(ostream &out) const out << value(); } +void PENew::dump(ostream&out) const +{ + out << "new [" << *size_ << "]"; +} + +void PENewClass::dump(ostream&out) const +{ + out << "class_new"; +} + +void PENull::dump(ostream&out) const +{ + out << "null"; +} + void PENumber::dump(ostream&out) const { out << value(); @@ -376,15 +432,20 @@ void PWire::dump(ostream&out, unsigned ind) const out << " " << name_; - // If the wire has indices, dump them. - if (lidx_ || ridx_) { + // If the wire has unpacked indices, dump them. + for (list::const_iterator cur = unpacked_.begin() + ; cur != unpacked_.end() ; ++cur) { out << "["; - if (lidx_) out << *lidx_; - if (ridx_) out << ":" << *ridx_; + if (cur->first) out << *cur->first; + if (cur->second) out << ":" << *cur->second; out << "]"; } out << ";" << endl; + if (set_data_type_) { + set_data_type_->pform_dump(out, 8); + } + dump_attributes_map(out, attributes, 8); } @@ -1046,6 +1107,16 @@ void PGenerate::dump(ostream&out, unsigned indent) const dump_localparams_(out, indent+2); + typedef list::const_iterator parm_hiter_t; + for (parm_hiter_t cur = defparms.begin() + ; cur != defparms.end() ; ++ cur ) { + out << setw(indent+2) << "" << "defparam " << (*cur).first << " = "; + if ((*cur).second) + out << *(*cur).second << ";" << endl; + else + out << "/* ERROR */;" << endl; + } + dump_events_(out, indent+2); dump_wires_(out, indent+2); @@ -1194,6 +1265,40 @@ void LexicalScope::dump_wires_(ostream&out, unsigned indent) const } } +void PScopeExtra::dump_classes_(ostream&out, unsigned indent) const +{ + // Dump the task definitions. + typedef map::const_iterator class_iter_t; + for (class_iter_t cur = classes.begin() + ; cur != classes.end() ; ++ cur ) { + cur->second->dump(out, indent); + } +} + +void PClass::dump(ostream&out, unsigned indent) const +{ + out << setw(indent) << "" << "class " << type->name << ";" << endl; + type->pform_dump(out, indent+2); + out << setw(indent) << "" << "endclass" << endl; +} + +void Module::dump_specparams_(ostream&out, unsigned indent) const +{ + typedef map::const_iterator parm_iter_t; + for (parm_iter_t cur = specparams.begin() + ; cur != specparams.end() ; ++ cur ) { + out << setw(indent) << "" << "specparam "; + if ((*cur).second.msb) + out << "[" << *(*cur).second.msb << ":" + << *(*cur).second.lsb << "] "; + out << (*cur).first << " = "; + if ((*cur).second.expr) + out << *(*cur).second.expr << ";" << endl; + else + out << "/* ERROR */;" << endl; + } +} + void Module::dump(ostream&out) const { if (attributes.begin() != attributes.end()) { @@ -1231,14 +1336,23 @@ void Module::dump(ostream&out) const out << ")" << endl; } + for (map::const_iterator cur = nested_modules.begin() + ; cur != nested_modules.end() ; ++cur) { + out << setw(4) << "" << "Nested module " << cur->first << ";" << endl; + } + dump_typedefs_(out, 4); dump_parameters_(out, 4); dump_localparams_(out, 4); + dump_specparams_(out, 4); + dump_enumerations_(out, 4); + dump_classes_(out, 4); + typedef map::const_iterator genvar_iter_t; for (genvar_iter_t cur = genvars.begin() ; cur != genvars.end() ; ++ cur ) { @@ -1251,13 +1365,6 @@ void Module::dump(ostream&out) const (*cur)->dump(out, 4); } - typedef map::const_iterator specparm_iter_t; - for (specparm_iter_t cur = specparams.begin() - ; cur != specparams.end() ; ++ cur ) { - out << " specparam " << (*cur).first << " = " - << *(*cur).second << ";" << endl; - } - typedef list::const_iterator parm_hiter_t; for (parm_hiter_t cur = defparms.begin() ; cur != defparms.end() ; ++ cur ) { diff --git a/pform_package.cc b/pform_package.cc new file mode 100644 index 000000000..e760c578e --- /dev/null +++ b/pform_package.cc @@ -0,0 +1,42 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "pform.h" +# include "PPackage.h" +# include "parse_misc.h" +# include "ivl_assert.h" + +static PPackage*pform_cur_package = 0; + +void pform_start_package_declaration(const struct vlltype&loc, const char*name) +{ + VLerror(loc, "sorry: Package declarations not supported."); + ivl_assert(loc, pform_cur_package == 0); + + perm_string use_name = lex_strings.make(name); + PPackage*pkg_scope = pform_push_package_scope(loc, use_name); + pform_cur_package = pkg_scope; +} + +void pform_end_package_declaration(const struct vlltype&loc) +{ + ivl_assert(loc, pform_cur_package); + pform_cur_package = 0; + pform_pop_scope(); +} diff --git a/pform_pclass.cc b/pform_pclass.cc index 935734a62..382d3b44f 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -14,21 +14,53 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "pform.h" # include "PClass.h" +# include "parse_misc.h" +/* + * The functions here help the parser put together class type declarations. + */ 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); + class_scope->type = type; assert(pform_cur_class == 0); pform_cur_class = class_scope; } +void pform_class_property(const struct vlltype&loc, + property_qualifier_t property_qual, + data_type_t*data_type, + list*decls) +{ + assert(pform_cur_class); + + if (property_qual.test_static()) { + // I think the thing to do with static properties is to + // make them PWires directly in the PClass scope. They + // are wires like program/modules wires, and not + // instance members. + VLerror(loc, "sorry: static class properties not implemented."); + return; + } + + // Add the non-static properties to the class type + // object. Unwind the list of names to make a map of name to + // type. + for (list::iterator cur = decls->begin() + ; cur != decls->end() ; ++cur) { + + decl_assignment_t*curp = *cur; + pform_cur_class->type->properties[curp->name] = data_type; + } +} + void pform_end_class_declaration(void) { assert(pform_cur_class); diff --git a/pform_string_type.cc b/pform_string_type.cc new file mode 100644 index 000000000..593950af5 --- /dev/null +++ b/pform_string_type.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "pform.h" +# include "parse_misc.h" +# include "ivl_assert.h" + +static void pform_set_string_type(string_type_t*string_type, perm_string name, NetNet::Type net_type, list*attr) +{ + PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING); + pform_bind_attributes(net->attributes, attr, true); +} + +void pform_set_string_type(string_type_t*string_type, list*names, NetNet::Type net_type, list*attr) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur) { + pform_set_string_type(string_type, *cur, net_type, attr); + } +} + diff --git a/pform_struct_type.cc b/pform_struct_type.cc index 16ef1debd..b03b45554 100644 --- a/pform_struct_type.cc +++ b/pform_struct_type.cc @@ -14,19 +14,22 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 struct_type_t::figure_packed_base_type(void) const { + if (! packed_flag) + return IVL_VT_NO_TYPE; + ivl_variable_type_t base_type = IVL_VT_BOOL; - for (list::iterator cur = struct_type->members->begin() - ; cur != struct_type->members->end() ; ++ cur) { + for (list::iterator cur = members->begin() + ; cur != members->end() ; ++ cur) { struct_member_t*tmp = *cur; @@ -48,19 +51,19 @@ static ivl_variable_type_t figure_struct_base_type(struct_type_t*struct_type) * 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, list*attr) +static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list*attr) { - ivl_variable_type_t base_type = figure_struct_base_type(struct_type); + ivl_variable_type_t base_type = struct_type->figure_packed_base_type(); - PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, base_type); - net->set_struct_type(struct_type); + PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type); + net->set_data_type(struct_type); pform_bind_attributes(net->attributes, attr, true); } -static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, list*attr) +static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, NetNet::Type net_type, list*attr) { if (struct_type->packed_flag) { - pform_set_packed_struct(struct_type, name, attr); + pform_set_packed_struct(struct_type, name, net_type, attr); return; } @@ -68,11 +71,11 @@ static void pform_set_struct_type(struct_type_t*struct_type, perm_string name, l ivl_assert(*struct_type, 0); } -void pform_set_struct_type(struct_type_t*struct_type, list*names, list*attr) +void pform_set_struct_type(struct_type_t*struct_type, list*names, NetNet::Type net_type, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur) { - pform_set_struct_type(struct_type, *cur, attr); + pform_set_struct_type(struct_type, *cur, net_type, attr); } } @@ -82,11 +85,11 @@ static void pform_makewire(const struct vlltype&li, perm_string name, list*) { - ivl_variable_type_t base_type = figure_struct_base_type(struct_type); + ivl_variable_type_t base_type = struct_type->figure_packed_base_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); + cur->set_data_type(struct_type); } void pform_makewire(const struct vlltype&li, diff --git a/pform_types.cc b/pform_types.cc index 9a85b5b7e..5a7868bef 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -23,3 +23,22 @@ data_type_t::~data_type_t() { } + +string_type_t::~string_type_t() +{ +} + +ivl_variable_type_t data_type_t::figure_packed_base_type(void) const +{ + return IVL_VT_NO_TYPE; +} + +ivl_variable_type_t parray_type_t::figure_packed_base_type(void) const +{ + return base_type->figure_packed_base_type(); +} + +ivl_variable_type_t vector_type_t::figure_packed_base_type(void) const +{ + return base_type; +} diff --git a/pform_types.h b/pform_types.h index ed3f20f53..8af2d3c6e 100644 --- a/pform_types.h +++ b/pform_types.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // This for the perm_string type. @@ -34,7 +34,10 @@ * parse-form types. */ +class Design; +class NetScope; class PExpr; +class ivl_type_s; typedef named named_number_t; typedef named named_pexpr_t; typedef std::pair pform_range_t; @@ -69,11 +72,16 @@ struct decl_assignment_t { * "data_type" rule in the parse rule. We make the type virtual so * that dynamic types will work. */ -struct data_type_t : public LineInfo { +class data_type_t : public LineInfo { + public: virtual ~data_type_t() = 0; - + // This method is used to figure out the base type of a packed + // compound object. Return IVL_VT_NO_TYPE if the type is not packed. + virtual ivl_variable_type_t figure_packed_base_type(void)const; // This method is used by the pform dumper to diagnostic dump. virtual void pform_dump(std::ostream&out, unsigned indent) const; + // Elaborate the type to an ivl_type_s type. + virtual ivl_type_s* elaborate_type(Design*des, NetScope*scope) const; }; /* @@ -94,9 +102,13 @@ struct struct_member_t : public LineInfo { ivl_variable_type_t type; std::auto_ptr< list > range; std::auto_ptr< list > names; + void pform_dump(std::ostream&out, unsigned indent) const; }; struct struct_type_t : public data_type_t { + virtual ivl_variable_type_t figure_packed_base_type(void)const; + virtual void pform_dump(std::ostream&out, unsigned indent) const; + bool packed_flag; std::auto_ptr< list > members; }; @@ -106,27 +118,111 @@ struct atom2_type_t : public data_type_t { : type_code(tc), signed_flag(flag) { } int type_code; bool signed_flag; + + ivl_type_s* elaborate_type(Design*des, NetScope*scope) const; }; +/* + * The vector_type_t class represents types in the old Verilog + * way. Some typical examples: + * + * logic signed [7:0] foo + * bit unsigned foo + * reg foo + * + * There are a few special cases: + * + * For the most part, Verilog treats "logic" and "reg" as synonyms, + * but there are a few cases where the parser needs to know the + * difference. So "reg_flag" is set to true if the IVL_VT_LOGIC type + * is due to the "reg" keyword. + * + * If there are no reg/logic/bit/bool keywords, then Verilog will + * assume the type is logic, but the context may need to know about + * this case, so the implicit_flag member is set to true in that case. + */ 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) { } + : base_type(bt), signed_flag(sf), reg_flag(false), implicit_flag(false), pdims(pd) { } + virtual ivl_variable_type_t figure_packed_base_type(void)const; + ivl_variable_type_t base_type; bool signed_flag; + bool reg_flag; // True if "reg" was used + bool implicit_flag; // True if this type is implicitly logic/reg std::auto_ptr< list > pdims; }; +/* + * The array_type_t is a generalization of the vector_type_t in that + * the base type is another general data type. Ultimately, the subtype + * must also be packed (as this is a packed array) but that may be + * worked out during elaboration. + */ +struct parray_type_t : public data_type_t { + inline explicit parray_type_t(data_type_t*btype, std::list*pd) + : base_type(btype), packed_dims(pd) { } + virtual ivl_variable_type_t figure_packed_base_type(void)const; + virtual void pform_dump(std::ostream&out, unsigned indent) const; + + data_type_t*base_type; + std::auto_ptr< list > packed_dims; +}; + struct real_type_t : public data_type_t { - inline explicit real_type_t(int tc) : type_code(tc) { } - int type_code; + enum type_t { REAL, SHORTREAL }; + inline explicit real_type_t(type_t tc) : type_code(tc) { } + type_t type_code; +}; + +struct string_type_t : public data_type_t { + inline explicit string_type_t() { } + ~string_type_t(); }; struct class_type_t : public data_type_t { + inline explicit class_type_t(perm_string n) : name(n) { } + void pform_dump(std::ostream&out, unsigned indent) const; + perm_string name; + + std::map properties; +}; + +class property_qualifier_t { + public: + static inline property_qualifier_t set_none() + { property_qualifier_t res; res.mask_ = 0; return res; } + + static inline property_qualifier_t set_static() + { property_qualifier_t res; res.mask_ = 1; return res; } + + static inline property_qualifier_t set_protected() + { property_qualifier_t res; res.mask_ = 2; return res; } + + static inline property_qualifier_t set_local() + { property_qualifier_t res; res.mask_ = 4; return res; } + + static inline property_qualifier_t set_rand() + { property_qualifier_t res; res.mask_ = 8; return res; } + + static inline property_qualifier_t set_randc() + { property_qualifier_t res; res.mask_ = 16; return res; } + + inline property_qualifier_t operator | (property_qualifier_t r) + { property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; } + + public: + inline bool test_static() const { return mask_ & 1; } + inline bool test_protected() const { return mask_ & 2; } + inline bool test_local() const { return mask_ & 4; } + + private: + int mask_; }; /* diff --git a/sv_vpi_user.h b/sv_vpi_user.h index 606f7f73f..ccdc21be5 100644 --- a/sv_vpi_user.h +++ b/sv_vpi_user.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vpi_user.h" @@ -48,12 +48,17 @@ EXTERN_C_START #define vpiIntVar 612 #define vpiByteVar 614 #define vpiLogicVar vpiReg +#define vpiClassVar 615 +#define vpiStringVar 616 #define vpiBitVar 620 +#define vpiArrayVar vpiRegArray /********* TYPESPECS *************/ #define vpiEnumTypespec 633 #define vpiEnumConst 634 +#define vpiClassDefn 652 + /********* One-to-One ***********/ #define vpiBaseTypespec 703 diff --git a/svector.h b/svector.h index 8681e510d..2e9a1d3ab 100644 --- a/svector.h +++ b/svector.h @@ -18,7 +18,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/symbol_search.cc b/symbol_search.cc index d2d6b118c..05cfdc7f7 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 @@ -14,17 +15,150 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "netlist.h" # include "netmisc.h" -# include +# include "ivl_assert.h" /* * Search for the hierarchical name. */ +struct symbol_search_results { + inline symbol_search_results() { + scope = 0; + net = 0; + par_val = 0; + par_msb = 0; + par_lsb = 0; + eve = 0; + } + + inline bool is_scope() const { + if (net) return false; + if (eve) return false; + if (par_val) return false; + if (scope) return true; + return false; + } + + // Scope where symbol was located. This is set in all cases, + // assuming the search succeeded. + NetScope*scope; + // If this was a net, the signal itself. + NetNet*net; + // If this was a parameter, the value expression and the + // optional value dimensions. + const NetExpr*par_val; + const NetExpr*par_msb; + const NetExpr*par_lsb; + // If this is a named event, ... + NetEvent*eve; +}; + +bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, + pform_name_t path, struct symbol_search_results*res, + NetScope*start_scope = 0) +{ + assert(scope); + bool prefix_scope = false; + bool recurse_flag = false; + name_component_t path_tail = path.back(); + path.pop_back(); + + // If this is a recursive call, then we need to know that so + // that we can enable the search for scopes. Set the + // recurse_flag to true if this is a recurse. + if (start_scope==0) + start_scope = scope; + else + recurse_flag = true; + + // If there are components ahead of the tail, symbol_search + // recursively. Ideally, the result is a scope that we search + // for the tail key, but there are other special cases as well. + if (! path.empty()) { + symbol_search_results recurse; + bool flag = symbol_search(li, des, scope, path, &recurse, start_scope); + if (! flag) + return false; + + // The prefix is found to be a scope, so switch to that + // scoke, set the hier_path to turn of upwards searches, + // and continue our search for the tail. + if (recurse.is_scope()) { + scope = recurse.scope; + prefix_scope = true; + + if (scope->is_auto() && li) { + cerr << li->get_fileline() << ": error: Hierarchical " + "reference to automatically allocated item " + "`" << path_tail.name << "' in path `" << path << "'" << endl; + des->errors += 1; + } + } + } + + while (scope) { + if (NetNet*net = scope->find_signal(path_tail.name)) { + res->scope = scope; + res->net = net; + return true; + } + + if (NetEvent*eve = scope->find_event(path_tail.name)) { + res->scope = scope; + res->eve = eve; + return true; + } + + if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->par_msb, res->par_lsb)) { + res->scope = scope; + res->par_val = par; + return true; + } + + if (recurse_flag) { + bool flag = false; + hname_t path_item = eval_path_component(des, start_scope, path_tail, flag); + if (flag) { + cerr << li->get_fileline() << ": XXXXX: Errors evaluating scope index" << endl; + } else if (NetScope*chld = des->find_scope(scope, path_item)) { + res->scope = chld; + return true; + } + } + + // Don't scan up past a module boundary. + if (scope->type()==NetScope::MODULE && !scope->nested_module()) + break; + // Don't scan up if we are searching within a prefixed scope. + if (prefix_scope) + break; + + scope = scope->parent(); + } + + // Last chance: this is a single name, so it might be the name + // of a root scope. Ask the design if this is a root + // scope. This is only possible if there is no prefix. + if (prefix_scope==false) { + hname_t path_item (path_tail.name); + scope = des->find_scope(path_item); + if (scope) { + res->scope = scope; + return true; + } + } + + return false; +} + +/* + * Compatibility version. Remove me! + */ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope, pform_name_t path, NetNet*&net, @@ -32,58 +166,19 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope, NetEvent*&eve, const NetExpr*&ex1, const NetExpr*&ex2) { - assert(scope); - bool hier_path = false; - - /* Get the tail name of the object we are looking for. */ - perm_string key = peek_tail_name(path); - path.pop_back(); - - /* Initialize output argument to cleared. */ - net = 0; - par = 0; - eve = 0; - - /* If the path has a scope part, then search for the specified - scope that we are supposed to search. */ - if (! path.empty()) { - list path_list = eval_scope_path(des, scope, path); - assert(path_list.size() <= path.size()); - - // If eval_scope_path returns a short list, then some - // part of the scope was not found. Abort. - if (path_list.size() < path.size()) - return 0; - - scope = des->find_scope(scope, path_list); - - if (scope && scope->is_auto() && li) { - cerr << li->get_fileline() << ": error: Hierarchical " - "reference to automatically allocated item " - "`" << key << "' in path `" << path << "'" << endl; - des->errors += 1; - } - - hier_path = true; + symbol_search_results recurse; + bool flag = symbol_search(li, des, scope, path, &recurse); + if (! flag) { + return 0; } - while (scope) { - if ( (net = scope->find_signal(key)) ) - return scope; + if (recurse.is_scope()) + return recurse.scope; - if ( (eve = scope->find_event(key)) ) - return scope; - - if ( (par = scope->get_parameter(des, key, ex1, ex2)) ) - return scope; - - /* We can't look up if we are at the enclosing module scope - * or if a hierarchical path was given. */ - if ((scope->type() == NetScope::MODULE) || hier_path) - scope = 0; - else - scope = scope->parent(); - } - - return 0; + net = recurse.net; + par = recurse.par_val; + ex1 = recurse.par_msb; + ex2 = recurse.par_lsb; + eve = recurse.eve; + return recurse.scope; } diff --git a/syn-rules.y b/syn-rules.y index ebd3aa50b..1507b08df 100644 --- a/syn-rules.y +++ b/syn-rules.y @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/sync.cc b/sync.cc index 019034713..1b3a62d88 100644 --- a/sync.cc +++ b/sync.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/synth.cc b/synth.cc index 0617bae76..3e4c85a1d 100644 --- a/synth.cc +++ b/synth.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/synth2.cc b/synth2.cc index 9adc21f5d..f1e8d6371 100644 --- a/synth2.cc +++ b/synth2.cc @@ -14,13 +14,14 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include "functor.h" # include "netlist.h" +# include "netvector.h" # include "netmisc.h" # include "compiler.h" # include @@ -221,10 +222,10 @@ bool NetCase::synth_async(Design*des, NetScope*scope, continue; } + netvector_t*isig_vec = new netvector_t(mux_data_type, mux_width-1, 0); isig = new NetNet(scope, scope->local_symbol(), - NetNet::TRI, mux_width); + NetNet::TRI, isig_vec); isig->local_flag(true); - isig->data_type(mux_data_type); connect(mux->pin_Data(idx), isig->pin(0)); diff --git a/sys_funcs.cc b/sys_funcs.cc index 56e6ab523..8e13ddede 100644 --- a/sys_funcs.cc +++ b/sys_funcs.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/t-dll-analog.cc b/t-dll-analog.cc index 26f21abe0..e254f8dd8 100644 --- a/t-dll-analog.cc +++ b/t-dll-analog.cc @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/t-dll-api.cc b/t-dll-api.cc index 008847127..52060e793 100644 --- a/t-dll-api.cc +++ b/t-dll-api.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 @@ -14,14 +14,17 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include "StringHeap.h" # include "t-dll.h" # include "discipline.h" +# include "netclass.h" +# include "netdarray.h" # include "netenum.h" +# include "netvector.h" # include # include # include @@ -259,13 +262,13 @@ extern "C" ivl_variable_type_t ivl_enum_type(ivl_enumtype_t net) extern "C" unsigned ivl_enum_width(ivl_enumtype_t net) { assert(net); - return net->base_width(); + return net->packed_width(); } extern "C" int ivl_enum_signed(ivl_enumtype_t net) { assert(net); - return net->has_sign(); + return net->get_signed(); } extern "C" const char*ivl_enum_file(ivl_enumtype_t net) @@ -411,6 +414,11 @@ extern "C" ivl_enumtype_t ivl_expr_enumtype(ivl_expr_t net) return net->u_.enumtype_.type; } +extern "C" ivl_type_t ivl_expr_net_type(ivl_expr_t net) +{ + return net->net_type; +} + extern "C" const char* ivl_expr_name(ivl_expr_t net) { switch (net->type_) { @@ -421,6 +429,13 @@ extern "C" const char* ivl_expr_name(ivl_expr_t net) case IVL_EX_SIGNAL: return net->u_.signal_.sig->name_; + case IVL_EX_PROPERTY: + { ivl_signal_t sig = ivl_expr_signal(net); + ivl_type_t use_type = ivl_signal_net_type(sig); + unsigned idx = ivl_expr_property_idx(net); + return ivl_type_prop_name(use_type, idx); + } + default: assert(0); } @@ -465,6 +480,9 @@ extern "C" ivl_expr_t ivl_expr_oper1(ivl_expr_t net) case IVL_EX_MEMORY: return net->u_.memory_.idx_; + case IVL_EX_NEW: + return net->u_.new_.size; + case IVL_EX_SIGNAL: return net->u_.signal_.word; @@ -584,6 +602,13 @@ extern "C" ivl_event_t ivl_expr_event(ivl_expr_t net) return net->u_.event_.event; } +extern "C" int ivl_expr_property_idx(ivl_expr_t net) +{ + assert(net); + assert(net->type_ == IVL_EX_PROPERTY); + return net->u_.property_.prop_idx; +} + extern "C" ivl_scope_t ivl_expr_scope(ivl_expr_t net) { assert(net); @@ -607,6 +632,9 @@ extern "C" ivl_signal_t ivl_expr_signal(ivl_expr_t net) case IVL_EX_ARRAY: return net->u_.signal_.sig; + case IVL_EX_PROPERTY: + return net->u_.property_.sig; + default: assert(0); return 0; @@ -1422,7 +1450,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) case IVL_LPM_REPEAT: return 0; case IVL_LPM_ARRAY: // Array ports take the signedness of the array. - return net->u_.array.sig->signed_; + return net->u_.array.sig->net_type->get_signed()? 1 : 0; default: assert(0); return 0; @@ -1544,6 +1572,12 @@ extern "C" unsigned ivl_lval_width(ivl_lval_t net) return net->width_; } +extern "C" int ivl_lval_property_idx(ivl_lval_t net) +{ + assert(net); + return net->property_idx; +} + extern "C" ivl_signal_t ivl_lval_sig(ivl_lval_t net) { assert(net); @@ -1681,6 +1715,13 @@ extern "C" const char* ivl_parameter_basename(ivl_parameter_t net) return net->basename; } +extern "C" int ivl_parameter_local(ivl_parameter_t net) +{ + assert(net); + return net->local; +} + + extern "C" ivl_expr_t ivl_parameter_expr(ivl_parameter_t net) { assert(net); @@ -1823,6 +1864,18 @@ extern "C" int ivl_scope_children(ivl_scope_t net, return 0; } +extern "C" ivl_type_t ivl_scope_class(ivl_scope_t net, unsigned idx) +{ + assert(idx < net->classes.size()); + return net->classes[idx]; +} + +extern "C" unsigned ivl_scope_classes(ivl_scope_t net) +{ + return net->classes.size(); +} + + extern "C" ivl_statement_t ivl_scope_def(ivl_scope_t net) { assert(net); @@ -1979,6 +2032,40 @@ extern "C" ivl_scope_t ivl_scope_parent(ivl_scope_t net) return net->parent; } + +extern "C" unsigned ivl_scope_mod_module_ports(ivl_scope_t net) +{ + assert(net); + assert (net->type_ == IVL_SCT_MODULE ); + return static_cast(net->module_ports_info.size()); +} + +extern "C" const char *ivl_scope_mod_module_port_name(ivl_scope_t net, unsigned idx ) +{ + assert(net); + assert (net->type_ == IVL_SCT_MODULE ); + assert( idx < net->module_ports_info.size()); + + return net->module_ports_info[idx].name; +} + +extern "C" ivl_signal_port_t ivl_scope_mod_module_port_type(ivl_scope_t net, unsigned idx ) +{ + switch( net->module_ports_info[idx].type ) + { + case PortType::PINPUT : return IVL_SIP_INPUT; + case PortType::POUTPUT : return IVL_SIP_OUTPUT; + case PortType::PINOUT : return IVL_SIP_INOUT; + default : return IVL_SIP_NONE; + } +} + +extern "C" unsigned ivl_scope_mod_module_port_width(ivl_scope_t net, unsigned idx ) +{ + return net->module_ports_info[idx].width; +} + + extern "C" unsigned ivl_scope_ports(ivl_scope_t net) { assert(net); @@ -2008,13 +2095,13 @@ extern "C" ivl_nexus_t ivl_scope_mod_port(ivl_scope_t net, unsigned idx) extern "C" unsigned ivl_scope_sigs(ivl_scope_t net) { assert(net); - return net->nsigs_; + return net->sigs_.size(); } extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx) { assert(net); - assert(idx < net->nsigs_); + assert(idx < net->sigs_.size()); return net->sigs_[idx]; } @@ -2155,31 +2242,31 @@ extern "C" unsigned ivl_signal_packed_dimensions(ivl_signal_t net) 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; + return net->packed_dims[dim].get_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; + return net->packed_dims[dim].get_lsb(); } extern "C" int ivl_signal_msb(ivl_signal_t net) { - if (net->packed_dims.size() == 0) + if (net->packed_dims.empty()) return 0; assert(net->packed_dims.size() == 1); - return net->packed_dims[0].msb; + return net->packed_dims[0].get_msb(); } extern "C" int ivl_signal_lsb(ivl_signal_t net) { - if (net->packed_dims.size() == 0) + if (net->packed_dims.empty()) return 0; assert(net->packed_dims.size() == 1); - return net->packed_dims[0].lsb; + return net->packed_dims[0].get_lsb(); } extern "C" ivl_scope_t ivl_signal_scope(ivl_signal_t net) @@ -2190,7 +2277,7 @@ extern "C" ivl_scope_t ivl_signal_scope(ivl_signal_t net) extern "C" unsigned ivl_signal_width(ivl_signal_t net) { - return net->width_; + return net->net_type->packed_width(); } extern "C" ivl_signal_port_t ivl_signal_port(ivl_signal_t net) @@ -2198,6 +2285,11 @@ extern "C" ivl_signal_port_t ivl_signal_port(ivl_signal_t net) return net->port_; } +extern "C" int ivl_signal_module_port_index(ivl_signal_t net) +{ + return net->module_port_index_; +} + extern "C" int ivl_signal_local(ivl_signal_t net) { return net->local_; @@ -2205,7 +2297,7 @@ extern "C" int ivl_signal_local(ivl_signal_t net) extern "C" int ivl_signal_signed(ivl_signal_t net) { - return net->signed_; + return net->net_type->get_signed()? 1 : 0; } extern "C" unsigned ivl_signal_forced_net(ivl_signal_t net) @@ -2227,12 +2319,20 @@ extern "C" unsigned ivl_signal_lineno(ivl_signal_t net) extern "C" int ivl_signal_integer(ivl_signal_t net) { - return net->isint_; + if (const netvector_t*vec = dynamic_cast (net->net_type)) + return vec->get_isint()? 1 : 0; + else + return 0; } extern "C" ivl_variable_type_t ivl_signal_data_type(ivl_signal_t net) { - return net->data_type; + return net->net_type->base_type(); +} + +extern "C" ivl_type_t ivl_signal_net_type(ivl_signal_t net) +{ + return net->net_type; } extern "C" unsigned ivl_signal_npath(ivl_signal_t net) @@ -2271,6 +2371,8 @@ extern "C" ivl_scope_t ivl_stmt_block_scope(ivl_statement_t net) switch (net->type_) { case IVL_ST_BLOCK: case IVL_ST_FORK: + case IVL_ST_FORK_JOIN_ANY: + case IVL_ST_FORK_JOIN_NONE: return net->u_.block_.scope; default: assert(0); @@ -2283,6 +2385,8 @@ extern "C" unsigned ivl_stmt_block_count(ivl_statement_t net) switch (net->type_) { case IVL_ST_BLOCK: case IVL_ST_FORK: + case IVL_ST_FORK_JOIN_ANY: + case IVL_ST_FORK_JOIN_NONE: return net->u_.block_.nstmt_; default: assert(0); @@ -2296,6 +2400,8 @@ extern "C" ivl_statement_t ivl_stmt_block_stmt(ivl_statement_t net, switch (net->type_) { case IVL_ST_BLOCK: case IVL_ST_FORK: + case IVL_ST_FORK_JOIN_ANY: + case IVL_ST_FORK_JOIN_NONE: return net->u_.block_.stmt_ + i; default: assert(0); @@ -2721,3 +2827,72 @@ extern "C" unsigned ivl_switch_lineno(ivl_switch_t net) { return net->lineno; } + +extern "C" ivl_variable_type_t ivl_type_base(ivl_type_t net) +{ + if (net == 0) return IVL_VT_NO_TYPE; + else return net->base_type(); +} + +extern "C" ivl_type_t ivl_type_element(ivl_type_t net) +{ + if (const netarray_t*da = dynamic_cast (net)) + return da->element_type(); + + assert(0); + return 0; +} + +extern "C" unsigned ivl_type_packed_dimensions(ivl_type_t net) +{ + vector slice = net->slice_dimensions(); + return slice.size(); +} + +extern "C" int ivl_type_packed_lsb(ivl_type_t net, unsigned dim) +{ + vector slice = net->slice_dimensions(); + assert(dim < slice.size()); + return slice[dim].get_lsb(); +} + +extern "C" int ivl_type_packed_msb(ivl_type_t net, unsigned dim) +{ + vector slice = net->slice_dimensions(); + assert(dim < slice.size()); + return slice[dim].get_msb(); +} + +extern "C" const char* ivl_type_name(ivl_type_t net) +{ + if (const netclass_t*class_type = dynamic_cast(net)) { + return class_type->get_name(); + } + + return 0; +} + +extern "C" int ivl_type_properties(ivl_type_t net) +{ + const netclass_t*class_type = dynamic_cast(net); + assert(class_type); + + return class_type->get_properties(); +} + +extern "C" const char* ivl_type_prop_name(ivl_type_t net, int idx) +{ + if (idx < 0) return 0; + const netclass_t*class_type = dynamic_cast(net); + assert(class_type); + + return class_type->get_prop_name(idx); +} + +extern "C" ivl_type_t ivl_type_prop_type(ivl_type_t net, int idx) +{ + const netclass_t*class_type = dynamic_cast(net); + assert(class_type); + + return class_type->get_prop_type(idx); +} diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 0db2ffd62..8809dd177 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -24,6 +24,7 @@ # include # include "t-dll.h" # include "netlist.h" +# include "netclass.h" # include # include # include "ivl_alloc.h" @@ -56,6 +57,7 @@ void dll_target::sub_off_from_expr_(long off) ivl_expr_t tmpc = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmpc->type_ = IVL_EX_NUMBER; tmpc->value_ = IVL_VT_VECTOR; + tmpc->net_type= 0; tmpc->width_ = expr_->width_; tmpc->signed_ = expr_->signed_; tmpc->sized_ = 1; @@ -71,6 +73,7 @@ void dll_target::sub_off_from_expr_(long off) ivl_expr_t tmps = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmps->type_ = IVL_EX_BINARY; tmps->value_ = IVL_VT_VECTOR; + tmps->net_type= 0; tmps->width_ = tmpc->width_; tmps->signed_ = tmpc->signed_; tmps->sized_ = 1; @@ -90,6 +93,7 @@ void dll_target::mul_expr_by_const_(long val) ivl_expr_t tmpc = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmpc->type_ = IVL_EX_NUMBER; tmpc->value_ = IVL_VT_VECTOR; + tmpc->net_type= 0; tmpc->width_ = expr_->width_; tmpc->signed_ = expr_->signed_; tmpc->sized_ = 1; @@ -105,6 +109,7 @@ void dll_target::mul_expr_by_const_(long val) ivl_expr_t tmps = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmps->type_ = IVL_EX_BINARY; tmps->value_ = IVL_VT_VECTOR; + tmpc->net_type= 0; tmps->width_ = tmpc->width_; tmps->signed_ = tmpc->signed_; tmps->sized_ = 1; @@ -124,6 +129,7 @@ ivl_expr_t dll_target::expr_from_value_(const verinum&val) char*bits; expr->type_ = IVL_EX_NUMBER; expr->value_= IVL_VT_VECTOR; + expr->net_type=0; expr->width_= val.len(); expr->signed_ = val.has_sign()? 1 : 0; expr->sized_= 1; @@ -158,6 +164,7 @@ void dll_target::expr_access_func(const NetEAccess*net) expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_->type_ = IVL_EX_BACCESS; expr_->value_ = IVL_VT_REAL; + expr_->net_type=0; expr_->width_ = 1; expr_->signed_= 1; expr_->sized_ = 1; @@ -182,6 +189,7 @@ void dll_target::expr_binary(const NetEBinary*net) expr_->type_ = IVL_EX_BINARY; expr_->value_= get_expr_type(net); + expr_->net_type=0; expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->sized_= 1; @@ -200,7 +208,8 @@ void dll_target::expr_concat(const NetEConcat*net) assert(cur); cur->type_ = IVL_EX_CONCAT; - cur->value_ = IVL_VT_VECTOR; + cur->value_ = net->expr_type(); + cur->net_type=0; cur->width_ = net->expr_width(); cur->signed_ = net->has_sign() ? 1 : 0; cur->sized_ = 1; @@ -226,6 +235,7 @@ void dll_target::expr_const(const NetEConst*net) expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_->value_= net->expr_type(); + expr_->net_type=0; FILE_NAME(expr_, net); if (net->value().is_string()) { @@ -303,9 +313,59 @@ void dll_target::expr_creal(const NetECReal*net) expr_->type_ = IVL_EX_REALNUM; FILE_NAME(expr_, net); expr_->value_= IVL_VT_REAL; + expr_->net_type=0; expr_->u_.real_.value = net->value().as_double(); } +void dll_target::expr_new(const NetENew*net) +{ + ivl_expr_t size = 0; + if (net->size_expr()) { + net->size_expr()->expr_scan(this); + size = expr_; + expr_ = 0; + } + + assert(expr_ == 0); + expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); + expr_->width_ = net->expr_width(); + expr_->signed_ = 0; + expr_->sized_ = 1; + expr_->type_ = IVL_EX_NEW; + FILE_NAME(expr_, net); + expr_->value_ = net->expr_type(); // May be IVL_VT_DARRAY or _CLASS + expr_->net_type= net->get_type(); + expr_->u_.new_.size = size; +} + +void dll_target::expr_null(const NetENull*net) +{ + assert(expr_ == 0); + expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); + expr_->width_ = net->expr_width(); + expr_->signed_ = 0; + expr_->sized_ = 1; + expr_->type_ = IVL_EX_NULL; + FILE_NAME(expr_, net); + expr_->value_ = IVL_VT_CLASS; + expr_->net_type= 0; +} + +void dll_target::expr_property(const NetEProperty*net) +{ + assert(expr_ == 0); + expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); + expr_->width_ = net->expr_width(); + expr_->signed_ = net->has_sign(); + expr_->sized_ = 1; + expr_->type_ = IVL_EX_PROPERTY; + FILE_NAME(expr_, net); + expr_->value_ = net->expr_type(); + expr_->net_type= net->net_type(); + expr_->u_.property_.sig = find_signal(des_, net->get_sig()); + expr_->u_.property_.prop_idx = net->property_idx(); +} + void dll_target::expr_event(const NetEEvent*net) { assert(expr_ == 0); @@ -315,6 +375,7 @@ void dll_target::expr_event(const NetEEvent*net) expr_->type_ = IVL_EX_EVENT; FILE_NAME(expr_, net); expr_->value_= IVL_VT_VOID; + expr_->net_type=0; /* Locate the event by name. Save the ivl_event_t in the expression so that the generator can find it easily. */ @@ -339,6 +400,7 @@ void dll_target::expr_scope(const NetEScope*net) expr_->type_ = IVL_EX_SCOPE; FILE_NAME(expr_, net); expr_->value_= IVL_VT_VOID; + expr_->net_type=0; expr_->u_.scope_.scope = lookup_scope_(net->scope()); } @@ -351,6 +413,7 @@ void dll_target::expr_netenum(const NetENetenum*net) expr_->type_ = IVL_EX_ENUMTYPE; FILE_NAME(expr_, net); expr_->value_= IVL_VT_VOID; + expr_->net_type=0; expr_->u_.enumtype_.type = net->netenum(); } @@ -370,7 +433,8 @@ void dll_target::expr_select(const NetESelect*net) expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_->type_ = IVL_EX_SELECT; - expr_->value_= IVL_VT_VECTOR; + expr_->value_= net->expr_type(); + expr_->net_type=0; expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->sized_= 1; @@ -390,6 +454,7 @@ void dll_target::expr_sfunc(const NetESFunc*net) expr->type_ = IVL_EX_SFUNC; FILE_NAME(expr, net); expr->value_= net->expr_type(); + expr->net_type=net->net_type(); expr->width_= net->expr_width(); expr->signed_ = net->has_sign()? 1 : 0; expr->sized_= 1; @@ -420,6 +485,7 @@ void dll_target::expr_ternary(const NetETernary*net) expr->type_ = IVL_EX_TERNARY; expr->value_= net->expr_type(); + expr->net_type=0; expr->width_ = net->expr_width(); expr->signed_ = net->has_sign()? 1 : 0; expr->sized_ = 1; @@ -461,6 +527,7 @@ void dll_target::expr_signal(const NetESignal*net) expr_->type_ = IVL_EX_SIGNAL; expr_->value_= net->expr_type(); + expr_->net_type=0; expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->sized_= 1; @@ -488,6 +555,7 @@ void dll_target::expr_ufunc(const NetEUFunc*net) expr->type_ = IVL_EX_UFUNC; expr->value_= net->expr_type(); + expr->net_type=0; expr->width_= net->expr_width(); expr->signed_ = net->has_sign()? 1 : 0; expr->sized_= 1; @@ -523,6 +591,7 @@ void dll_target::expr_unary(const NetEUnary*net) expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_->type_ = IVL_EX_UNARY; expr_->value_= net->expr_type(); + expr_->net_type=0; expr_->width_ = net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->sized_ = 1; diff --git a/t-dll-proc.cc b/t-dll-proc.cc index fbc55464e..0cf6fe8bb 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.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 @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -27,6 +27,7 @@ # include "ivl_target.h" # include "compiler.h" # include "t-dll.h" +# include "netclass.h" # include # include "ivl_alloc.h" @@ -179,6 +180,14 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net) cur->idx = expr_; expr_ = 0; } + + cur->property_idx = -1; + perm_string pname = asn->get_property(); + if (!pname.nil()) { + const netclass_t*use_type = dynamic_cast (cur->n.sig->net_type); + cur->property_idx = use_type->property_idx_from_name(pname); + } + } else { assert(0); } @@ -386,9 +395,20 @@ bool dll_target::proc_block(const NetBlock*net) it, so fill in the block fields of the existing statement, and generate the contents for the statement array. */ - stmt_cur_->type_ = (net->type() == NetBlock::SEQU) - ? IVL_ST_BLOCK - : IVL_ST_FORK; + switch (net->type()) { + case NetBlock::SEQU: + stmt_cur_->type_ = IVL_ST_BLOCK; + break; + case NetBlock::PARA: + stmt_cur_->type_ = IVL_ST_FORK; + break; + case NetBlock::PARA_JOIN_ANY: + stmt_cur_->type_ = IVL_ST_FORK_JOIN_ANY; + break; + case NetBlock::PARA_JOIN_NONE: + stmt_cur_->type_ = IVL_ST_FORK_JOIN_NONE; + break; + } stmt_cur_->u_.block_.nstmt_ = count; stmt_cur_->u_.block_.stmt_ = (struct ivl_statement_s*) calloc(count, sizeof(struct ivl_statement_s)); diff --git a/t-dll.cc b/t-dll.cc index e6b44c75f..2af801995 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -25,6 +25,7 @@ # include // sprintf() # include "compiler.h" # include "t-dll.h" +# include "netclass.h" # include "netmisc.h" # include "discipline.h" # include @@ -257,7 +258,7 @@ ivl_signal_t dll_target::find_signal(ivl_design_s &des, const NetNet*net) perm_string nname = net->name(); - for (unsigned idx = 0 ; idx < scope->nsigs_ ; idx += 1) { + for (unsigned idx = 0 ; idx < scope->sigs_.size() ; idx += 1) { if (strcmp(scope->sigs_[idx]->name_, nname) == 0) return scope->sigs_[idx]; } @@ -396,11 +397,6 @@ void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net) } -static void scope_add_enumeration(ivl_scope_t scope, ivl_enumtype_t net) -{ - scope->enumerations_.push_back(net); -} - void scope_add_event(ivl_scope_t scope, ivl_event_t net) { if (scope->nevent_ == 0) { @@ -461,7 +457,7 @@ ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope, */ void dll_target::make_scope_parameters(ivl_scope_t scop, const NetScope*net) { - scop->nparam_ = net->parameters.size() + net->localparams.size(); + scop->nparam_ = net->parameters.size(); if (scop->nparam_ == 0) { scop->param_ = 0; return; @@ -478,19 +474,7 @@ void dll_target::make_scope_parameters(ivl_scope_t scop, const NetScope*net) assert(idx < scop->nparam_); ivl_parameter_t cur_par = scop->param_ + idx; cur_par->basename = (*cur_pit).first; - cur_par->scope = scop; - FILE_NAME(cur_par, &((*cur_pit).second)); - - NetExpr*etmp = (*cur_pit).second.val; - make_scope_param_expr(cur_par, etmp); - idx += 1; - } - for (pit_t cur_pit = net->localparams.begin() - ; cur_pit != net->localparams.end() ; ++ cur_pit ) { - - assert(idx < scop->nparam_); - ivl_parameter_t cur_par = scop->param_ + idx; - cur_par->basename = (*cur_pit).first; + cur_par->local = cur_pit->second.local_flag; cur_par->scope = scop; FILE_NAME(cur_par, &((*cur_pit).second)); @@ -545,8 +529,6 @@ void dll_target::add_root(ivl_design_s &des__, const NetScope *s) root_->name_ = name; FILE_NAME(root_, s); root_->parent = 0; - root_->nsigs_ = 0; - root_->sigs_ = 0; root_->nlog_ = 0; root_->log_ = 0; root_->nevent_ = 0; @@ -563,13 +545,14 @@ void dll_target::add_root(ivl_design_s &des__, const NetScope *s) root_->attr = fill_in_attributes(s); root_->is_auto = 0; root_->is_cell = s->is_cell(); - root_->ports = s->module_ports(); + root_->ports = s->module_port_nets(); if (root_->ports > 0) { root_->u_.net = new NetNet*[root_->ports]; for (unsigned idx = 0; idx < root_->ports; idx += 1) { - root_->u_.net[idx] = s->module_port(idx); + root_->u_.net[idx] = s->module_port_net(idx); } } + root_->module_ports_info = s->module_port_info(); des__.nroots_++; if (des__.roots_) @@ -799,10 +782,17 @@ bool dll_target::bufz(const NetBUFZ*net) return true; } +bool dll_target::class_type(const NetScope*in_scope, netclass_t*net) +{ + ivl_scope_t use_scope = find_scope(des_, in_scope); + use_scope->classes.push_back(net); + return true; +} + bool dll_target::enumeration(const NetScope*in_scope, netenum_t*net) { - ivl_scope_t scop = find_scope(des_, in_scope); - scope_add_enumeration(scop, net); + ivl_scope_t use_scope = find_scope(des_, in_scope); + use_scope->enumerations_.push_back(net); return true; } @@ -2291,8 +2281,6 @@ void dll_target::scope(const NetScope*net) scop->parent = find_scope(des_, net->parent()); assert(scop->parent); scop->parent->children[net->fullname()] = scop; - scop->nsigs_ = 0; - scop->sigs_ = 0; scop->nlog_ = 0; scop->log_ = 0; scop->nevent_ = 0; @@ -2312,14 +2300,16 @@ void dll_target::scope(const NetScope*net) case NetScope::MODULE: scop->type_ = IVL_SCT_MODULE; scop->tname_ = net->module_name(); - scop->ports = net->module_ports(); + scop->ports = net->module_port_nets(); if (scop->ports > 0) { scop->u_.net = new NetNet*[scop->ports]; for (unsigned idx = 0; idx < scop->ports; idx += 1) { - scop->u_.net[idx] = net->module_port(idx); + scop->u_.net[idx] = net->module_port_net(idx); } } + scop->module_ports_info = net->module_port_info(); break; + case NetScope::TASK: { const NetTaskDef*def = net->task_def(); if (def == 0) { @@ -2380,27 +2370,14 @@ void dll_target::signal(const NetNet*net) assert(obj->scope_); FILE_NAME(obj, net); - if (obj->scope_->nsigs_ == 0) { - assert(obj->scope_->sigs_ == 0); - obj->scope_->nsigs_ = 1; - obj->scope_->sigs_ = (ivl_signal_t*)malloc(sizeof(ivl_signal_t)); - - } else { - assert(obj->scope_->sigs_); - obj->scope_->nsigs_ += 1; - obj->scope_->sigs_ = (ivl_signal_t*) - realloc(obj->scope_->sigs_, - obj->scope_->nsigs_*sizeof(ivl_signal_t)); - } - - obj->scope_->sigs_[obj->scope_->nsigs_-1] = obj; + obj->scope_->sigs_.push_back(obj); /* Save the primitive properties of the signal in the ivl_signal_t object. */ { size_t idx = 0; - list::const_iterator cur; + vector::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) { @@ -2408,15 +2385,14 @@ void dll_target::signal(const NetNet*net) } } - obj->width_ = net->vector_width(); - obj->signed_= net->get_signed()? 1 : 0; - obj->isint_ = false; + obj->net_type = net->net_type(); obj->local_ = net->local_flag()? 1 : 0; obj->forced_net_ = (net->type() != NetNet::REG) && (net->peek_lref() > 0) ? 1 : 0; obj->discipline = net->get_discipline(); - obj->array_dimensions_ = net->array_dimensions(); + obj->array_dimensions_ = net->unpacked_dimensions(); + assert(obj->array_dimensions_ == net->unpacked_dimensions()); switch (net->port_type()) { @@ -2437,11 +2413,12 @@ void dll_target::signal(const NetNet*net) break; } + obj->module_port_index_ = net->get_module_port_index(); + switch (net->type()) { case NetNet::REG: obj->type_ = IVL_SIT_REG; - obj->isint_ = net->get_isint(); break; /* The SUPPLY0/1 net types are replaced with pulldown/up @@ -2492,11 +2469,9 @@ void dll_target::signal(const NetNet*net) obj->npath = 0; obj->path = 0; - obj->data_type = net->data_type(); obj->nattr = net->attr_cnt(); obj->attr = fill_in_attributes(net); - /* Get the nexus objects for all the pins of the signal. If the signal has only one pin, then write the single ivl_nexus_t object into n.pin_. Otherwise, make an array of @@ -2506,9 +2481,23 @@ void dll_target::signal(const NetNet*net) t_cookie of the Nexus object so that I find it again when I next encounter the nexus. */ - obj->array_base = net->array_first(); - obj->array_words = net->array_count(); - obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0; + if (obj->array_dimensions_ == 1) { + const vector& dims = net->unpacked_dims(); + if (dims[0].get_msb() < dims[0].get_lsb()) { + obj->array_base = dims[0].get_msb(); + obj->array_addr_swapped = false; + } else { + obj->array_base = dims[0].get_lsb(); + obj->array_addr_swapped = true; + } + obj->array_words = net->unpacked_count(); + } else { + // The back-end API doesn't yet support multi-dimension + // unpacked arrays, so just report the canonical dimensions. + obj->array_base = 0; + obj->array_words = net->unpacked_count(); + obj->array_addr_swapped = 0; + } ivl_assert(*net, obj->array_words == net->pin_count()); if (debug_optimizer && obj->array_words > 1000) cerr << "debug: " diff --git a/t-dll.h b/t-dll.h index 2bdae36bb..1c017f5ae 100644 --- a/t-dll.h +++ b/t-dll.h @@ -1,7 +1,7 @@ #ifndef __t_dll_H #define __t_dll_H /* - * 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 @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "target.h" @@ -58,6 +58,7 @@ struct dll_target : public target_t, public expr_scan_t { bool bufz(const NetBUFZ*); bool branch(const NetBranch*); + bool class_type(const NetScope*, netclass_t*); bool enumeration(const NetScope*, netenum_t*); void event(const NetEvent*); void logic(const NetLogic*); @@ -137,7 +138,10 @@ struct dll_target : public target_t, public expr_scan_t { void expr_concat(const NetEConcat*); void expr_const(const NetEConst*); void expr_creal(const NetECReal*); + void expr_new(const NetENew*); + void expr_null(const NetENull*); void expr_param(const NetEConstParam*); + void expr_property(const NetEProperty*); void expr_rparam(const NetECRealParam*); void expr_event(const NetEEvent*); void expr_scope(const NetEScope*); @@ -218,6 +222,7 @@ struct ivl_event_s { struct ivl_expr_s { ivl_expr_type_t type_; ivl_variable_type_t value_; + ivl_type_t net_type; perm_string file; unsigned lineno; @@ -317,6 +322,14 @@ struct ivl_expr_s { uint64_t value; } delay_; + struct { + ivl_expr_t size; + } new_; + + struct { + ivl_signal_t sig; + unsigned prop_idx; + } property_; } u_; }; @@ -434,10 +447,11 @@ enum ivl_lval_type_t { struct ivl_lval_s { ivl_expr_t loff; - ivl_select_type_t sel_type; + ivl_select_type_t sel_type :3; ivl_expr_t idx; unsigned width_; unsigned type_ : 8; + int property_idx; union { ivl_signal_t sig; ivl_memory_t mem; @@ -584,6 +598,7 @@ struct ivl_parameter_s { perm_string basename; ivl_scope_t scope; ivl_expr_t value; + bool local; perm_string file; unsigned lineno; }; @@ -624,10 +639,10 @@ struct ivl_scope_s { unsigned def_lineno; ivl_scope_type_t type_; + std::vector classes; std::vector enumerations_; - unsigned nsigs_; - ivl_signal_t*sigs_; + std::vector sigs_; unsigned nlog_; ivl_net_logic_t*log_; @@ -647,6 +662,10 @@ struct ivl_scope_s { unsigned is_cell; + // Ports of Module scope (just introspection data for VPI) - actual connections + // are nets defined in u_.net (may be > 1 per module port) + std::vector module_ports_info; + unsigned ports; union { ivl_signal_t*port; @@ -672,25 +691,24 @@ struct ivl_scope_s { struct ivl_signal_s { ivl_signal_type_t type_; ivl_signal_port_t port_; - ivl_variable_type_t data_type; + int module_port_index_; ivl_discipline_t discipline; perm_string file; unsigned lineno; - unsigned width_; - unsigned signed_ : 1; - unsigned isint_ : 1; + // This is the type for the signal + ivl_type_t net_type; unsigned local_ : 1; unsigned forced_net_ : 1; /* For now, support only 0 or 1 array dimensions. */ - unsigned array_dimensions_ : 1; + unsigned array_dimensions_ : 8; unsigned array_addr_swapped : 1; /* These encode the declared packed dimensions for the signal, in case they are needed by the run-time */ - std::vector packed_dims; + std::vector packed_dims; perm_string name_; ivl_scope_t scope_; @@ -709,6 +727,7 @@ struct ivl_signal_s { unsigned nattr; }; + /* * The ivl_statement_t represents any statement. The type of statement * is defined by the ivl_statement_type_t enumeration. Given the type, diff --git a/target.cc b/target.cc index 7c744dd87..77dabeb7c 100644 --- a/target.cc +++ b/target.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -43,6 +43,13 @@ bool target_t::branch(const NetBranch*obj) return false; } +bool target_t::class_type(const NetScope*, netclass_t*obj) +{ + cerr << "<>:0" << ": error: target (" << typeid(*this).name() + << "): Unhandled class_type <" << obj << ">." << endl; + return false; +} + void target_t::event(const NetEvent*ev) { cerr << ev->get_fileline() << ": error: target (" << typeid(*this).name() @@ -444,11 +451,29 @@ void expr_scan_t::expr_const(const NetEConst*) "unhandled expr_const." << endl; } +void expr_scan_t::expr_new(const NetENew*) +{ + cerr << "expr_scan_t (" << typeid(*this).name() << "): " + "unhandled expr_new." << endl; +} + +void expr_scan_t::expr_null(const NetENull*) +{ + cerr << "expr_scan_t (" << typeid(*this).name() << "): " + "unhandled expr_null." << endl; +} + void expr_scan_t::expr_param(const NetEConstParam*that) { expr_const(that); } +void expr_scan_t::expr_property(const NetEProperty*) +{ + cerr << "expr_scan_t (" << typeid(*this).name() << "): " + "unhandled expr_property." << endl; +} + void expr_scan_t::expr_creal(const NetECReal*) { cerr << "expr_scan_t (" << typeid(*this).name() << "): " diff --git a/target.h b/target.h index 1ff7fc522..a82924b13 100644 --- a/target.h +++ b/target.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "netlist.h" @@ -56,6 +56,8 @@ struct target_t { anything else is called. */ virtual void scope(const NetScope*); + virtual bool class_type(const NetScope*, netclass_t*); + /* This is called to convert module ports from a NetNet* to an * ivl_signal_t object. */ virtual void convert_module_ports(const NetScope*); @@ -150,7 +152,10 @@ struct expr_scan_t { virtual ~expr_scan_t(); virtual void expr_access_func(const NetEAccess*); virtual void expr_const(const NetEConst*); + virtual void expr_new(const NetENew*); + virtual void expr_null(const NetENull*); virtual void expr_param(const NetEConstParam*); + virtual void expr_property(const NetEProperty*); virtual void expr_rparam(const NetECRealParam*); virtual void expr_creal(const NetECReal*); virtual void expr_concat(const NetEConcat*); diff --git a/tgt-fpga/Makefile.in b/tgt-fpga/Makefile.in index 7aa2e1f14..cee67286b 100644 --- a/tgt-fpga/Makefile.in +++ b/tgt-fpga/Makefile.in @@ -13,9 +13,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/tgt-fpga/d-generic-edif.c b/tgt-fpga/d-generic-edif.c index 5831306ff..cfa0b3af0 100644 --- a/tgt-fpga/d-generic-edif.c +++ b/tgt-fpga/d-generic-edif.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "device.h" diff --git a/tgt-fpga/d-generic.c b/tgt-fpga/d-generic.c index 8cb266113..e75f568ff 100644 --- a/tgt-fpga/d-generic.c +++ b/tgt-fpga/d-generic.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: d-generic.c,v 1.14 2003/11/12 03:20:14 steve Exp $" -#endif # include "device.h" # include "fpga_priv.h" @@ -512,55 +509,3 @@ const struct device_s d_generic = { 0, 0 }; - - -/* - * $Log: d-generic.c,v $ - * Revision 1.14 2003/11/12 03:20:14 steve - * devices need show_cmp_gt - * - * Revision 1.13 2003/06/24 03:55:00 steve - * Add ivl_synthesis_cell support for virtex2. - * - * Revision 1.12 2002/10/28 02:05:56 steve - * Add Virtex code generators for left shift, - * subtraction, and GE comparators. - * - * Revision 1.11 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.10 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - * Revision 1.9 2001/09/16 01:48:16 steve - * Suppor the PAD attribute on signals. - * - * Revision 1.8 2001/09/02 21:33:07 steve - * Rearrange the XNF code generator to be generic-xnf - * so that non-XNF code generation is also possible. - * - * Start into the virtex EDIF output driver. - * - * Revision 1.7 2001/09/01 04:30:44 steve - * Generic ADD code. - * - * Revision 1.6 2001/09/01 02:28:42 steve - * Generate code for MUX devices. - * - * Revision 1.5 2001/09/01 02:01:30 steve - * identity compare, and PWR records for constants. - * - * Revision 1.4 2001/08/31 23:02:13 steve - * Relax pin count restriction on logic gates. - * - * Revision 1.3 2001/08/31 04:17:56 steve - * Many more logic gate types. - * - * Revision 1.2 2001/08/31 02:59:06 steve - * Add root port SIG records. - * - * Revision 1.1 2001/08/28 04:14:20 steve - * Add the fpga target. - * - */ - diff --git a/tgt-fpga/d-lpm.c b/tgt-fpga/d-lpm.c index 5e1891aac..8d95aa547 100644 --- a/tgt-fpga/d-lpm.c +++ b/tgt-fpga/d-lpm.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: d-lpm.c,v 1.12 2004/10/04 01:10:56 steve Exp $" -#endif /* * This is the driver for a purely generic LPM module writer. This @@ -873,44 +870,3 @@ const struct device_s d_lpm_edif = { lpm_show_mult, /* show_mult */ lpm_show_constant /* show_constant */ }; - -/* - * $Log: d-lpm.c,v $ - * Revision 1.12 2004/10/04 01:10:56 steve - * Clean up spurious trailing white space. - * - * Revision 1.11 2003/11/12 03:20:14 steve - * devices need show_cmp_gt - * - * Revision 1.10 2003/10/31 03:45:50 steve - * Handle adders that use Cout for the top bit. - * - * Revision 1.9 2003/10/27 02:18:27 steve - * Emit constants for LPM device. - * - * Revision 1.8 2003/09/03 23:34:09 steve - * Support synchronous set of LPM_FF devices. - * - * Revision 1.7 2003/08/26 04:45:47 steve - * iverilog-vpi support --cflags a la gtk. - * - * Revision 1.6 2003/08/15 02:23:53 steve - * Add synthesis support for synchronous reset. - * - * Revision 1.5 2003/08/10 16:42:23 steve - * Add async clear to LPM_FF devices. - * - * Revision 1.4 2003/08/09 03:23:03 steve - * Add support for IVL_LPM_MULT device. - * - * Revision 1.3 2003/08/09 02:40:50 steve - * Generate LPM_FF devices. - * - * Revision 1.2 2003/08/07 05:18:04 steve - * Add support for OR/NOR/bufif0/bufif1. - * - * Revision 1.1 2003/08/07 04:04:01 steve - * Add an LPM device type. - * - */ - diff --git a/tgt-fpga/d-virtex.c b/tgt-fpga/d-virtex.c index 24e371741..77d5286d4 100644 --- a/tgt-fpga/d-virtex.c +++ b/tgt-fpga/d-virtex.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "device.h" diff --git a/tgt-fpga/d-virtex2.c b/tgt-fpga/d-virtex2.c index 3c154fdc0..9df35e466 100644 --- a/tgt-fpga/d-virtex2.c +++ b/tgt-fpga/d-virtex2.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "device.h" diff --git a/tgt-fpga/device.h b/tgt-fpga/device.h index 448a0b860..78e842599 100644 --- a/tgt-fpga/device.h +++ b/tgt-fpga/device.h @@ -16,11 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: device.h,v 1.15 2007/02/26 19:49:49 steve Exp $" -#endif # include @@ -77,57 +74,4 @@ struct device_s { */ extern device_t device_from_arch(const char*arch); - -/* - * $Log: device.h,v $ - * Revision 1.15 2007/02/26 19:49:49 steve - * Spelling fixes (larry doolittle) - * - * Revision 1.14 2003/11/12 03:20:14 steve - * devices need show_cmp_gt - * - * Revision 1.13 2003/10/27 02:18:27 steve - * Emit constants for LPM device. - * - * Revision 1.12 2003/08/09 03:23:03 steve - * Add support for IVL_LPM_MULT device. - * - * Revision 1.11 2003/06/24 03:55:00 steve - * Add ivl_synthesis_cell support for virtex2. - * - * Revision 1.10 2002/10/28 02:05:56 steve - * Add Virtex code generators for left shift, - * subtraction, and GE comparators. - * - * Revision 1.9 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.8 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - * Revision 1.7 2001/09/16 01:48:16 steve - * Suppor the PAD attribute on signals. - * - * Revision 1.6 2001/09/02 21:33:07 steve - * Rearrange the XNF code generator to be generic-xnf - * so that non-XNF code generation is also possible. - * - * Start into the virtex EDIF output driver. - * - * Revision 1.5 2001/09/01 04:30:44 steve - * Generic ADD code. - * - * Revision 1.4 2001/09/01 02:28:42 steve - * Generate code for MUX devices. - * - * Revision 1.3 2001/09/01 02:01:30 steve - * identity compare, and PWR records for constants. - * - * Revision 1.2 2001/08/31 02:59:06 steve - * Add root port SIG records. - * - * Revision 1.1 2001/08/28 04:14:20 steve - * Add the fpga target. - * - */ #endif diff --git a/tgt-fpga/edif.c b/tgt-fpga/edif.c index 9e8d97930..a923d49c4 100644 --- a/tgt-fpga/edif.c +++ b/tgt-fpga/edif.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "edif.h" diff --git a/tgt-fpga/edif.h b/tgt-fpga/edif.h index 5fb99e260..38d54fe70 100644 --- a/tgt-fpga/edif.h +++ b/tgt-fpga/edif.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/tgt-fpga/fpga.c b/tgt-fpga/fpga.c index 54775b520..116d381a4 100644 --- a/tgt-fpga/fpga.c +++ b/tgt-fpga/fpga.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: fpga.c,v 1.10 2003/10/27 02:18:28 steve Exp $" -#endif # include "config.h" @@ -157,41 +154,3 @@ int target_design(ivl_design_t des) xnf = 0; return 0; } - -/* - * $Log: fpga.c,v $ - * Revision 1.10 2003/10/27 02:18:28 steve - * Emit constants for LPM device. - * - * Revision 1.9 2003/08/07 04:04:01 steve - * Add an LPM device type. - * - * Revision 1.8 2003/06/25 01:49:06 steve - * Spelling fixes. - * - * Revision 1.7 2003/06/24 03:55:00 steve - * Add ivl_synthesis_cell support for virtex2. - * - * Revision 1.6 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.5 2001/09/16 01:48:16 steve - * Suppor the PAD attribute on signals. - * - * Revision 1.4 2001/09/02 21:33:07 steve - * Rearrange the XNF code generator to be generic-xnf - * so that non-XNF code generation is also possible. - * - * Start into the virtex EDIF output driver. - * - * Revision 1.3 2001/09/01 02:01:30 steve - * identity compare, and PWR records for constants. - * - * Revision 1.2 2001/08/31 02:59:06 steve - * Add root port SIG records. - * - * Revision 1.1 2001/08/28 04:14:20 steve - * Add the fpga target. - * - */ - diff --git a/tgt-fpga/fpga_priv.h b/tgt-fpga/fpga_priv.h index 156bd4cf2..8c1b60f24 100644 --- a/tgt-fpga/fpga_priv.h +++ b/tgt-fpga/fpga_priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -47,5 +47,4 @@ extern void xnf_mangle_lpm_name(ivl_lpm_t net, char*buf, size_t nbuf); extern const char*xnf_mangle_nexus_name(ivl_nexus_t net); - #endif diff --git a/tgt-fpga/gates.c b/tgt-fpga/gates.c index b6f6857b1..aca09ec78 100644 --- a/tgt-fpga/gates.c +++ b/tgt-fpga/gates.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: gates.c,v 1.14 2003/11/12 03:20:14 steve Exp $" -#endif # include # include "fpga_priv.h" @@ -174,40 +171,3 @@ int show_scope_gates(ivl_scope_t net, void*x) return ivl_scope_children(net, show_scope_gates, 0); } - -/* - * $Log: gates.c,v $ - * Revision 1.14 2003/11/12 03:20:14 steve - * devices need show_cmp_gt - * - * Revision 1.13 2003/08/09 03:23:03 steve - * Add support for IVL_LPM_MULT device. - * - * Revision 1.12 2003/08/07 04:04:01 steve - * Add an LPM device type. - * - * Revision 1.11 2003/06/24 03:55:01 steve - * Add ivl_synthesis_cell support for virtex2. - * - * Revision 1.10 2002/10/28 02:05:56 steve - * Add Virtex code generators for left shift, - * subtraction, and GE comparators. - * - * Revision 1.9 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.8 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - * Revision 1.7 2001/09/09 22:23:28 steve - * Virtex support for mux devices and adders - * with carry chains. Also, make Virtex specific - * implementations of primitive logic. - * - * Revision 1.6 2001/09/02 21:33:07 steve - * Rearrange the XNF code generator to be generic-xnf - * so that non-XNF code generation is also possible. - * - * Start into the virtex EDIF output driver. - */ - diff --git a/tgt-fpga/generic.c b/tgt-fpga/generic.c index 74c9c6e0d..42afc2f64 100644 --- a/tgt-fpga/generic.c +++ b/tgt-fpga/generic.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: generic.c,v 1.3 2003/08/26 16:26:02 steve Exp $" -#endif # include "generic.h" @@ -31,19 +28,3 @@ edif_cell_t cell_1 = 0; edif_cell_t cell_ipad = 0; edif_cell_t cell_opad = 0; edif_cell_t cell_iopad = 0; - - - -/* - * $Log: generic.c,v $ - * Revision 1.3 2003/08/26 16:26:02 steve - * ifdef idents correctly. - * - * Revision 1.2 2003/07/03 17:46:33 steve - * IOPAD support. - * - * Revision 1.1 2003/06/25 02:55:57 steve - * Virtex and Virtex2 share much code. - * - */ - diff --git a/tgt-fpga/generic.h b/tgt-fpga/generic.h index 59a219b35..e81633438 100644 --- a/tgt-fpga/generic.h +++ b/tgt-fpga/generic.h @@ -16,11 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: generic.h,v 1.3 2003/08/26 16:26:02 steve Exp $" -#endif # include "edif.h" @@ -42,17 +39,4 @@ extern edif_cell_t cell_ipad; extern edif_cell_t cell_opad; extern edif_cell_t cell_iopad; - -/* - * $Log: generic.h,v $ - * Revision 1.3 2003/08/26 16:26:02 steve - * ifdef idents correctly. - * - * Revision 1.2 2003/07/03 17:46:33 steve - * IOPAD support. - * - * Revision 1.1 2003/06/25 02:55:57 steve - * Virtex and Virtex2 share much code. - * - */ #endif diff --git a/tgt-fpga/mangle.c b/tgt-fpga/mangle.c index 5b98e73e6..ac3b66fdf 100644 --- a/tgt-fpga/mangle.c +++ b/tgt-fpga/mangle.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "fpga_priv.h" diff --git a/tgt-fpga/tables.c b/tgt-fpga/tables.c index fe54dbe2e..1aa44f16f 100644 --- a/tgt-fpga/tables.c +++ b/tgt-fpga/tables.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: tables.c,v 1.6 2003/08/07 04:04:01 steve Exp $" -#endif # include "fpga_priv.h" # include @@ -57,30 +54,3 @@ device_t device_from_arch(const char*arch) return 0; } - -/* - * $Log: tables.c,v $ - * Revision 1.6 2003/08/07 04:04:01 steve - * Add an LPM device type. - * - * Revision 1.5 2003/03/24 00:47:54 steve - * Add new virtex2 architecture family, and - * also the new edif.h EDIF management functions. - * - * Revision 1.4 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.3 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - * Revision 1.2 2001/09/06 04:28:40 steve - * Separate the virtex and generic-edif code generators. - * - * Revision 1.1 2001/09/02 21:33:07 steve - * Rearrange the XNF code generator to be generic-xnf - * so that non-XNF code generation is also possible. - * - * Start into the virtex EDIF output driver. - * - */ - diff --git a/tgt-fpga/xilinx.c b/tgt-fpga/xilinx.c index f64ab491f..eb5390e63 100644 --- a/tgt-fpga/xilinx.c +++ b/tgt-fpga/xilinx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve at icarus.com) + * Copyright (c) 2003-2012 Stephen Williams (steve at 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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "edif.h" @@ -877,7 +877,7 @@ void xilinx_shiftl(ivl_lpm_t net) inputs. The slice on the low end shifts in a 0 for a select input. */ for (qdx = 0 ; qdx < width ; qdx += 1) { - ivl_nexus_t nex0, nex1; + ivl_nexus_t nex0; edif_joint_t jnt0; edif_joint_t jnt1; @@ -885,6 +885,7 @@ void xilinx_shiftl(ivl_lpm_t net) jnt0 = edif_joint_of_nexus(edf, nex0); if (qdx > 0) { + ivl_nexus_t nex1; nex1 = ivl_lpm_data(net,qdx-1); jnt1 = edif_joint_of_nexus(edf, nex1); } else { diff --git a/tgt-fpga/xilinx.h b/tgt-fpga/xilinx.h index 83f24bd1b..3789c561d 100644 --- a/tgt-fpga/xilinx.h +++ b/tgt-fpga/xilinx.h @@ -16,11 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: xilinx.h,v 1.9 2007/02/26 19:49:50 steve Exp $" -#endif /* * This header file includes XILINX library support functions. They @@ -128,34 +125,4 @@ extern void xilinx_mux(ivl_lpm_t net); extern void xilinx_add(ivl_lpm_t net); extern void xilinx_shiftl(ivl_lpm_t net); -/* - * $Log: xilinx.h,v $ - * Revision 1.9 2007/02/26 19:49:50 steve - * Spelling fixes (larry doolittle) - * - * Revision 1.8 2003/08/15 02:23:53 steve - * Add synthesis support for synchronous reset. - * - * Revision 1.7 2003/07/04 00:10:09 steve - * Generate MUXF5 based 4-input N-wide muxes. - * - * Revision 1.6 2003/07/02 03:02:15 steve - * More xilinx common code. - * - * Revision 1.5 2003/07/02 00:25:40 steve - * Add xilinx support for bufif1. - * - * Revision 1.4 2003/06/28 04:18:47 steve - * Add support for wide OR/NOR gates. - * - * Revision 1.3 2003/06/26 03:57:05 steve - * Add Xilinx support for A/B MUX devices. - * - * Revision 1.2 2003/06/25 02:55:57 steve - * Virtex and Virtex2 share much code. - * - * Revision 1.1 2003/04/05 05:53:34 steve - * Move library cell management to common file. - * - */ #endif diff --git a/tgt-null/Makefile.in b/tgt-null/Makefile.in index 8a354ef97..1de125ccd 100644 --- a/tgt-null/Makefile.in +++ b/tgt-null/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/tgt-null/null.c b/tgt-null/null.c index c99f6ca85..35f2869ca 100644 --- a/tgt-null/null.c +++ b/tgt-null/null.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "version_base.h" diff --git a/tgt-pal/Makefile.in b/tgt-pal/Makefile.in index 7ae034a09..261f5fecf 100644 --- a/tgt-pal/Makefile.in +++ b/tgt-pal/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/tgt-pal/dump_final.c b/tgt-pal/dump_final.c index 393403832..06797042c 100644 --- a/tgt-pal/dump_final.c +++ b/tgt-pal/dump_final.c @@ -14,18 +14,14 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: dump_final.c,v 1.4 2003/02/26 01:24:35 steve Exp $" -#endif # include "config.h" # include "priv.h" # include - void dump_final_design(FILE*out) { unsigned idx; @@ -53,23 +49,3 @@ void dump_final_design(FILE*out) } } } - - - -/* - * $Log: dump_final.c,v $ - * Revision 1.4 2003/02/26 01:24:35 steve - * ivl_lpm_name is obsolete. - * - * Revision 1.3 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.2 2001/07/25 03:10:50 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.1 2000/12/09 03:42:52 steve - * Stuff registers into macrocells. - * - */ - diff --git a/tgt-pal/emit_jed.c b/tgt-pal/emit_jed.c index de0672b8c..d80e8cfa0 100644 --- a/tgt-pal/emit_jed.c +++ b/tgt-pal/emit_jed.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/tgt-pal/enables.c b/tgt-pal/enables.c index 6b7a467da..1ac34ae02 100644 --- a/tgt-pal/enables.c +++ b/tgt-pal/enables.c @@ -14,18 +14,14 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: enables.c,v 1.6 2002/08/12 01:35:03 steve Exp $" -#endif # include "config.h" # include "ivl_target.h" # include # include "priv.h" - /* * Given a pin index, look at the nexus for a bufif device that is * driving it, if any. Save that device in the enable slot for the @@ -76,28 +72,3 @@ void absorb_pad_enables(void) absorb_pad_enable(idx); } } - - -/* - * $Log: enables.c,v $ - * Revision 1.6 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.5 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - * Revision 1.4 2001/07/25 03:10:50 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.3 2001/02/07 22:22:00 steve - * ivl_target header search path fixes. - * - * Revision 1.2 2000/12/09 03:42:52 steve - * Stuff registers into macrocells. - * - * Revision 1.1 2000/12/09 01:17:38 steve - * Add the pal loadable target. - * - */ - diff --git a/tgt-pal/fit_log.c b/tgt-pal/fit_log.c index 3f5efed3e..5bab00a9d 100644 --- a/tgt-pal/fit_log.c +++ b/tgt-pal/fit_log.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -36,7 +36,6 @@ * objects. An expression is a null terminated array of terms. */ - static void dump_expr(term_t**expr, const char*title) { unsigned idx; diff --git a/tgt-pal/fit_reg.c b/tgt-pal/fit_reg.c index 94d96b593..093287414 100644 --- a/tgt-pal/fit_reg.c +++ b/tgt-pal/fit_reg.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: fit_reg.c,v 1.7 2002/08/12 01:35:03 steve Exp $" -#endif # include "config.h" @@ -133,30 +130,3 @@ int scan_ff_q(ivl_lpm_t ff, unsigned q) error_count += 1; return 0; } - -/* - * $Log: fit_reg.c,v $ - * Revision 1.7 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.6 2001/07/25 03:10:50 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.5 2001/05/16 03:55:30 steve - * Update to new LPM API for flip-flops. - * - * Revision 1.4 2001/02/07 22:22:00 steve - * ivl_target header search path fixes. - * - * Revision 1.3 2001/01/15 00:05:39 steve - * Add client data pointer for scope and process scanners. - * - * Revision 1.2 2000/12/09 05:40:42 steve - * documentation... - * - * Revision 1.1 2000/12/09 03:42:52 steve - * Stuff registers into macrocells. - * - */ - diff --git a/tgt-pal/imain.c b/tgt-pal/imain.c index 4f262753e..b88df81fe 100644 --- a/tgt-pal/imain.c +++ b/tgt-pal/imain.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/tgt-pal/pads.c b/tgt-pal/pads.c index 7513725ec..e8ec81516 100644 --- a/tgt-pal/pads.c +++ b/tgt-pal/pads.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: pads.c,v 1.4 2002/08/12 01:35:03 steve Exp $" -#endif # include "config.h" @@ -78,21 +75,3 @@ int get_pad_bindings(ivl_scope_t net, void*x) return 0; } - -/* - * $Log: pads.c,v $ - * Revision 1.4 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.3 2001/07/25 03:10:50 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.2 2001/01/15 00:05:39 steve - * Add client data pointer for scope and process scanners. - * - * Revision 1.1 2000/12/09 01:17:38 steve - * Add the pal loadable target. - * - */ - diff --git a/tgt-pal/priv.h b/tgt-pal/priv.h index d846201f8..d0dbc5846 100644 --- a/tgt-pal/priv.h +++ b/tgt-pal/priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/tgt-pcb/Makefile.in b/tgt-pcb/Makefile.in index efa3949fb..0285a2991 100644 --- a/tgt-pcb/Makefile.in +++ b/tgt-pcb/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/tgt-pcb/pcb.cc b/tgt-pcb/pcb.cc index da895dc2f..d744aa818 100644 --- a/tgt-pcb/pcb.cc +++ b/tgt-pcb/pcb.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/tgt-pcb/pcb_config.h.in b/tgt-pcb/pcb_config.h.in index 32ee73711..806c281ba 100644 --- a/tgt-pcb/pcb_config.h.in +++ b/tgt-pcb/pcb_config.h.in @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # undef HAVE_STDINT_H diff --git a/tgt-pcb/pcb_priv.h b/tgt-pcb/pcb_priv.h index 3dab1b9cd..2e85a4945 100644 --- a/tgt-pcb/pcb_priv.h +++ b/tgt-pcb/pcb_priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/tgt-pcb/scope.cc b/tgt-pcb/scope.cc index a5ed9ec62..9a06dd48a 100644 --- a/tgt-pcb/scope.cc +++ b/tgt-pcb/scope.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "pcb_priv.h" @@ -117,7 +117,7 @@ void sheet_box(ivl_scope_t scope, const map&attrs) } /* - * A black box is a component. Do not process the contents, other then + * A black box is a component. Do not process the contents, other than * to get at the ports that we'll attach to the netlist. */ static void black_box(ivl_scope_t scope, const map&attrs) diff --git a/tgt-pcb/show_netlist.cc b/tgt-pcb/show_netlist.cc index 992be0c5e..b0889bd31 100644 --- a/tgt-pcb/show_netlist.cc +++ b/tgt-pcb/show_netlist.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "pcb_priv.h" diff --git a/tgt-pcb/show_pcb.cc b/tgt-pcb/show_pcb.cc index 2a0d7a52c..fc46f76ef 100644 --- a/tgt-pcb/show_pcb.cc +++ b/tgt-pcb/show_pcb.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "pcb_config.h" diff --git a/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index b9df1d927..bbbb91f1c 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh @@ -45,7 +44,7 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -O = stub.o enumerate.o expression.o statement.o switches.o +O = stub.o classes.o enumerate.o expression.o statement.o switches.o types.o all: dep stub.tgt diff --git a/tgt-stub/classes.c b/tgt-stub/classes.c new file mode 100644 index 000000000..9b4f67db4 --- /dev/null +++ b/tgt-stub/classes.c @@ -0,0 +1,34 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "config.h" +# include "priv.h" +# include + +void show_class(ivl_type_t net) +{ + unsigned idx; + + fprintf(out, " class %s\n", ivl_type_name(net)); + for (idx = 0 ; idx < ivl_type_properties(net) ; idx += 1) { + fprintf(out, " "); + show_net_type(ivl_type_prop_type(net,idx)); + fprintf(out, " %s\n", ivl_type_prop_name(net,idx)); + } +} diff --git a/tgt-stub/enumerate.c b/tgt-stub/enumerate.c index 1c18229a7..139fae534 100644 --- a/tgt-stub/enumerate.c +++ b/tgt-stub/enumerate.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 79420225b..c1415f243 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -165,6 +165,105 @@ static void show_memory_expression(ivl_expr_t net, unsigned ind) width); } +static void show_new_expression(ivl_expr_t net, unsigned ind) +{ + switch (ivl_expr_value(net)) { + case IVL_VT_CLASS: + fprintf(out, "%*snew \n", ind, ""); + if (ivl_expr_oper1(net)) { + fprintf(out, "%*sERROR: class_new expression has a size!\n", + ind+3, ""); + show_expression(ivl_expr_oper1(net), ind+3); + stub_errors += 1; + } + break; + case IVL_VT_DARRAY: + fprintf(out, "%*snew [] \n", ind, ""); + if (ivl_expr_oper1(net)) { + show_expression(ivl_expr_oper1(net), ind+3); + } else { + fprintf(out, "%*sERROR: darray_new missing size expression\n", + ind+3, ""); + stub_errors += 1; + } + break; + default: + fprintf(out, "%*snew ERROR: expression type: %s\n", + ind+3, "", vt_type_string(net)); + stub_errors += 1; + break; + } +} + +static void show_null_expression(ivl_expr_t net, unsigned ind) +{ + fprintf(out, "%*s\n", ind, ""); + if (ivl_expr_value(net) != IVL_VT_CLASS) { + fprintf(out, "%*sERROR: null expression must be IVL_VT_CLASS, got %s.\n", + ind+3, "", vt_type_string(net)); + stub_errors += 1; + } +} + +static void show_property_expression(ivl_expr_t net, unsigned ind) +{ + ivl_signal_t sig = ivl_expr_signal(net); + const char* pnam = ivl_expr_name(net); + + fprintf(out, "%*s\n", ind, "", + ivl_signal_basename(sig), pnam, ivl_expr_width(net)); + if (ivl_signal_data_type(sig) != IVL_VT_CLASS) { + fprintf(out, "%*sERROR: Property signal must be IVL_VT_CLASS, got %s.\n", + ind+3, "", data_type_string(ivl_signal_data_type(sig))); + } +} + +static void show_select_expression(ivl_expr_t net, unsigned ind) +{ + unsigned width = ivl_expr_width(net); + const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; + const char*vt = vt_type_string(net); + ivl_expr_t oper1 = ivl_expr_oper1(net); + ivl_expr_t oper2 = ivl_expr_oper2(net); + + if (ivl_expr_value(oper1) == IVL_VT_STRING) { + /* If the sub-expression is a STRING, then this is a + substring and the code generator will handle it + differently. */ + fprintf(out, "%*s\n", ind, "", width, width/8); + if (width%8 != 0) { + fprintf(out, "%*sERROR: Width should be a multiple of 8 bits.\n", ind, ""); + stub_errors += 1; + } + assert(oper1); + show_expression(oper1, ind+3); + + if (oper2) { + show_expression(oper2, ind+3); + } else { + fprintf(out, "%*sERROR: oper2 missing! Pad makes no sense for IVL_VT_STRING expressions.\n", ind+3, ""); + stub_errors += 1; + } + + } else if (oper2) { + /* If oper2 is present, then it is the base of a part + select. The width of the expression defines the range + of the part select. */ + fprintf(out, "%*s\n", ind, "", + width, sign, vt); + show_expression(oper1, ind+3); + show_expression(oper2, ind+3); + + } else { + /* There is no base expression so this is a pad + operation. The sub-expression is padded (signed or + unsigned as appropriate) to the expression width. */ + fprintf(out, "%*s\n", ind, "", + width, sign); + show_expression(oper1, ind+3); + } +} + static void show_signal_expression(ivl_expr_t net, unsigned ind) { unsigned width = ivl_expr_width(net); @@ -173,6 +272,7 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind) ivl_expr_t word = ivl_expr_oper1(net); ivl_signal_t sig = ivl_expr_signal(net); + const char*vt_sig = data_type_string(ivl_signal_data_type(sig)); unsigned dimensions = ivl_signal_dimensions(sig); unsigned word_count = ivl_signal_array_count(sig); @@ -182,8 +282,8 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind) stub_errors += 1; } - fprintf(out, "%*s\n", ind, "", - ivl_expr_name(net), word_count, width, sign, vt); + fprintf(out, "%*s\n", ind, "", + ivl_expr_name(net), word_count, width, sign, vt, vt_sig); /* If the expression refers to a signal array, then there must also be a word select expression, and if the signal is not an @@ -196,6 +296,14 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind) fprintf(out, "%*sERROR: Missing word expression\n", ind+2, ""); stub_errors += 1; } + /* If this is not an array, then the expression with must + match the signal width. We have IVL_EX_SELECT expressions + for casting signal widths. */ + if (dimensions == 0 && ivl_signal_width(sig) != width) { + fprintf(out, "%*sERROR: Expression width (%u) doesn't match ivl_signal_width(sig)=%u\n", + ind+2, "", width, ivl_signal_width(sig)); + stub_errors += 1; + } if (word != 0) { fprintf(out, "%*sAddress-0 word address:\n", ind+2, ""); @@ -257,9 +365,10 @@ void show_unary_expression(ivl_expr_t net, unsigned ind) void show_expression(ivl_expr_t net, unsigned ind) { + assert(net); unsigned idx; - const ivl_expr_type_t code = ivl_expr_type(net); ivl_parameter_t par = ivl_expr_parameter(net); + const ivl_expr_type_t code = ivl_expr_type(net); unsigned width = ivl_expr_width(net); const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; const char*sized = ivl_expr_sized(net)? "sized" : "unsized"; @@ -295,6 +404,18 @@ void show_expression(ivl_expr_t net, unsigned ind) show_memory_expression(net, ind); break; + case IVL_EX_NEW: + show_new_expression(net, ind); + break; + + case IVL_EX_NULL: + show_null_expression(net, ind); + break; + + case IVL_EX_PROPERTY: + show_property_expression(net, ind); + break; + case IVL_EX_NUMBER: { const char*bits = ivl_expr_bits(net); @@ -312,18 +433,7 @@ void show_expression(ivl_expr_t net, unsigned ind) } case IVL_EX_SELECT: - /* The SELECT expression can be used to express part - select, or if the base is null vector extension. */ - if (ivl_expr_oper2(net)) { - fprintf(out, "%*s\n", ind, "", - width, sign); - show_expression(ivl_expr_oper1(net), ind+3); - show_expression(ivl_expr_oper2(net), ind+3); - } else { - fprintf(out, "%*s\n", ind, "", - width, sign); - show_expression(ivl_expr_oper1(net), ind+3); - } + show_select_expression(net, ind); break; case IVL_EX_STRING: @@ -384,7 +494,7 @@ void show_expression(ivl_expr_t net, unsigned ind) break; default: - fprintf(out, "%*s\n", ind, "", code); + fprintf(out, "%*s\n", ind, "", code); break; } } diff --git a/tgt-stub/priv.h b/tgt-stub/priv.h index 7ebaed030..60902779d 100644 --- a/tgt-stub/priv.h +++ b/tgt-stub/priv.h @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -49,6 +49,7 @@ extern ivl_discipline_t discipline_of_nexus(ivl_nexus_t nex); */ extern void test_expr_is_delay(ivl_expr_t expr); +extern void show_class(ivl_type_t net); extern void show_enumerate(ivl_enumtype_t net); /* @@ -61,8 +62,15 @@ extern void show_expression(ivl_expr_t net, unsigned ind); */ extern void show_statement(ivl_statement_t net, unsigned ind); +/* + * Show the type of the signal, in one line. + */ +extern void show_type_of_signal(ivl_signal_t); + extern void show_switch(ivl_switch_t net); /* */ extern const char*data_type_string(ivl_variable_type_t vtype); + +extern void show_net_type(ivl_type_t net_type); diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 401b049e7..ea020b6f0 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2007 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 @@ -14,21 +14,87 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include "priv.h" # include -static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) +/* + * If the l-value signal is a darray object, then the ivl_lval_mux() + * gets you the array index expression. + */ +static unsigned show_assign_lval_darray(ivl_lval_t lval, unsigned ind) { - unsigned wid = 0; - ivl_signal_t sig = ivl_lval_sig(lval); assert(sig); - fprintf(out, "%*s{name=%s width=%u lvwidth=%u}\n", + fprintf(out, "%*s{name=%s darray width=%u l-value width=%u}\n", + ind, "", + ivl_signal_name(sig), + ivl_signal_width(sig), + ivl_lval_width(lval)); + + if (ivl_lval_idx(lval)) { + fprintf(out, "%*sAddress-0 select of ", ind+4, ""); + show_type_of_signal(sig); + fprintf(out, ":\n"); + show_expression(ivl_lval_idx(lval), ind+6); + } + + if (ivl_lval_mux(lval)) { + fprintf(out, "%*sERROR: unexpected ivl_lval_mux() expression:\n", ind+4, ""); + stub_errors += 1; + show_expression(ivl_lval_mux(lval), ind+6); + } + if (ivl_lval_part_off(lval)) { + fprintf(out, "%*sERROR: unexpected Part select expression:\n", ind+4, ""); + stub_errors += 1; + show_expression(ivl_lval_part_off(lval), ind+8); + } + + return ivl_lval_width(lval); +} + +static unsigned show_assign_lval_class(ivl_lval_t lval, unsigned ind) +{ + ivl_signal_t sig = ivl_lval_sig(lval); + int sig_prop = ivl_lval_property_idx(lval); + assert(sig); + + /* If there is no property select, then this l-value is for + the class handle itself. */ + if (sig_prop < 0) { + fprintf(out, "%*s{name=%s class object}\n", ind, "", ivl_signal_name(sig)); + if (ivl_lval_width(lval) != 1) { + fprintf(out, "%*sERROR: ivl_lval_width should be 1 for class objects\n", + ind+4, ""); + stub_errors += 1; + } + return ivl_lval_width(lval); + } + + fprintf(out, "%*s{name=%s. l-value width=%u}\n", + ind, "", ivl_signal_name(sig), sig_prop, ivl_lval_width(lval)); + + return ivl_lval_width(lval); +} + +static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) +{ + ivl_signal_t sig = ivl_lval_sig(lval); + assert(sig); + + /* Special case: target signal is a darray. */ + if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) + return show_assign_lval_darray(lval, ind); + + /* Special case: target signal is a class. */ + if (ivl_signal_data_type(sig) == IVL_VT_CLASS) + return show_assign_lval_class(lval, ind); + + fprintf(out, "%*s{name=%s signal width=%u l-value width=%u}\n", ind, "", ivl_signal_name(sig), ivl_signal_width(sig), @@ -59,9 +125,7 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) show_expression(ivl_lval_part_off(lval), ind+8); } - wid = ivl_lval_width(lval); - - return wid; + return ivl_lval_width(lval); } static void show_stmt_cassign(ivl_statement_t net, unsigned ind) @@ -329,6 +393,28 @@ void show_statement(ivl_statement_t net, unsigned ind) break; } + case IVL_ST_FORK_JOIN_ANY: { + unsigned cnt = ivl_stmt_block_count(net); + fprintf(out, "%*sfork\n", ind, ""); + for (idx = 0 ; idx < cnt ; idx += 1) { + ivl_statement_t cur = ivl_stmt_block_stmt(net, idx); + show_statement(cur, ind+4); + } + fprintf(out, "%*sjoin_any\n", ind, ""); + break; + } + + case IVL_ST_FORK_JOIN_NONE: { + unsigned cnt = ivl_stmt_block_count(net); + fprintf(out, "%*sfork\n", ind, ""); + for (idx = 0 ; idx < cnt ; idx += 1) { + ivl_statement_t cur = ivl_stmt_block_stmt(net, idx); + show_statement(cur, ind+4); + } + fprintf(out, "%*sjoin_none\n", ind, ""); + break; + } + case IVL_ST_FREE: fprintf(out, "%*sfree automatic storage ...\n", ind, ""); break; @@ -370,6 +456,6 @@ void show_statement(ivl_statement_t net, unsigned ind) break; default: - fprintf(out, "%*sunknown statement type (%u)\n", ind, "", code); + fprintf(out, "%*sunknown statement type (%d)\n", ind, "", code); } } diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 3cddd2ab6..83426e0cb 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* @@ -169,6 +169,12 @@ const char*data_type_string(ivl_variable_type_t vtype) case IVL_VT_STRING: vt = "string"; break; + case IVL_VT_DARRAY: + vt = "darray"; + break; + case IVL_VT_CLASS: + vt = "class"; + break; } return vt; @@ -564,7 +570,7 @@ static void show_lpm_mux(ivl_lpm_t net) ivl_lpm_basename(net), width, size); nex = ivl_lpm_q(net); - fprintf(out, " Q: %p \n", nex, drive0, drive1); + fprintf(out, " Q: %p \n", nex, drive0, drive1); if (width != width_of_nexus(nex)) { fprintf(out, " Q: ERROR: Nexus width is %u\n", width_of_nexus(nex)); @@ -1219,7 +1225,6 @@ static void show_signal(ivl_signal_t net) const char*type = "?"; const char*port = ""; - const char*data_type = "?"; const char*sign = ivl_signal_signed(net)? "signed" : "unsigned"; switch (ivl_signal_type(net)) { @@ -1260,25 +1265,6 @@ static void show_signal(ivl_signal_t net) break; } - switch (ivl_signal_data_type(net)) { - - case IVL_VT_BOOL: - data_type = "bool"; - break; - - case IVL_VT_LOGIC: - data_type = "logic"; - break; - - case IVL_VT_REAL: - data_type = "real"; - break; - - default: - data_type = "?data?"; - break; - } - const char*discipline_txt = "NONE"; if (ivl_signal_discipline(net)) { ivl_discipline_t dis = ivl_signal_discipline(net); @@ -1288,13 +1274,9 @@ 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", 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 %s %s", type, sign, port); + show_type_of_signal(net); fprintf(out, " %s[word=%u, adr=%d] ", ivl_signal_basename(net), idx, ivl_signal_array_base(net)+idx, @@ -1358,6 +1340,15 @@ static void show_signal(ivl_signal_t net) } } + switch (ivl_signal_data_type(net)) { + case IVL_VT_NO_TYPE: + case IVL_VT_VOID: + fprintf(out, " ERROR: Invalid type for signal.\n"); + stub_errors += 1; + break; + default: + break; + } } void test_expr_is_delay(ivl_expr_t expr) @@ -1492,9 +1483,9 @@ static void show_logic(ivl_net_logic_t net) for (idx = 0 ; idx < npins ; idx += 1) { ivl_nexus_t nex = ivl_logic_pin(net, idx); - fprintf(out, " %d: %p", idx, nex); + fprintf(out, " %u: %p", idx, nex); if (idx == 0) - fprintf(out, " ", drive0, drive1); + fprintf(out, " ", drive0, drive1); fprintf(out, "\n"); if (nex == 0) { @@ -1507,7 +1498,7 @@ static void show_logic(ivl_net_logic_t net) } if (ivl_logic_width(net) != width_of_nexus(nex)) { - fprintf(out, " %d: ERROR: Nexus width is %u\n", + fprintf(out, " %u: ERROR: Nexus width is %u\n", idx, width_of_nexus(nex)); stub_errors += 1; } @@ -1597,6 +1588,9 @@ static int show_scope(ivl_scope_t net, void*x) } } + for (idx = 0 ; idx < ivl_scope_classes(net) ; idx += 1) + show_class(ivl_scope_class(net, idx)); + for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) show_parameter(ivl_scope_param(net, idx)); diff --git a/tgt-stub/switches.c b/tgt-stub/switches.c index 564a06d80..929ab592c 100644 --- a/tgt-stub/switches.c +++ b/tgt-stub/switches.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/tgt-stub/types.c b/tgt-stub/types.c new file mode 100644 index 000000000..7323f6729 --- /dev/null +++ b/tgt-stub/types.c @@ -0,0 +1,127 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "config.h" +# include "priv.h" +# include + +static void show_net_type_darray(ivl_type_t net_type) +{ + /* Dynamic arrays have a single element type. */ + ivl_type_t element_type = ivl_type_element(net_type); + + fprintf(out, "darray of "); + show_net_type(element_type); +} + +void show_net_type(ivl_type_t net_type) +{ + ivl_variable_type_t data_type = ivl_type_base(net_type); + + switch (data_type) { + case IVL_VT_NO_TYPE: + fprintf(out, ""); + stub_errors += 1; + break; + case IVL_VT_BOOL: + fprintf(out, "bool"); + break; + case IVL_VT_LOGIC: + fprintf(out, "logic"); + break; + case IVL_VT_REAL: + fprintf(out, "real"); + break; + case IVL_VT_STRING: + fprintf(out, "string"); + break; + case IVL_VT_DARRAY: + show_net_type_darray(net_type); + break; + case IVL_VT_CLASS: + fprintf(out, "class"); + break; + case IVL_VT_VOID: + fprintf(out, "void"); + break; + } + + unsigned packed_dimensions = ivl_type_packed_dimensions(net_type); + unsigned idx; + for (idx = 0 ; idx < packed_dimensions ; idx += 1) { + fprintf(out, "[%d:%d]", ivl_type_packed_msb(net_type, idx), + ivl_type_packed_lsb(net_type, idx)); + } +} + +void show_type_of_signal(ivl_signal_t net) +{ + unsigned dim; + + /* The data_type is the base type of the signal. This the the + starting point for the type. In the long run I think I want + to remove this in favor of the ivl_signal_net_type below. */ + ivl_variable_type_t data_type = ivl_signal_data_type(net); + + /* This gets the more general type description. This is a + newer form so doesn't yet handle all the cases. Newer + types, such DARRAY types, REQUIRE this method to get at the + type details. */ + ivl_type_t net_type = ivl_signal_net_type(net); + + if (net_type) { + show_net_type(net_type); + return; + } + + switch (data_type) { + case IVL_VT_NO_TYPE: + fprintf(out, ""); + break; + case IVL_VT_BOOL: + fprintf(out, "bool"); + break; + case IVL_VT_LOGIC: + fprintf(out, "logic"); + break; + case IVL_VT_REAL: + fprintf(out, "real"); + break; + case IVL_VT_STRING: + fprintf(out, "string"); + break; + case IVL_VT_DARRAY: + /* The DARRAY type MUST be described by an + ivl_signal_net_type object. */ + fprintf(out, "ERROR-DARRAY"); + stub_errors += 1; + break; + case IVL_VT_VOID: + fprintf(out, "void"); + break; + case IVL_VT_CLASS: + fprintf(out, "class"); + break; + } + + 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)); + } +} diff --git a/tgt-verilog/Makefile.in b/tgt-verilog/Makefile.in index b1ba3d771..3fdcb205e 100644 --- a/tgt-verilog/Makefile.in +++ b/tgt-verilog/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/tgt-verilog/verilog.c b/tgt-verilog/verilog.c index fb8d60bb7..d9c6af93f 100644 --- a/tgt-verilog/verilog.c +++ b/tgt-verilog/verilog.c @@ -14,11 +14,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: verilog.c,v 1.29 2007/02/26 19:49:50 steve Exp $" -#endif # include "config.h" @@ -380,7 +377,7 @@ static void show_statement(ivl_statement_t net, unsigned ind) break; default: - fprintf(out, "%*sunknown statement type (%u)\n", ind, "", code); + fprintf(out, "%*sunknown statement type (%d)\n", ind, "", code); } } @@ -437,78 +434,3 @@ int target_design(ivl_design_t des) return 0; } - - - -/* - * $Log: verilog.c,v $ - * Revision 1.29 2007/02/26 19:49:50 steve - * Spelling fixes (larry doolittle) - * - * Revision 1.28 2004/02/15 18:03:30 steve - * Cleanup of warnings. - * - * Revision 1.27 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.26 2001/12/15 02:13:17 steve - * The IVL_SIT_WIRE type does not exist, it is a - * synonym for IVL_SIT_TRI. - * - * Revision 1.25 2001/09/30 16:45:10 steve - * Fix some Cygwin DLL handling. (Venkat Iyer) - * - * Revision 1.24 2001/07/25 03:10:50 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.23 2001/05/22 02:14:47 steve - * Update the mingw build to not require cygwin files. - * - * Revision 1.22 2001/05/20 15:09:40 steve - * Mingw32 support (Venkat Iyer) - * - * Revision 1.21 2001/05/08 23:59:33 steve - * Add ivl and vvp.tgt support for memories in - * expressions and l-values. (Stephan Boettcher) - * - * Revision 1.20 2001/02/07 22:22:00 steve - * ivl_target header search path fixes. - * - * Revision 1.19 2001/01/15 00:05:39 steve - * Add client data pointer for scope and process scanners. - * - * Revision 1.18 2000/11/09 05:14:07 steve - * show concatenation operators. - * - * Revision 1.17 2000/11/07 06:14:06 steve - * Display l-values with width. - * - * Revision 1.16 2000/10/26 16:42:25 steve - * draw proper signal references for the gates. - * - * Revision 1.15 2000/10/26 00:32:28 steve - * emit declarations of signals and gates. - * - * Revision 1.14 2000/10/25 05:41:55 steve - * Scan the processes, and get the target signals - * - * Revision 1.13 2000/10/21 16:49:45 steve - * Reduce the target entry points to the target_design. - * - * Revision 1.12 2000/10/15 21:02:09 steve - * Makefile patches to support target loading under cygwin. - * - * Revision 1.11 2000/10/15 04:46:23 steve - * Scopes and processes are accessible randomly from - * the design, and signals and logic are accessible - * from scopes. Remove the target calls that are no - * longer needed. - * - * Add the ivl_nexus_ptr_t and the means to get at - * them from nexus objects. - * - * Give names to methods that manipulate the ivl_design_t - * type more consistent names. - */ - diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 8487fc1ab..50f76731d 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/tgt-vlog95/Makefile.in b/tgt-vlog95/Makefile.in index 2c95d9e55..a7a387a7d 100644 --- a/tgt-vlog95/Makefile.in +++ b/tgt-vlog95/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index 3d32ca023..d490c6a7a 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.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 @@ -400,9 +400,7 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) int msb = 1; int lsb = 0; if (type == IVL_EX_SIGNAL) { - ivl_signal_t sig = ivl_expr_signal(sig_expr); - msb = ivl_signal_msb(sig); - lsb = ivl_signal_lsb(sig); + get_sig_msb_lsb(ivl_expr_signal(sig_expr), &msb, &lsb); } /* A bit select. */ if (width == 1) { @@ -430,11 +428,11 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned 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; + int msb, lsb; + int64_t value; unsigned e_wid = ivl_expr_width(expr) - 1; + get_sig_msb_lsb(ivl_expr_signal(sig_expr), &msb, &lsb); + value = lsb; if (msb >= lsb) value += e_wid; else value -= e_wid; fprintf(vlog_out, "[%"PRId64":%u]", value, lsb); @@ -534,7 +532,7 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) fprintf(vlog_out, "("); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, "++)"); - fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment " + fprintf(stderr, "%s:%u: vlog95 sorry: Post-increment " "operator is not currently translated.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); @@ -554,7 +552,7 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) fprintf(vlog_out, "("); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, "--)"); - fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement " + fprintf(stderr, "%s:%u: vlog95 sorry: Post-decrement " "operator is not currently translated.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 4a57e6616..7c3d2e42c 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.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 @@ -606,7 +606,7 @@ static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex, ivl_lpm_t lpm = 0; ivl_net_const_t net_const = 0; ivl_net_logic_t nlogic = 0; - ivl_signal_t sig = 0; + ivl_signal_t sig; /* Look for a signal in the local scope first. */ sig = find_local_signal(scope, nex, array_word); if (sig) return sig; @@ -692,12 +692,11 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) 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); - fprintf(vlog_out, "[%d]", array_word); + int array_idx = (int) array_word + ivl_signal_array_base(sig); + fprintf(vlog_out, "[%d]", array_idx); } - msb = ivl_signal_msb(sig); - lsb = ivl_signal_lsb(sig); + get_sig_msb_lsb(sig, &msb, &lsb); if (sign_extend) { assert(base != lsb); if (msb >= lsb) base += lsb; @@ -1222,8 +1221,7 @@ static void emit_lpm_part_pv(ivl_scope_t scope, ivl_lpm_t lpm) if (ivl_signal_dimensions(sig)) { fprintf(vlog_out, "[%"PRId64"]", array_word); } - msb = ivl_signal_msb(sig); - lsb = ivl_signal_lsb(sig); + get_sig_msb_lsb(sig, &msb, &lsb); fprintf(vlog_out, "["); if (width == 1) { if (msb >= lsb) base += lsb; @@ -1853,6 +1851,9 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) case IVL_VT_BOOL: fprintf(stderr, " bool"); break; case IVL_VT_LOGIC: fprintf(stderr, " logic"); break; case IVL_VT_STRING: fprintf(stderr, " string"); break; + case IVL_VT_DARRAY: fprintf(stderr, " dynamic array"); + case IVL_VT_CLASS: fprintf(stderr, " class"); + break; } } else { fprintf(stderr, "Error: No/missing information!"); diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index 492f88f68..f37073ef0 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -171,7 +171,7 @@ void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr, unsigned is_stmt) if (rtype > 0) { fprintf(vlog_out, ""); fprintf(stderr, "%s:%u: vlog95 error: Time value is " - "greater than 64 bits (%u) and cannot be " + "greater than 64 bits (%d) and cannot be " "safely represented.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), rtype); @@ -857,3 +857,27 @@ void emit_id(const char *id) if (is_escaped(id)) fprintf(vlog_out, "\\%s ", id); else fprintf(vlog_out, "%s", id); } + +/* + * Get the correct MSB and LSB for a signal. + */ +void get_sig_msb_lsb(ivl_signal_t sig, int *msb, int *lsb) +{ + switch (ivl_signal_packed_dimensions(sig)) { + /* For a scalar we use zero for both the MSB and LSB. */ + case 0: + *msb = 0; + *lsb = 0; + break; + case 1: + /* For a vector we use the real MSB and LSB. */ + *msb = ivl_signal_packed_msb(sig, 0); + *lsb = ivl_signal_packed_lsb(sig, 0); + break; + /* For a packed vector we use the normalized MSB and LSB. */ + default: + *msb = ivl_signal_width(sig) - 1; + *lsb = 0; + break; + } +} diff --git a/tgt-vlog95/numbers.c b/tgt-vlog95/numbers.c index e81b4e0a1..3579f5018 100644 --- a/tgt-vlog95/numbers.c +++ b/tgt-vlog95/numbers.c @@ -140,7 +140,7 @@ void emit_number(const char *bits, unsigned nbits, unsigned is_signed, if (rtype > 0) { fprintf(vlog_out, ""); fprintf(stderr, "%s:%u: vlog95 error: Signed number is " - "greater than 32 bits (%u) and cannot be " + "greater than 32 bits (%d) and cannot be " "safely represented.\n", file, lineno, rtype); vlog_errors += 1; diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index a3bc6b34e..8a81b7f34 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.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 @@ -61,8 +61,8 @@ void emit_func_return(ivl_signal_t sig) } else if (ivl_signal_data_type(sig) == IVL_VT_REAL) { fprintf(vlog_out, " real"); } else { - int msb = ivl_signal_msb(sig); - int lsb = ivl_signal_lsb(sig); + int msb, lsb; + get_sig_msb_lsb(sig, &msb, &lsb); if (msb != 0 || lsb != 0) fprintf(vlog_out, " [%d:%d]", msb, lsb); } } @@ -108,9 +108,24 @@ void emit_var_def(ivl_signal_t sig) ivl_signal_basename(sig)); vlog_errors += 1; } + } else if (ivl_signal_data_type(sig) == IVL_VT_STRING) { + fprintf(vlog_out, "string "); + emit_sig_id(sig); + fprintf(stderr, "%s:%u: vlog95 error: SystemVerilog strings (%s) " + "are not supported.\n", ivl_signal_file(sig), + ivl_signal_lineno(sig), ivl_signal_basename(sig)); + vlog_errors += 1; + } else if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) { + fprintf(vlog_out, " "); + emit_sig_id(sig); + fprintf(stderr, "%s:%u: vlog95 error: SystemVerilog dynamic " + "arrays (%s) are not supported.\n", + ivl_signal_file(sig), + ivl_signal_lineno(sig), ivl_signal_basename(sig)); + vlog_errors += 1; } else { - int msb = ivl_signal_msb(sig); - int lsb = ivl_signal_lsb(sig); + int msb, lsb; + get_sig_msb_lsb(sig, &msb, &lsb); fprintf(vlog_out, "reg "); if (ivl_signal_signed(sig)) { if (allow_signed) { @@ -184,8 +199,8 @@ static void save_net_constants(ivl_scope_t scope, ivl_signal_t sig) void emit_net_def(ivl_scope_t scope, ivl_signal_t sig) { - int msb = ivl_signal_msb(sig); - int lsb = ivl_signal_lsb(sig); + int msb, lsb; + get_sig_msb_lsb(sig, &msb, &lsb); if (ivl_signal_local(sig)) return; fprintf(vlog_out, "%*c", indent, ' '); if (ivl_signal_data_type(sig) == IVL_VT_REAL){ @@ -402,8 +417,8 @@ static void emit_sig_type(ivl_signal_t sig) } else if (ivl_signal_data_type(sig) == IVL_VT_REAL) { fprintf(vlog_out, " real"); } else { - int msb = ivl_signal_msb(sig); - int lsb = ivl_signal_lsb(sig); + int msb, lsb; + get_sig_msb_lsb(sig, &msb, &lsb); if (ivl_signal_signed(sig)) { if (allow_signed) { fprintf(vlog_out, " signed"); @@ -432,8 +447,8 @@ static void emit_sig_type(ivl_signal_t sig) ivl_signal_basename(sig)); vlog_errors += 1; } else { - int msb = ivl_signal_msb(sig); - int lsb = ivl_signal_lsb(sig); + int msb, lsb; + get_sig_msb_lsb(sig, &msb, &lsb); if (ivl_signal_signed(sig)) { if (allow_signed) { fprintf(vlog_out, " signed"); @@ -729,6 +744,14 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) assert(indent != 0); emit_named_block_scope(scope); return 0; /* A named begin/fork is handled in line. */ + case IVL_SCT_GENERATE: + fprintf(stderr, "%s:%u: vlog95 sorry: generate scopes are not " + "currently translated \"%s\".\n", + ivl_scope_file(scope), + ivl_scope_lineno(scope), + ivl_scope_tname(scope)); + vlog_errors += 1; + return 0; default: fprintf(stderr, "%s:%u: vlog95 error: Unsupported scope type " "(%d) named: %s.\n", ivl_scope_file(scope), diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 31ee451a5..d34cdd97b 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.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 @@ -191,8 +191,7 @@ static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval) } /* We have some kind of select. */ - lsb = ivl_signal_lsb(sig); - msb = ivl_signal_msb(sig); + get_sig_msb_lsb(sig, &msb, &lsb); sel_type = ivl_lval_sel_type(lval); assert(sel_expr); /* A bit select. */ @@ -319,6 +318,68 @@ static unsigned is_delayed_or_event_assign(ivl_scope_t scope, return 1; } +/* + * A common routine to emit the basic assignment construct. It can also + * translate an assignment with an opcode when allowed. + */ +static void emit_assign_and_opt_opcode(ivl_scope_t scope, ivl_statement_t stmt, + unsigned allow_opcode) +{ + unsigned wid; + char opcode, *opcode_str; + + assert (ivl_statement_type(stmt) == IVL_ST_ASSIGN); +// HERE: Do we need to calculate the width? The compiler should have already +// done this for us. + wid = emit_stmt_lval(scope, stmt); + /* Get the opcode and the string version of the opcode. */ + opcode = ivl_stmt_opcode(stmt); + switch (opcode) { + case 0: opcode_str = ""; break; + case '+': opcode_str = "+"; break; + case '-': opcode_str = "-"; break; + case '*': opcode_str = "*"; break; + case '/': opcode_str = "/"; break; + case '%': opcode_str = "%"; break; + case '&': opcode_str = "&"; break; + case '|': opcode_str = "|"; break; + case '^': opcode_str = "^"; break; + case 'l': opcode_str = "<<"; break; + case 'r': opcode_str = ">>"; break; + case 'R': opcode_str = ">>>"; break; + default: + fprintf(stderr, "%s:%u: vlog95 error: unknown assignment operator " + "(%c).\n", + ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), + opcode); + vlog_errors += 1; + opcode_str = ""; + break; + } + if (opcode && ! allow_opcode) { + fprintf(stderr, "%s:%u: vlog95 error: assignment operator %s= is " + "not allowed in this context.\n", + ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), + opcode_str); + vlog_errors += 1; + } + fprintf(vlog_out, " = "); + if (opcode) { + unsigned twid = emit_stmt_lval(scope, stmt); + assert(twid == wid); + fprintf(vlog_out, " %s ", opcode_str); + /* The >>>= assignment operator is only allowed when the allow + * signed flag is true. */ + if ((! allow_signed) && (opcode == 'R')) { + fprintf(stderr, "%s:%u: vlog95 error: >>>= operator is not " + "supported.\n", + ivl_stmt_file(stmt), ivl_stmt_lineno(stmt)); + vlog_errors += 1; + } + } + emit_expr(scope, ivl_stmt_rval(stmt), wid); +} + /* * Icarus translated for(; ; ) into * @@ -334,7 +395,6 @@ static unsigned is_delayed_or_event_assign(ivl_scope_t scope, */ static unsigned is_for_loop(ivl_scope_t scope, ivl_statement_t stmt) { - unsigned wid; ivl_statement_t assign, while_lp, while_blk, body, incr_assign; /* We must have two block elements. */ @@ -368,22 +428,14 @@ static unsigned is_for_loop(ivl_scope_t scope, ivl_statement_t stmt) /* The pattern matched so generate the appropriate code. */ fprintf(vlog_out, "%*cfor(", get_indent(), ' '); - /* Emit the initialization statement. */ -// HERE: Do we need to calculate the width? The compiler should have already -// done this for us. - wid = emit_stmt_lval(scope, assign); - fprintf(vlog_out, " = "); - emit_expr(scope, ivl_stmt_rval(assign), wid); + /* Emit the initialization statement (no opcode is allowed). */ + emit_assign_and_opt_opcode(scope, assign, 0); fprintf(vlog_out, "; "); /* Emit the condition. */ emit_expr(scope, ivl_stmt_cond_expr(while_lp), 0); fprintf(vlog_out, "; "); - /* Emit in increment statement. */ -// HERE: Do we need to calculate the width? The compiler should have already -// done this for us. - wid = emit_stmt_lval(scope, incr_assign); - fprintf(vlog_out, " = "); - emit_expr(scope, ivl_stmt_rval(incr_assign), wid); + /* Emit the increment statement (an opcode is allowed). */ + emit_assign_and_opt_opcode(scope, incr_assign, 1); fprintf(vlog_out, ")"); emit_stmt_file_line(stmt); /* Now emit the body. */ @@ -728,13 +780,9 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope, static void emit_stmt_assign(ivl_scope_t scope, ivl_statement_t stmt) { - unsigned wid; fprintf(vlog_out, "%*c", get_indent(), ' '); -// HERE: Do we need to calculate the width? The compiler should have already -// done this for us. - wid = emit_stmt_lval(scope, stmt); - fprintf(vlog_out, " = "); - emit_expr(scope, ivl_stmt_rval(stmt), wid); + /* Emit the basic assignment (an opcode is allowed).*/ + emit_assign_and_opt_opcode(scope, stmt, 1); fprintf(vlog_out, ";"); emit_stmt_file_line(stmt); fprintf(vlog_out, "\n"); @@ -1119,6 +1167,20 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) emit_stmt_fork(scope, stmt); } break; + case IVL_ST_FORK_JOIN_ANY: + fprintf(stderr, "%s:%u: vlog95 sorry: fork/join_any is not " + "currently translated.\n", + ivl_stmt_file(stmt), + ivl_stmt_lineno(stmt)); + vlog_errors += 1; + break; + case IVL_ST_FORK_JOIN_NONE: + fprintf(stderr, "%s:%u: vlog95 sorry: fork/join_none is not " + "currently translated.\n", + ivl_stmt_file(stmt), + ivl_stmt_lineno(stmt)); + vlog_errors += 1; + break; case IVL_ST_FREE: /* This statement is only used with an automatic task so we * can safely skip it. The automatic task definition will @@ -1169,6 +1231,13 @@ void emit_process(ivl_scope_t scope, ivl_process_t proc) case IVL_PR_ALWAYS: fprintf(vlog_out, "always"); break; + case IVL_PR_FINAL: + fprintf(vlog_out, "final"); + fprintf(stderr, "%s:%u: vlog95 sorry: final blocks are not " + "currently translated.\n", + ivl_process_file(proc), ivl_process_lineno(proc)); + vlog_errors+= 1; + break; default: fprintf(vlog_out, ""); fprintf(stderr, "%s:%u: vlog95 error: Unknown process type (%d).\n", diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index 12ce11cc0..9e22637e1 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -119,6 +119,11 @@ extern int32_t get_int32_from_number(ivl_expr_t expr, int *return_type); extern int64_t get_int64_from_number(ivl_expr_t expr, int *return_type); extern uint64_t get_uint64_from_number(ivl_expr_t expr, int *return_type); +/* + * Get the appropriate MSB and LSB for a signal. + */ +extern void get_sig_msb_lsb(ivl_signal_t sig, int *msb, int *lsb); + /* * Cleanup functions. */ diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index 9edeb32ec..0aee3a915 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # #ident "$Id: Makefile.in,v 1.26 2007/02/06 05:07:32 steve Exp $" # @@ -48,8 +47,10 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -O = vvp.o draw_enum.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \ - eval_bool.o eval_expr.o eval_real.o modpath.o stmt_assign.o vector.o \ +O = vvp.o draw_class.o draw_enum.o draw_mux.o draw_net_input.o \ + draw_switch.o draw_ufunc.o draw_vpi.o \ + eval_bool.o eval_expr.o eval_object.o eval_real.o eval_string.o \ + modpath.o stmt_assign.o vector.o \ vvp_process.o vvp_scope.o all: dep vvp.tgt vvp.conf vvp-s.conf diff --git a/tgt-vvp/draw_class.c b/tgt-vvp/draw_class.c new file mode 100644 index 000000000..a4d6b6894 --- /dev/null +++ b/tgt-vvp/draw_class.c @@ -0,0 +1,46 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +# include "vvp_priv.h" +# include +# include +# include +# include + +static void show_prop_type(ivl_type_t ptype) +{ + // XXXX: For now, assume all properties are 32bit integers. + fprintf(vvp_out, "\"b32\""); +} + +void draw_class_in_scope(ivl_type_t classtype) +{ + int idx; + fprintf(vvp_out, "C%p .class \"%s\" [%d]\n", + classtype, ivl_type_name(classtype), ivl_type_properties(classtype)); + + for (idx = 0 ; idx < ivl_type_properties(classtype) ; idx += 1) { + fprintf(vvp_out, " %3d: \"%s\", ", idx, ivl_type_prop_name(classtype,idx)); + show_prop_type(ivl_type_prop_type(classtype,idx)); + fprintf(vvp_out, "\n"); + } + + fprintf(vvp_out, " ;\n"); +} diff --git a/tgt-vvp/draw_enum.c b/tgt-vvp/draw_enum.c index b4eb94573..ddc8cff09 100644 --- a/tgt-vvp/draw_enum.c +++ b/tgt-vvp/draw_enum.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index 234834900..2e3585b35 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" @@ -96,7 +96,7 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz) input[2] = draw_net_input(ivl_lpm_select(net)); fprintf(vvp_out, "L_%p%s .functor %s %u", net, dly, muxz, width); if (str0!=IVL_DR_STRONG || str1!=IVL_DR_STRONG) - fprintf(vvp_out, " [%u %u]", str0, str1); + fprintf(vvp_out, " [%d %d]", str0, str1); fprintf(vvp_out, ", %s", input[0]); fprintf(vvp_out, ", %s", input[1]); fprintf(vvp_out, ", %s", input[2]); @@ -127,15 +127,15 @@ static void draw_lpm_mux_nest(ivl_lpm_t net, const char*muxz) } for (level = 1 ; level < swidth-1 ; level += 1) { - fprintf(vvp_out, "L_%p/%ds .part %s, %d, 1;\n", + fprintf(vvp_out, "L_%p/%us .part %s, %u, 1;\n", net, level, select_input, level); for (idx = 0 ; idx < (ivl_lpm_size(net) >> level); idx += 2) { - fprintf(vvp_out, "L_%p/%d/%d .functor %s %u", + fprintf(vvp_out, "L_%p/%u/%d .functor %s %u", net, level, idx/2, muxz, width); fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx+0); fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx+1); - fprintf(vvp_out, ", L_%p/%ds", net, level); + fprintf(vvp_out, ", L_%p/%us", net, level); fprintf(vvp_out, ", C4<>;\n"); } diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index 5b7de3472..b48a6fe78 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" @@ -85,17 +85,6 @@ static ivl_variable_type_t signal_data_type_of_nexus(ivl_nexus_t nex) return out; } -static void draw_C4_repeated_constant(char bit_char, unsigned width) -{ - unsigned idx; - - fprintf(vvp_out, "C4<"); - for (idx = 0 ; idx < width ; idx += 1) - fprintf(vvp_out, "%c", bit_char); - - fprintf(vvp_out, ">"); -} - static char* draw_C4_to_string(ivl_net_const_t cptr) { const char*bits = ivl_const_bits(cptr); @@ -648,10 +637,10 @@ static void draw_net_input_x(ivl_nexus_t nex, ivl_signal_type_t res; char result[512]; unsigned idx; - int level; + char**driver_labels; unsigned ndrivers = 0; - const char*resolv_type, *branch_type; + const char*resolv_type; char*nex_private = 0; @@ -663,31 +652,25 @@ static void draw_net_input_x(ivl_nexus_t nex, case IVL_SIT_TRI: case IVL_SIT_UWIRE: resolv_type = "tri"; - branch_type = "tri"; break; case IVL_SIT_TRI0: resolv_type = "tri0"; - branch_type = "tri"; nex_flags |= VVP_NEXUS_DATA_STR; break; case IVL_SIT_TRI1: resolv_type = "tri1"; - branch_type = "tri"; nex_flags |= VVP_NEXUS_DATA_STR; break; case IVL_SIT_TRIAND: resolv_type = "triand"; - branch_type = "triand"; break; case IVL_SIT_TRIOR: resolv_type = "trior"; - branch_type = "trior"; break; default: - fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res); + fprintf(stderr, "vvp.tgt: Unsupported signal type: %d\n", res); assert(0); resolv_type = "tri"; - branch_type = "tri"; break; } @@ -835,46 +818,17 @@ static void draw_net_input_x(ivl_nexus_t nex, display_multi_driver_error(nex, ndrivers, MDRV_REAL); } - level = 0; - while (ndrivers) { - unsigned int inst; - for (inst = 0; inst < ndrivers; inst += 4) { - char*drive[4]; - if (level == 0) { - for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) { - drive[idx-inst] = draw_net_input_drive(nex, drivers[idx]); - } - } - - if (ndrivers > 4) - fprintf(vvp_out, "RS_%p/%d/%d .resolv %s", - nex, level, inst, branch_type); - else - fprintf(vvp_out, "RS_%p .resolv %s", - nex, resolv_type); - - for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) { - if (level) { - fprintf(vvp_out, ", RS_%p/%d/%d", - nex, level - 1, idx*4); - } else { - fprintf(vvp_out, ", %s", drive[idx-inst]); - free(drive[idx-inst]); - } - } - for ( ; idx < inst+4 ; idx += 1) { - fprintf(vvp_out, ", "); - draw_C4_repeated_constant('z',width_of_nexus(nex)); - } - - fprintf(vvp_out, ";\n"); - } - if (ndrivers > 4) - ndrivers = (ndrivers+3) / 4; - else - ndrivers = 0; - level += 1; + driver_labels = malloc(ndrivers * sizeof(char*)); + for (idx = 0; idx < ndrivers; idx += 1) { + driver_labels[idx] = draw_net_input_drive(nex, drivers[idx]); } + fprintf(vvp_out, "RS_%p .resolv %s", nex, resolv_type); + for (idx = 0; idx < ndrivers; idx += 1) { + fprintf(vvp_out, ", %s", driver_labels[idx]); + free(driver_labels[idx]); + } + fprintf(vvp_out, ";\n"); + free(driver_labels); snprintf(result, sizeof result, "RS_%p", nex); diff --git a/tgt-vvp/draw_switch.c b/tgt-vvp/draw_switch.c index 59d60614b..b53d214b0 100644 --- a/tgt-vvp/draw_switch.c +++ b/tgt-vvp/draw_switch.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" diff --git a/tgt-vvp/draw_ufunc.c b/tgt-vvp/draw_ufunc.c index a7b6ecd10..66942988f 100644 --- a/tgt-vvp/draw_ufunc.c +++ b/tgt-vvp/draw_ufunc.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" @@ -46,13 +46,11 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t expr) static void function_argument_real(ivl_signal_t port, ivl_expr_t expr) { - int res = draw_eval_real(expr); - /* ports cannot be arrays. */ assert(ivl_signal_dimensions(port) == 0); - fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res); - clr_word(res); + draw_eval_real(expr); + fprintf(vvp_out, " %%store/real v%p_0;\n", port); } static void function_argument_bool(ivl_signal_t port, ivl_expr_t expr) @@ -160,11 +158,10 @@ struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid) return res; } -int draw_ufunc_real(ivl_expr_t expr) +void draw_ufunc_real(ivl_expr_t expr) { ivl_scope_t def = ivl_expr_def(expr); ivl_signal_t retval = ivl_scope_port(def, 0); - int res = 0; unsigned idx; /* If this is an automatic function, allocate the local storage. */ @@ -188,13 +185,11 @@ int draw_ufunc_real(ivl_expr_t expr) assert(ivl_signal_dimensions(retval) == 0); /* Load the result into a word. */ - res = allocate_word(); - fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, retval); + fprintf(vvp_out, " %%load/real v%p_0;\n", retval); /* If this is an automatic function, free the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%free S_%p;\n", def); } - return res; } diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index ef4bf50c0..f7e52ad7a 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" @@ -31,6 +31,12 @@ struct args_info { char*text; int vec_flag; /* True if the vec must be released. */ struct vector_info vec; + /* True if this argument is a calculated string. */ + char str_flag; + /* True if this argument is a calculated real. */ + char real_flag; + /* Stack position if this argument is a calculated string. */ + unsigned stack; struct args_info *child; /* Arguments can be nested. */ }; @@ -178,6 +184,18 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL && ivl_expr_type(vexpr) != IVL_EX_SELECT) return 0; + /* If the expression is a substring expression, then + the xPV method of passing the argument will not work + and we have to resort to the default method. */ + if (ivl_expr_value(vexpr) == IVL_VT_STRING) + return 0; + + /* If the sub-expression is a DARRAY, then this select + is a dynamic-array word select. Handle that + elsewhere. */ + if (ivl_expr_value(vexpr) == IVL_VT_DARRAY) + return 0; + /* The signal is part of an array. */ /* Add &APV<> code here when it is finished. */ bexpr = ivl_expr_oper2(expr); @@ -265,6 +283,12 @@ static void draw_vpi_taskfunc_args(const char*call_string, ivl_parameter_t par; + /* Keep track of how much string stack this function call is + going to need. We'll need this for making stack references, + and also to clean out the stack when done. */ + unsigned str_stack_need = 0; + unsigned real_stack_need = 0; + /* Figure out how many expressions are going to be evaluated for this task call. I won't need to evaluate expressions for items that are VPI objects directly. */ @@ -312,11 +336,14 @@ static void draw_vpi_taskfunc_args(const char*call_string, case IVL_EX_STRING: if (( par = ivl_expr_parameter(expr) )) { snprintf(buffer, sizeof buffer, "P_%p", par); + args[idx].text = strdup(buffer); } else { - snprintf(buffer, sizeof buffer, "\"%s\"", ivl_expr_string(expr)); + size_t needed_len = strlen(ivl_expr_string(expr)) + 3; + args[idx].text = malloc(needed_len); + snprintf(args[idx].text, needed_len, "\"%s\"", + ivl_expr_string(expr)); } - args[idx].text = strdup(buffer); continue; case IVL_EX_REALNUM: @@ -369,15 +396,32 @@ static void draw_vpi_taskfunc_args(const char*call_string, ivl_expr_signed(expr)? "s" : "u"); break; case IVL_VT_REAL: - args[idx].vec_flag = 1; - args[idx].vec.base = draw_eval_real(expr); + draw_eval_real(expr); + args[idx].vec_flag = 0; + args[idx].vec.base = 0; args[idx].vec.wid = 0; - snprintf(buffer, sizeof buffer, - "W<%u,r>", args[idx].vec.base); + args[idx].str_flag = 0; + args[idx].real_flag = 1; + args[idx].stack = real_stack_need; + real_stack_need += 1; break; case IVL_VT_STRING: - /* STRING expressions not supported yet. */ + /* Eval the string into the stack, and tell VPI + about the stack position. */ + draw_eval_string(expr); + args[idx].vec_flag = 0; + args[idx].vec.base = 0; + args[idx].vec.wid = 0; + args[idx].str_flag = 1; + args[idx].stack = str_stack_need; + args[idx].real_flag = 0; + str_stack_need += 1; + buffer[0] = 0; + break; default: + fprintf(vvp_out, "\nXXXX Unexpected argument: call_string=<%s>, arg=%u, type=%d\n", + call_string, idx, ivl_expr_value(expr)); + fflush(vvp_out); assert(0); } args[idx].text = strdup(buffer); @@ -388,7 +432,19 @@ static void draw_vpi_taskfunc_args(const char*call_string, for (idx = 0 ; idx < parm_count ; idx += 1) { struct args_info*ptr; - fprintf(vvp_out, ", %s", args[idx].text); + if (args[idx].str_flag) { + /* If this is a string stack reference, then + calculate the stack depth and use that to + generate the completed string. */ + unsigned pos = str_stack_need - args[idx].stack - 1; + fprintf(vvp_out, ", S<%u,str>",pos); + } else if (args[idx].real_flag) { + unsigned pos = real_stack_need - args[idx].stack - 1; + fprintf(vvp_out, ", W<%u,r>",pos); + } else { + fprintf(vvp_out, ", %s", args[idx].text); + } + free(args[idx].text); /* Clear the nested children vectors. */ for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) { @@ -408,6 +464,7 @@ static void draw_vpi_taskfunc_args(const char*call_string, free(args); + fprintf(vvp_out, " {%u %u}", real_stack_need, str_stack_need); fprintf(vvp_out, ";\n"); } @@ -429,7 +486,7 @@ void draw_vpi_task_call(ivl_statement_t tnet) } if (parm_count == 0) { - fprintf(vvp_out, " %s %u %u \"%s\";\n", command, + fprintf(vvp_out, " %s %u %u \"%s\" {0 0};\n", command, ivl_file_table_index(ivl_stmt_file(tnet)), ivl_stmt_lineno(tnet), ivl_stmt_name(tnet)); } else { @@ -464,16 +521,13 @@ struct vector_info draw_vpi_func_call(ivl_expr_t fnet, unsigned wid) return res; } -int draw_vpi_rfunc_call(ivl_expr_t fnet) +void draw_vpi_rfunc_call(ivl_expr_t fnet) { char call_string[1024]; - int res = allocate_word(); - sprintf(call_string, " %%vpi_func/r %u %u \"%s\", %d", + sprintf(call_string, " %%vpi_func/r %u %u \"%s\"", ivl_file_table_index(ivl_expr_file(fnet)), - ivl_expr_lineno(fnet), ivl_expr_name(fnet), res); + ivl_expr_lineno(fnet), ivl_expr_name(fnet)); draw_vpi_taskfunc_args(call_string, 0, fnet); - - return res; } diff --git a/tgt-vvp/eval_bool.c b/tgt-vvp/eval_bool.c index e37a51f75..d0441ed11 100644 --- a/tgt-vvp/eval_bool.c +++ b/tgt-vvp/eval_bool.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 3e7b548d0..f965a75f8 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" @@ -277,8 +277,6 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) */ void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix) { - int word; - switch (ivl_expr_value(expr)) { case IVL_VT_BOOL: @@ -287,9 +285,8 @@ void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix) break; case IVL_VT_REAL: - word = draw_eval_real(expr); - fprintf(vvp_out, " %%cvt/sr %u, %u;\n", ix, word); - clr_word(word); + draw_eval_real(expr); + fprintf(vvp_out, " %%cvt/sr %u;\n", ix); break; default: @@ -428,19 +425,15 @@ static struct vector_info draw_eq_immediate(ivl_expr_t expr, unsigned ewid, static struct vector_info draw_binary_expr_eq_real(ivl_expr_t expr) { struct vector_info res; - int lword, rword; res.base = allocate_vector(1); res.wid = 1; assert(res.base); - lword = draw_eval_real(ivl_expr_oper1(expr)); - rword = draw_eval_real(ivl_expr_oper2(expr)); + draw_eval_real(ivl_expr_oper1(expr)); + draw_eval_real(ivl_expr_oper2(expr)); - clr_word(lword); - clr_word(rword); - - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", lword, rword); + fprintf(vvp_out, " %%cmp/wr;\n"); switch (ivl_expr_opcode(expr)) { case 'e': @@ -459,6 +452,86 @@ static struct vector_info draw_binary_expr_eq_real(ivl_expr_t expr) return res; } +static struct vector_info draw_binary_expr_eq_string(ivl_expr_t expr) +{ + ivl_expr_t le = ivl_expr_oper1(expr); + ivl_expr_t re = ivl_expr_oper2(expr); + + struct vector_info res; + res.base = allocate_vector(1); + res.wid = 1; + assert(res.base); + + draw_eval_string(le); + draw_eval_string(re); + + fprintf(vvp_out, " %%cmp/str;\n"); + + switch (ivl_expr_opcode(expr)) { + + case 'e': /* == */ + fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); + break; + + case 'n': /* != */ + fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); + fprintf(vvp_out, " %%inv %u, 1;\n", res.base); + break; + + default: + assert(0); + } + + return res; +} + +static struct vector_info draw_binary_expr_eq_class(ivl_expr_t expr) +{ + ivl_expr_t le = ivl_expr_oper1(expr); + ivl_expr_t re = ivl_expr_oper2(expr); + + struct vector_info res; + res.base = allocate_vector(1); + res.wid = 1; + assert(res.base); + + if (ivl_expr_type(le) == IVL_EX_NULL) { + ivl_expr_t tmp = le; + le = re; + re = tmp; + } + + /* Special case: If both operands are null, then the + expression has a constant value. */ + if (ivl_expr_type(le)==IVL_EX_NULL && ivl_expr_type(re)==IVL_EX_NULL) { + switch (ivl_expr_opcode(expr)) { + case 'e': /* == */ + fprintf(vvp_out, " %%mov %u, 1, 1;\n", res.base); + break; + case 'n': /* != */ + fprintf(vvp_out, " %%mov %u, 0, 1;\n", res.base); + break; + default: + assert(0); + break; + } + return res; + } + + if (ivl_expr_type(re) == IVL_EX_NULL && ivl_expr_type(le)==IVL_EX_SIGNAL) { + fprintf(vvp_out, " %%test_nul v%p_0;\n", ivl_expr_signal(le)); + fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base); + if (ivl_expr_opcode(expr) == 'n') + fprintf(vvp_out, " %%inv %u, 1;\n", res.base); + return res; + } + + fprintf(stderr, "SORRY: Compare class handles not implemented\n"); + fprintf(vvp_out, " ; XXXX compare class handles.\n"); + vvp_errors += 1; + return res; +} + static struct vector_info draw_binary_expr_eq(ivl_expr_t expr, unsigned ewid, int stuff_ok_flag) @@ -476,13 +549,35 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t expr, return draw_binary_expr_eq_real(expr); } + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_eq_string(expr); + } + + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_type(re) == IVL_EX_STRING)) { + return draw_binary_expr_eq_string(expr); + } + + if ((ivl_expr_type(le) == IVL_EX_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_eq_string(expr); + } + + if ((ivl_expr_value(le) == IVL_VT_CLASS) + && (ivl_expr_value(re) == IVL_VT_CLASS)) { + return draw_binary_expr_eq_class(expr); + } + if (number_is_immediate(re,16,0) && !number_is_unknown(re)) return draw_eq_immediate(expr, ewid, le, re, stuff_ok_flag); assert(ivl_expr_value(le) == IVL_VT_LOGIC - || ivl_expr_value(le) == IVL_VT_BOOL); + || ivl_expr_value(le) == IVL_VT_BOOL + || ivl_expr_value(le) == IVL_VT_STRING); assert(ivl_expr_value(re) == IVL_VT_LOGIC - || ivl_expr_value(re) == IVL_VT_BOOL); + || ivl_expr_value(re) == IVL_VT_BOOL + || ivl_expr_value(re) == IVL_VT_STRING); wid = ivl_expr_width(le); if (ivl_expr_width(re) > wid) @@ -784,36 +879,90 @@ static struct vector_info draw_binary_expr_le_real(ivl_expr_t expr) ivl_expr_t le = ivl_expr_oper1(expr); ivl_expr_t re = ivl_expr_oper2(expr); - int lword = draw_eval_real(le); - int rword = draw_eval_real(re); res.base = allocate_vector(1); res.wid = 1; assert(res.base); - clr_word(lword); - clr_word(rword); - switch (ivl_expr_opcode(expr)) { case '<': - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", lword, rword); + draw_eval_real(le); + draw_eval_real(re); + fprintf(vvp_out, " %%cmp/wr;\n"); fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); break; case 'L': /* <= */ - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", lword, rword); + draw_eval_real(le); + draw_eval_real(re); + fprintf(vvp_out, " %%cmp/wr;\n"); fprintf(vvp_out, " %%or 5, 4, 1;\n"); fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); break; case '>': - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", rword, lword); + draw_eval_real(re); + draw_eval_real(le); + fprintf(vvp_out, " %%cmp/wr;\n"); fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); break; case 'G': /* >= */ - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", rword, lword); + draw_eval_real(re); + draw_eval_real(le); + fprintf(vvp_out, " %%cmp/wr;\n"); + fprintf(vvp_out, " %%or 5, 4, 1;\n"); + fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); + break; + + default: + assert(0); + } + + return res; +} + +static struct vector_info draw_binary_expr_le_string(ivl_expr_t expr) +{ + struct vector_info res; + + ivl_expr_t le = ivl_expr_oper1(expr); + ivl_expr_t re = ivl_expr_oper2(expr); + + res.base = allocate_vector(1); + res.wid = 1; + + assert(res.base); + + /* The %cmp/str function implements < and <= operands. To get + the > and >= results, simply switch the order of the + operands. */ + switch (ivl_expr_opcode(expr)) { + case '<': + case 'L': + draw_eval_string(le); + draw_eval_string(re); + break; + case '>': + case 'G': + draw_eval_string(re); + draw_eval_string(le); + break; + default: + assert(0); + } + + switch (ivl_expr_opcode(expr)) { + case '<': + case '>': + fprintf(vvp_out, " %%cmp/str;\n"); + fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); + break; + + case 'L': /* <= */ + case 'G': /* >= */ + fprintf(vvp_out, " %%cmp/str;\n"); fprintf(vvp_out, " %%or 5, 4, 1;\n"); fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base); break; @@ -844,21 +993,21 @@ static struct vector_info draw_binary_expr_le_bool(ivl_expr_t expr, switch (ivl_expr_opcode(expr)) { case 'G': - fprintf(vvp_out, " %%cmp/w%c %u, %u;\n", s_flag, rw, lw); + fprintf(vvp_out, " %%cmp/w%c %d, %d;\n", s_flag, rw, lw); fprintf(vvp_out, " %%or 5, 4, 1;\n"); break; case 'L': - fprintf(vvp_out, " %%cmp/w%c %u, %u;\n", s_flag, lw, rw); + fprintf(vvp_out, " %%cmp/w%c %d, %d;\n", s_flag, lw, rw); fprintf(vvp_out, " %%or 5, 4, 1;\n"); break; case '<': - fprintf(vvp_out, " %%cmp/w%c %u, %u;\n", s_flag, lw, rw); + fprintf(vvp_out, " %%cmp/w%c %d, %d;\n", s_flag, lw, rw); break; case '>': - fprintf(vvp_out, " %%cmp/w%c %u, %u;\n", s_flag, rw, lw); + fprintf(vvp_out, " %%cmp/w%c %d, %d;\n", s_flag, rw, lw); break; default: @@ -919,6 +1068,21 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr, return draw_binary_expr_le_bool(expr, wid); } + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_le_string(expr); + } + + if ((ivl_expr_value(le) == IVL_VT_STRING) + && (ivl_expr_type(re) == IVL_EX_STRING)) { + return draw_binary_expr_le_string(expr); + } + + if ((ivl_expr_type(le) == IVL_EX_STRING) + && (ivl_expr_value(re) == IVL_VT_STRING)) { + return draw_binary_expr_eq_string(expr); + } + assert(ivl_expr_value(le) == IVL_VT_LOGIC || ivl_expr_value(le) == IVL_VT_BOOL); assert(ivl_expr_value(re) == IVL_VT_LOGIC @@ -1944,6 +2108,23 @@ static struct vector_info draw_number_expr(ivl_expr_t expr, unsigned wid) return res; } +static struct vector_info draw_property_expr(ivl_expr_t expr, unsigned wid) +{ + ivl_signal_t sig = ivl_expr_signal(expr); + unsigned pidx = ivl_expr_property_idx(expr); + + struct vector_info res; + res.base = allocate_vector(wid); + res.wid = wid; + + assert(res.base != 0); + + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + fprintf(vvp_out, " %%prop/v %u, %u, %u;\n", pidx, res.base, wid); + + return res; +} + /* * This little helper function generates the instructions to pad a * vector in place. It is assumed that the calling function has set up @@ -2237,13 +2418,9 @@ static void draw_signal_dest(ivl_expr_t expr, struct vector_info res, if (ivl_signal_data_type(sig) == IVL_VT_REAL) { - int tmp; - assert(add_index < 0); - tmp = allocate_word(); - fprintf(vvp_out, " %%load/wr %d, v%p_%u;\n", tmp, sig, word); - fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n", res.base, tmp, res.wid); - clr_word(tmp); + fprintf(vvp_out, " %%load/real v%p_%u;\n", sig, word); + fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid); } else if (add_index >= 0) { @@ -2322,14 +2499,14 @@ static struct vector_info draw_select_array(ivl_expr_t sube, /* We can safely skip the bit index load below if the array word * index is undefined. We need to do this so that the bit index * load does not reset bit 4 to zero by loading a defined value. */ - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, label); + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count, label); if (ivl_expr_signed(bit_idx)) { fprintf(vvp_out, " %%ix/get/s 0, %u, %u;\n", shiv.base, shiv.wid); } else { fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid); } - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, label); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, label); if (shiv.base >= 8) clr_vector(shiv); @@ -2363,6 +2540,17 @@ static struct vector_info draw_select_signal(ivl_expr_t expr, unsigned use_word = 0; unsigned use_wid, lab_x, lab_end; + /* Special case: the sub expression is a DARRAY variable, so + do a dynamic array word load. */ + if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) { + res.base = allocate_vector(wid); + res.wid = wid; + draw_eval_expr_into_integer(bit_idx, 3); + fprintf(vvp_out, " %%load/dar %u, v%p_0, %u;\n", + res.base, sig, res.wid); + return res; + } + /* If this is an access to an array, try to get the index as a constant. If it is (and the array is not a reg array then this reduces to a signal access and we stay here. If it is @@ -2415,7 +2603,7 @@ static struct vector_info draw_select_signal(ivl_expr_t expr, lab_end = local_count++; /* If the index is 'bx then we just return 'bx. */ - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, lab_x); + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count, lab_x); use_wid = res.wid; if (use_wid > bit_wid) @@ -2427,10 +2615,10 @@ static struct vector_info draw_select_signal(ivl_expr_t expr, $signed() this may be signed or unsigned (default). */ pad_expr_in_place(expr, res, use_wid); - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_end); - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_x); + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_end); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_x); fprintf(vvp_out, " %%mov %u, 2, %u;\n", res.base, res.wid); - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_end); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_end); return res; } @@ -2589,7 +2777,7 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr, clr_vector(shiv); /* If we have an undefined index then just produce a 'bx result. */ - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, lab_x); + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count, lab_x); /* If the subv result is a magic constant, then make a copy in writable vector space and work from there instead. */ @@ -2621,14 +2809,14 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr, else fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", subv.base, subv.wid); - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_end); + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_end); - fprintf(vvp_out, "T_%d.%d ; Return 'bx value\n", thread_count, lab_x); + fprintf(vvp_out, "T_%u.%u ; Return 'bx value\n", thread_count, lab_x); fprintf(vvp_out, " %%mov %u, 2, %u;\n", subv.base, wid); - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_end); + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_end); /* DONE */ - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_end); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_end); if (subv.wid > wid) { res.base = subv.base; @@ -2646,6 +2834,25 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr, return res; } +static void draw_select_string_dest(ivl_expr_t expr, struct vector_info res) +{ + ivl_expr_t sube = ivl_expr_oper1(expr); + ivl_expr_t shift = ivl_expr_oper2(expr); + int shift_i; + + draw_eval_string(sube); + + shift_i = allocate_word(); + draw_eval_expr_into_integer(shift, shift_i); + + assert(res.wid % 8 == 0); + + clr_word(shift_i); + + fprintf(vvp_out, " %%substr/v %u, %d, %u;\n", res.base, shift_i, res.wid); + fprintf(vvp_out, " %%pop/str 1;\n"); +} + static struct vector_info draw_select_expr(ivl_expr_t expr, unsigned wid, int stuff_ok_flag) { @@ -2668,6 +2875,28 @@ static struct vector_info draw_select_expr(ivl_expr_t expr, unsigned wid, return res; } + /* Special case: The sub expression is a string, so do a + string select then a part select from that. */ + if (ivl_expr_value(sube) == IVL_VT_STRING) { + res.base = allocate_vector(wid); + res.wid = wid; + draw_select_string_dest(expr, res); + return res; + } + + /* Special case: The sub-expression is a DARRAY variable, so + do a dynamic array word load. */ + if (ivl_expr_value(sube) == IVL_VT_DARRAY) { + ivl_signal_t sig = ivl_expr_signal(sube); + assert(sig); + res.base = allocate_vector(wid); + res.wid = wid; + draw_eval_expr_into_integer(shift, 3); + fprintf(vvp_out, " %%load/dar %u, v%p_0, %u;\n", + res.base, sig, res.wid); + return res; + } + if (ivl_expr_type(sube) == IVL_EX_SIGNAL) { res = draw_select_signal(expr, sube, shift, ivl_expr_width(expr), wid); @@ -2721,24 +2950,24 @@ static struct vector_info draw_select_expr(ivl_expr_t expr, unsigned wid, lab_l = local_count++; lab_end = local_count++; /* If we have an undefined index then just produce a 'bx result. */ - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, lab_l); + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count, lab_l); cmp = allocate_word(); assert(subv.wid >= wid); /* Determine if we need to shift a 'bx into the top. */ - fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", cmp, subv.wid - wid); - fprintf(vvp_out, " %%cmp/ws %u, 0;\n", cmp); + fprintf(vvp_out, " %%ix/load %d, %u, 0;\n", cmp, subv.wid - wid); + fprintf(vvp_out, " %%cmp/ws %d, 0;\n", cmp); clr_word(cmp); - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 5;\n", thread_count, lab_l); + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 5;\n", thread_count, lab_l); /* Clear the cmp bit if the two values are equal. */ fprintf(vvp_out, " %%mov 4, 0, 1;\n"); fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", subv.base, subv.wid); - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_end); - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_l); + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_end); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_l); /* Multiply by -1. */ fprintf(vvp_out, " %%ix/mul 0, %u, %u;\n", 0xFFFFFFFF, 0xFFFFFFFF); fprintf(vvp_out, " %%shiftl/i0 %u, %u;\n", subv.base, subv.wid); - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_end); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_end); if (subv.wid > wid) { res.base = subv.base; @@ -2770,6 +2999,13 @@ static void draw_select_expr_dest(ivl_expr_t expr, struct vector_info dest, ivl_expr_t sube = ivl_expr_oper1(expr); ivl_expr_t shift= ivl_expr_oper2(expr); + /* Special case: The sub expression is a string, so do a + string select then a part select from that. */ + if (ivl_expr_value(sube) == IVL_VT_STRING) { + draw_select_string_dest(expr, dest); + return; + } + /* If the shift expression is not present, then this is really a pad expression, and that can be handled pretty easily. Evaluate the subexpression into the destination, @@ -2836,7 +3072,7 @@ static struct vector_info draw_ternary_expr(ivl_expr_t expr, unsigned wid) tst.wid = 1; } - fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u;\n", + fprintf(vvp_out, " %%jmp/0 T_%u.%u, %u;\n", thread_count, lab_true, tst.base); tru = draw_eval_expr_wid(true_ex, wid, 0); @@ -2853,17 +3089,17 @@ static struct vector_info draw_ternary_expr(ivl_expr_t expr, unsigned wid) tru = tmp; } - fprintf(vvp_out, " %%jmp/1 T_%d.%d, %u;\n", + fprintf(vvp_out, " %%jmp/1 T_%u.%u, %u;\n", thread_count, lab_out, tst.base); clear_expression_lookaside(); - fprintf(vvp_out, "T_%d.%d ; End of true expr.\n", + fprintf(vvp_out, "T_%u.%u ; End of true expr.\n", thread_count, lab_true); fal = draw_eval_expr_wid(false_ex, wid, 0); - fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u;\n", + fprintf(vvp_out, " %%jmp/0 T_%u.%u, %u;\n", thread_count, lab_false, tst.base); fprintf(vvp_out, " ; End of false expr.\n"); @@ -2873,15 +3109,15 @@ static struct vector_info draw_ternary_expr(ivl_expr_t expr, unsigned wid) fprintf(vvp_out, " %%blend %u, %u, %u; Condition unknown.\n", tru.base, fal.base, wid); - fprintf(vvp_out, " %%jmp T_%d.%d;\n", + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_out); - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_false); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_false); fprintf(vvp_out, " %%mov %u, %u, %u; Return false value\n", tru.base, fal.base, wid); /* This is the out label. */ - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out); clear_expression_lookaside(); res = tru; @@ -2897,7 +3133,6 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid) unsigned parm_count = ivl_expr_parms(expr); struct vector_info res; - /* If the function has no parameters, then use this short-form to draw the statement. */ if (parm_count == 0) { @@ -2906,7 +3141,7 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid) res.base = allocate_vector(wid); res.wid = wid; assert(res.base); - fprintf(vvp_out, " %%vpi_func %u %u \"%s\", %u, %u;\n", + fprintf(vvp_out, " %%vpi_func %u %u \"%s\", %u, %u {0 0};\n", ivl_file_table_index(ivl_expr_file(expr)), ivl_expr_lineno(expr), ivl_expr_name(expr), res.base, res.wid); @@ -3079,7 +3314,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid) struct vector_info res; ivl_expr_t sub = ivl_expr_oper1(expr); const char *rop = 0; - int word, inv = 0; + int inv = 0; switch (ivl_expr_opcode(expr)) { case '&': rop = "and"; break; @@ -3308,11 +3543,10 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid) break; case IVL_VT_REAL: - word = draw_eval_real(sub); + draw_eval_real(sub); res.base = allocate_vector(wid); res.wid = wid; - fprintf(vvp_out, " %%cvt/vr %d, %d, %u;\n", res.base, word, wid); - clr_word(word); + fprintf(vvp_out, " %%cvt/vr %d, %u;\n", res.base, wid); break; default: @@ -3322,12 +3556,10 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid) case 'v': /* Cast a real value to an integer. */ assert(ivl_expr_value(sub) == IVL_VT_REAL); - word = draw_eval_real(sub); + draw_eval_real(sub); res.base = allocate_vector(wid); res.wid = wid; - fprintf(vvp_out, " %%cvt/vr %u, %u, %u;\n", res.base, word, - res.wid); - clr_word(word); + fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid); break; case 'r': /* Handled in eval_real.c. */ @@ -3426,6 +3658,10 @@ struct vector_info draw_eval_expr_wid(ivl_expr_t expr, unsigned wid, res = draw_number_expr(expr, wid); break; + case IVL_EX_PROPERTY: + res = draw_property_expr(expr, wid); + break; + case IVL_EX_REALNUM: res = draw_realnum_expr(expr, wid); break; diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c new file mode 100644 index 000000000..e2b2acb80 --- /dev/null +++ b/tgt-vvp/eval_object.c @@ -0,0 +1,117 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "vvp_priv.h" +# include +# include + +static int eval_darray_new(ivl_expr_t ex) +{ + unsigned size_reg = allocate_word(); + ivl_expr_t size_expr = ivl_expr_oper1(ex); + draw_eval_expr_into_integer(size_expr, size_reg); + clr_word(size_reg); + + // The new function has a net_type that contains the details + // of the type. + ivl_type_t net_type = ivl_expr_net_type(ex); + assert(net_type); + + ivl_type_t element_type = ivl_type_element(net_type); + assert(element_type); + + switch (ivl_type_base(element_type)) { + case IVL_VT_REAL: + // REAL objects are not packable. + assert(ivl_type_packed_dimensions(element_type) == 0); + fprintf(vvp_out, " %%new/darray %u, \"r\";\n", size_reg); + break; + case IVL_VT_STRING: + // STRING objects are not packable. + assert(ivl_type_packed_dimensions(element_type) == 0); + fprintf(vvp_out, " %%new/darray %u, \"S\";\n", size_reg); + break; + case IVL_VT_BOOL: + // bool objects are vectorable, but for now only support + // a single dimensions. + assert(ivl_type_packed_dimensions(element_type) == 1); + int msb = ivl_type_packed_msb(element_type, 0); + int lsb = ivl_type_packed_lsb(element_type, 0); + int wid = msb>=lsb? msb - lsb : lsb - msb; + wid += 1; + + fprintf(vvp_out, " %%new/darray %u, \"sb%d\";\n", size_reg, wid); + break; + + default: + assert(0); + break; + } + + return 0; +} + +static int eval_class_new(ivl_expr_t ex) +{ + ivl_type_t class_type = ivl_expr_net_type(ex); + fprintf(vvp_out, " %%new/cobj C%p;\n", class_type); + return 0; +} + +static int eval_object_null(ivl_expr_t ex) +{ + fprintf(vvp_out, " %%null;\n"); + return 0; +} + +static int eval_object_signal(ivl_expr_t ex) +{ + ivl_signal_t sig = ivl_expr_signal(ex); + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + return 0; +} + +int draw_eval_object(ivl_expr_t ex) +{ + switch (ivl_expr_type(ex)) { + + case IVL_EX_NEW: + switch (ivl_expr_value(ex)) { + case IVL_VT_CLASS: + return eval_class_new(ex); + case IVL_VT_DARRAY: + return eval_darray_new(ex); + default: + fprintf(vvp_out, "; ERROR: draw_eval_object: Invalid type (%d) for \n", + ivl_expr_value(ex)); + return 0; + } + + case IVL_EX_NULL: + return eval_object_null(ex); + + case IVL_EX_SIGNAL: + return eval_object_signal(ex); + + default: + fprintf(vvp_out, "; ERROR: draw_eval_object: Invalid expression type %u\n", ivl_expr_type(ex)); + return 1; + + } +} diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 56fb2fe7b..77dedf262 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* @@ -52,10 +52,8 @@ void clr_word(int res) word_alloc_mask &= ~ (1U << res); } -static int draw_binary_real(ivl_expr_t expr) +static void draw_binary_real(ivl_expr_t expr) { - int l, r = -1; - switch (ivl_expr_opcode(expr)) { case 'E': case 'N': @@ -72,93 +70,52 @@ static int draw_binary_real(ivl_expr_t expr) assert(0); } - l = draw_eval_real(ivl_expr_oper1(expr)); - r = draw_eval_real(ivl_expr_oper2(expr)); + draw_eval_real(ivl_expr_oper1(expr)); + draw_eval_real(ivl_expr_oper2(expr)); switch (ivl_expr_opcode(expr)) { case '+': - fprintf(vvp_out, " %%add/wr %d, %d;\n", l, r); + fprintf(vvp_out, " %%add/wr;\n"); break; case '-': - fprintf(vvp_out, " %%sub/wr %d, %d;\n", l, r); + fprintf(vvp_out, " %%sub/wr;\n"); break; case '*': - fprintf(vvp_out, " %%mul/wr %d, %d;\n", l, r); + fprintf(vvp_out, " %%mul/wr;\n"); break; case '/': - fprintf(vvp_out, " %%div/wr %d, %d;\n", l, r); + fprintf(vvp_out, " %%div/wr;\n"); break; case '%': - fprintf(vvp_out, " %%mod/wr %d, %d;\n", l, r); + fprintf(vvp_out, " %%mod/wr;\n"); break; case 'p': - fprintf(vvp_out, " %%pow/wr %d, %d;\n", l, r); + fprintf(vvp_out, " %%pow/wr;\n"); break; - case 'm': { /* min(l,r) */ - int lab_out = local_count++; - int lab_r = local_count++; - /* If r is NaN, the go out and accept l as result. */ - fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, - lab_out); - /* If l is NaN, the go out and accept r as result. */ - fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, - lab_r); - /* If l <= r then go out. */ - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, - lab_out); - /* At this point we know we want r as the result. */ - fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, - lab_r, l, r); - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); - break; - } + case 'm': + fprintf(vvp_out, " %%min/wr;\n"); + break; - case 'M': { /* max(l,r) */ - int lab_out = local_count++; - int lab_r = local_count++; - /* If r is NaN, the go out and accept l as result. */ - fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, - lab_out); - /* If l is NaN, the go out and accept r as result. */ - fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, - lab_r); - /* if l >= r then go out. */ - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, - lab_out); - - fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, - lab_r, l, r); - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); - break; - } + case 'M': + fprintf(vvp_out, " %%max/wr;\n"); + break; default: fprintf(stderr, "XXXX draw_binary_real(%c)\n", ivl_expr_opcode(expr)); assert(0); } - - if (r >= 0) clr_word(r); - - return l; } -static int draw_number_real(ivl_expr_t expr) +static void draw_number_real(ivl_expr_t expr) { unsigned int idx; - int res = allocate_word(); const char*bits = ivl_expr_bits(expr); unsigned wid = ivl_expr_width(expr); unsigned long mant = 0; @@ -204,14 +161,12 @@ static int draw_number_real(ivl_expr_t expr) if (negate) vexp |= 0x4000; - fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load(num)= %c%lu (wid=%u)\n", - res, mant, vexp, (vexp&0x4000)? '-' : '+', mant, wid); - return res; + fprintf(vvp_out, " %%pushi/real %lu, %d; load(num)= %c%lu (wid=%u)\n", + mant, vexp, (vexp&0x4000)? '-' : '+', mant, wid); } -static int draw_realnum_real(ivl_expr_t expr) +static void draw_realnum_real(ivl_expr_t expr) { - int res = allocate_word(); double value = ivl_expr_dvalue(expr); double fract; @@ -222,18 +177,18 @@ static int draw_realnum_real(ivl_expr_t expr) /* Handle the special case that the value is +-inf. */ if (isinf(value)) { if (value > 0) - fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=+inf\n", - res, 0x3fff); + fprintf(vvp_out, " %%pushi/real 0, %d; load=+inf\n", + 0x3fff); else - fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=-inf\n", - res, 0x7fff); - return res; + fprintf(vvp_out, " %%pushi/real 0, %d; load=-inf\n", + 0x7fff); + return; } /* Handle the special case that the value is NaN. */ if (value != value) { - fprintf(vvp_out, " %%loadi/wr %d, 1, %d; load=NaN\n", - res, 0x3fff); - return res; + fprintf(vvp_out, " %%pushi/real 1, %d; load=NaN\n", + 0x3fff); + return; } if (value < 0) { @@ -251,8 +206,8 @@ static int draw_realnum_real(ivl_expr_t expr) assert(vexp < 0x2000); vexp += sign; - fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load=%#g\n", - res, mant, vexp, ivl_expr_dvalue(expr)); + fprintf(vvp_out, " %%pushi/real %lu, %d; load=%#g\n", + mant, vexp, ivl_expr_dvalue(expr)); /* Capture the residual bits, if there are any. Note that an IEEE754 mantissa has 52 bits, 31 of which were accounted @@ -268,59 +223,66 @@ static int draw_realnum_real(ivl_expr_t expr) vexp += sign; if (mant != 0) { - int tmp_word = allocate_word(); - fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load=%#g\n", - tmp_word, mant, vexp, ivl_expr_dvalue(expr)); - fprintf(vvp_out, " %%add/wr %d, %d;\n", res, tmp_word); - clr_word(tmp_word); + fprintf(vvp_out, " %%pushi/real %lu, %d; load=%#g\n", + mant, vexp, ivl_expr_dvalue(expr)); + fprintf(vvp_out, " %%add/wr;\n"); } - - return res; } /* * The real value of a logic expression is the integer value of the * expression converted to real. */ -static int draw_real_logic_expr(ivl_expr_t expr, int stuff_ok_flag) +static void draw_real_logic_expr(ivl_expr_t expr, int stuff_ok_flag) { - int res = allocate_word(); struct vector_info sv = draw_eval_expr(expr, stuff_ok_flag); const char*sign_flag = ivl_expr_signed(expr)? "/s" : ""; if (sv.wid > 64) { - fprintf(vvp_out, " %%cvt/rv%s %d, %u, %u;\n", - sign_flag, res, sv.base, sv.wid); + fprintf(vvp_out, " %%cvt/rv%s %u, %u;\n", + sign_flag, sv.base, sv.wid); } else { + int res = allocate_word(); fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", sign_flag, res, sv.base, sv.wid); if (ivl_expr_signed(expr)) - fprintf(vvp_out, " %%cvt/rs %d, %d;\n", res, res); + fprintf(vvp_out, " %%cvt/rs %d;\n", res); else - fprintf(vvp_out, " %%cvt/ru %d, %d;\n", res, res); + fprintf(vvp_out, " %%cvt/ru %d;\n", res); + clr_word(res); } clr_vector(sv); - - return res; } -static int draw_sfunc_real(ivl_expr_t expr) +static void draw_select_real(ivl_expr_t expr) { - int res; + /* The sube references the expression to be selected from. */ + ivl_expr_t sube = ivl_expr_oper1(expr); + /* This is the select expression */ + ivl_expr_t shift= ivl_expr_oper2(expr); + /* Assume the sub-expression is a signal */ + ivl_signal_t sig = ivl_expr_signal(sube); + assert(ivl_signal_data_type(sig) == IVL_VT_DARRAY); + + draw_eval_expr_into_integer(shift, 3); + fprintf(vvp_out, " %%load/dar/r v%p_0;\n", sig); +} + +static void draw_sfunc_real(ivl_expr_t expr) +{ switch (ivl_expr_value(expr)) { case IVL_VT_REAL: if (ivl_expr_parms(expr) == 0) { - res = allocate_word(); - fprintf(vvp_out, " %%vpi_func/r %u %u \"%s\", %d;\n", + fprintf(vvp_out, " %%vpi_func/r %u %u \"%s\" {0 0};\n", ivl_file_table_index(ivl_expr_file(expr)), - ivl_expr_lineno(expr), ivl_expr_name(expr), res); + ivl_expr_lineno(expr), ivl_expr_name(expr)); } else { - res = draw_vpi_rfunc_call(expr); + draw_vpi_rfunc_call(expr); } break; @@ -328,55 +290,53 @@ static int draw_sfunc_real(ivl_expr_t expr) /* If the value of the sfunc is a vector, then evaluate it as a vector, then convert the result to a real (via an index register) for the result. */ - res = draw_real_logic_expr(expr, 0); + draw_real_logic_expr(expr, 0); break; default: assert(0); - res = -1; } - return res; } -static int draw_signal_real_real(ivl_expr_t expr) +static void draw_signal_real_real(ivl_expr_t expr) { ivl_signal_t sig = ivl_expr_signal(expr); - int res = allocate_word(); if (ivl_signal_dimensions(sig) == 0) { - fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, sig); - return res; + fprintf(vvp_out, " %%load/real v%p_0;\n", sig); + return; } ivl_expr_t word_ex = ivl_expr_oper1(expr); int word_ix = allocate_word(); draw_eval_expr_into_integer(word_ex, word_ix); - fprintf(vvp_out, " %%load/ar %d, v%p, %d;\n", res, sig, word_ix); + fprintf(vvp_out, " %%load/ar v%p, %d;\n", sig, word_ix); clr_word(word_ix); - return res; } -static int draw_signal_real(ivl_expr_t expr) +static void draw_signal_real(ivl_expr_t expr) { ivl_signal_t sig = ivl_expr_signal(expr); switch (ivl_signal_data_type(sig)) { case IVL_VT_LOGIC: - return draw_real_logic_expr(expr, 0); + draw_real_logic_expr(expr, 0); + return; case IVL_VT_REAL: - return draw_signal_real_real(expr); + draw_signal_real_real(expr); + return; default: fprintf(stderr, "vvp.tgt error: signal_data_type=%d\n", ivl_signal_data_type(sig)); assert(0); - return -1; + return; } } /* If we have nested ternary operators they are likely tail recursive. * This code is structured to allow this recursion without overflowing * the available thread words. */ -static int draw_ternary_real(ivl_expr_t expr) +static void draw_ternary_real(ivl_expr_t expr) { ivl_expr_t cond = ivl_expr_oper1(expr); ivl_expr_t true_ex = ivl_expr_oper2(expr); @@ -385,11 +345,8 @@ static int draw_ternary_real(ivl_expr_t expr) struct vector_info tst; unsigned lab_true = local_count++; - unsigned lab_move = local_count++; unsigned lab_out = local_count++; - int tru, fal, res; - /* Evaluate the ternary condition. */ tst = draw_eval_expr(cond, STUFF_OK_XZ|STUFF_OK_RO); if ((tst.base >= 4) && (tst.wid > 1)) { @@ -407,130 +364,62 @@ static int draw_ternary_real(ivl_expr_t expr) } /* Evaluate the true expression second. */ - fprintf(vvp_out, " %%jmp/1 T_%d.%d, %u;\n", + fprintf(vvp_out, " %%jmp/1 T_%u.%u, %u;\n", thread_count, lab_true, tst.base); - /* Evaluate the false expression and copy it to the result word. */ - fal = draw_eval_real(false_ex); - res = allocate_word(); - fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, fal); - clr_word(fal); - fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u; End of false expr.\n", + /* Evaluate the false expression. */ + draw_eval_real(false_ex); + fprintf(vvp_out, " %%jmp/0 T_%u.%u, %u; End of false expr.\n", thread_count, lab_out, tst.base); - /* Evaluate the true expression. */ - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_true); - tru = draw_eval_real(true_ex); - fprintf(vvp_out, " %%jmp/1 T_%d.%d, %u; End of true expr.\n", - thread_count, lab_move, tst.base); - /* If the conditional is undefined then blend the real words. */ - fprintf(vvp_out, " %%blend/wr %d, %d;\n", res, tru); - fprintf(vvp_out, " %%jmp T_%d.%d; End of blend\n", + draw_eval_real(true_ex); + fprintf(vvp_out, " %%blend/wr;\n"); + fprintf(vvp_out, " %%jmp T_%u.%u; End of blend\n", thread_count, lab_out); - /* If we only need the true result then copy it to the result word. */ - fprintf(vvp_out, "T_%d.%d ; Move true result.\n", - thread_count, lab_move); - fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, tru); - clr_word(tru); + /* Evaluate the true expression. */ + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_true); + draw_eval_real(true_ex); /* This is the out label. */ - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out); clr_vector(tst); - - return res; } -static int increment(ivl_expr_t e, int s, bool pre) +static void increment(ivl_expr_t e, bool pre) { - ivl_signal_t sig; - int r; - int one; - - sig = ivl_expr_signal(e); - r = s; - - /* create a temporary word to hold value 1.0 */ - one = allocate_word(); - fprintf(vvp_out, " %%loadi/wr %d, 1, 0x1000; load 1.0\n", one); - - if (!pre) { - /* - * post-increment must return the non-incremented value. - * Therefore, copy the current value in a new word and return - * it. - */ - r = allocate_word(); - fprintf(vvp_out, " %%mov/wr %d, %d;\n", r, s); - } - - fprintf(vvp_out, " %%add/wr %d, %d;\n", s, one); - fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", sig, s); - - return r; + ivl_signal_t sig = ivl_expr_signal(e); + fprintf(vvp_out, " %%load/real v%p_0;\n", sig); + if (!pre) fprintf(vvp_out, " %%dup/real;\n"); + fprintf(vvp_out, " %%pushi/real 1, 0x1000;\n"); + fprintf(vvp_out, " %%add/wr;\n"); + if ( pre) fprintf(vvp_out, " %%dup/real;\n"); + fprintf(vvp_out, " %%store/real v%p_0;\n", sig); } -static inline int pre_increment(ivl_expr_t e, int s) +static void decrement(ivl_expr_t e, bool pre) { - return increment(e, s, true); + ivl_signal_t sig = ivl_expr_signal(e); + fprintf(vvp_out, " %%load/real v%p_0;\n", sig); + if (!pre) fprintf(vvp_out, " %%dup/real;\n"); + fprintf(vvp_out, " %%pushi/real 1, 0x1000;\n"); + fprintf(vvp_out, " %%sub/wr;\n"); + if ( pre) fprintf(vvp_out, " %%dup/real;\n"); + fprintf(vvp_out, " %%store/real v%p_0;\n", sig); } -static inline int post_increment(ivl_expr_t e, int s) -{ - return increment(e, s, false); -} - -static int decrement(ivl_expr_t e, int s, bool pre) -{ - ivl_signal_t sig; - int r; - int one; - - sig = ivl_expr_signal(e); - r = s; - - /* create a temporary word to hold value 1.0 */ - one = allocate_word(); - fprintf(vvp_out, " %%loadi/wr %d, 1, 0x1000; load 1.0\n", one); - - if (!pre) { - /* - * post-decrement must return the non-incremented value. - * Therefore, copy the current value in a new word and return - * it. - */ - r = allocate_word(); - fprintf(vvp_out, " %%mov/wr %d, %d;\n", r, s); - } - - fprintf(vvp_out, " %%sub/wr %d, %d;\n", s, one); - fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", sig, s); - - return r; -} - -static inline int pre_decrement(ivl_expr_t e, int s) -{ - return decrement(e, s, true); -} - -static inline int post_decrement(ivl_expr_t e, int s) -{ - return decrement(e, s, false); -} - -static int draw_unary_real(ivl_expr_t expr) +static void draw_unary_real(ivl_expr_t expr) { ivl_expr_t sube; - int sub; /* If the opcode is a ~ or a ! then the sub expression must not be * a real expression, so use vector evaluation and then convert * that result to a real value. */ if ((ivl_expr_opcode(expr) == '~') || (ivl_expr_opcode(expr) == '!')) { - return draw_real_logic_expr(expr, STUFF_OK_XZ); + draw_real_logic_expr(expr, STUFF_OK_XZ); + return; } sube = ivl_expr_oper1(expr); @@ -541,30 +430,28 @@ static int draw_unary_real(ivl_expr_t expr) assert(ivl_expr_value(sube) != IVL_VT_REAL); res = draw_eval_expr(sube, 1); if (ivl_expr_signed(sube)) suffix = "/s"; - sub = allocate_word(); - fprintf(vvp_out, " %%cvt/rv%s %d, %u, %u;\n", suffix, sub, - res.base, res.wid); + fprintf(vvp_out, " %%cvt/rv%s %u, %u;\n", suffix, res.base, res.wid); clr_vector(res); - return sub; + return; } - sub = draw_eval_real(sube); - if (ivl_expr_opcode(expr) == '+') - return sub; + if (ivl_expr_opcode(expr) == '+') { + draw_eval_real(sube); + return; + } if (ivl_expr_opcode(expr) == '-') { - int res = allocate_word(); - fprintf(vvp_out, " %%loadi/wr %d, 0, 0; load 0.0\n", res); - fprintf(vvp_out, " %%sub/wr %d, %d;\n", res, sub); - - clr_word(sub); - return res; + fprintf(vvp_out, " %%pushi/real 0, 0; load 0.0\n"); + draw_eval_real(sube); + fprintf(vvp_out, " %%sub/wr;\n"); + return; } if (ivl_expr_opcode(expr) == 'm') { /* abs() */ - fprintf(vvp_out, " %%abs/wr %d, %d;\n", sub, sub); - return sub; + draw_eval_real(sube); + fprintf(vvp_out, " %%abs/wr;\n"); + return; } if (ivl_expr_opcode(expr) == 'v') { /* Handled in eval_expr.c. */ @@ -573,70 +460,75 @@ static int draw_unary_real(ivl_expr_t expr) assert(0); } - switch (ivl_expr_opcode(expr)) { - case 'I': - return pre_increment(sube, sub); + switch (ivl_expr_opcode(expr)) { + case 'I': + increment(sube, true); + return; + case 'i': + increment(sube, false); + return; - case 'i': - return post_increment(sube, sub); - - case 'D': - return pre_decrement(sube, sub); - - case 'd': - return post_decrement(sube, sub); + case 'D': + decrement(sube, true); + return; + case 'd': + decrement(sube, false); + return; } 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) +void draw_eval_real(ivl_expr_t expr) { - int res = 0; /* If this expression/sub-expression is not real then we need * to evaluate it as a bit value and then convert the bit based * result to a real value. This is required to get integer * division to work correctly. */ if (ivl_expr_value(expr) != IVL_VT_REAL) { - return draw_real_logic_expr(expr, STUFF_OK_XZ); + draw_real_logic_expr(expr, STUFF_OK_XZ); + return; } switch (ivl_expr_type(expr)) { case IVL_EX_BINARY: - res = draw_binary_real(expr); + draw_binary_real(expr); break; case IVL_EX_NUMBER: - res = draw_number_real(expr); + draw_number_real(expr); break; case IVL_EX_REALNUM: - res = draw_realnum_real(expr); + draw_realnum_real(expr); + break; + + case IVL_EX_SELECT: + draw_select_real(expr); break; case IVL_EX_SFUNC: - res = draw_sfunc_real(expr); + draw_sfunc_real(expr); break; case IVL_EX_SIGNAL: - res = draw_signal_real(expr); + draw_signal_real(expr); break; case IVL_EX_TERNARY: - res = draw_ternary_real(expr); + draw_ternary_real(expr); break; case IVL_EX_UFUNC: - res = draw_ufunc_real(expr); + draw_ufunc_real(expr); break; case IVL_EX_UNARY: - res = draw_unary_real(expr); + draw_unary_real(expr); break; default: @@ -645,22 +537,23 @@ int draw_eval_real(ivl_expr_t expr) const char*sign_flag = ivl_expr_signed(expr)? "/s" : ""; clr_vector(sv); - res = allocate_word(); + int res = allocate_word(); fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", sign_flag, res, sv.base, sv.wid); - fprintf(vvp_out, " %%cvt/rs %d, %d;\n", res, res); + fprintf(vvp_out, " %%cvt/rs %d;\n", res); + + clr_word(res); } else { fprintf(stderr, "XXXX Evaluate real expression (%d)\n", ivl_expr_type(expr)); fprintf(vvp_out, " ; XXXX Evaluate real expression (%d)\n", ivl_expr_type(expr)); - return 0; + return; } break; } - return res; } diff --git a/tgt-vvp/eval_string.c b/tgt-vvp/eval_string.c new file mode 100644 index 000000000..01d6613fa --- /dev/null +++ b/tgt-vvp/eval_string.c @@ -0,0 +1,113 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "vvp_priv.h" +# include + +static void fallback_eval(ivl_expr_t expr) +{ + struct vector_info res = draw_eval_expr(expr, 0); + fprintf(vvp_out, " %%pushv/str %u, %u; Cast BOOL/LOGIC to string\n", + res.base, res.wid); + if (res.base > 0) + clr_vector(res); +} + +static void string_ex_concat(ivl_expr_t expr) +{ + unsigned repeat; + + assert(ivl_expr_parms(expr) != 0); + assert(ivl_expr_repeat(expr) != 0); + + /* Push the first string onto the stack, no matter what. */ + draw_eval_string(ivl_expr_parm(expr,0)); + + for (repeat = 0 ; repeat < ivl_expr_repeat(expr) ; repeat += 1) { + unsigned idx; + for (idx = (repeat==0)? 1 : 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { + ivl_expr_t sub = ivl_expr_parm(expr,idx); + + /* Special case: If operand is a string literal, + then concat it using the %concati/str + instruction. */ + if (ivl_expr_type(sub) == IVL_EX_STRING) { + fprintf(vvp_out, " %%concati/str \"%s\";\n", + ivl_expr_string(sub)); + continue; + } + + draw_eval_string(sub); + fprintf(vvp_out, " %%concat/str;\n"); + } + } +} + +static void string_ex_signal(ivl_expr_t expr) +{ + ivl_signal_t sig = ivl_expr_signal(expr); + + if (ivl_signal_data_type(sig) == IVL_VT_STRING) { + fprintf(vvp_out, " %%load/str v%p_0;\n", sig); + return; + } + + fallback_eval(expr); +} + +static void string_ex_select(ivl_expr_t expr) +{ + /* The sube references the expression to be selected from. */ + ivl_expr_t sube = ivl_expr_oper1(expr); + /* This is the select expression */ + ivl_expr_t shift= ivl_expr_oper2(expr); + + /* Assume the sub-expression is a signal */ + ivl_signal_t sig = ivl_expr_signal(sube); + assert(ivl_signal_data_type(sig) == IVL_VT_DARRAY); + + draw_eval_expr_into_integer(shift, 3); + fprintf(vvp_out, " %%load/dar/str v%p_0;\n", sig); +} + +void draw_eval_string(ivl_expr_t expr) +{ + + switch (ivl_expr_type(expr)) { + case IVL_EX_STRING: + fprintf(vvp_out, " %%pushi/str \"%s\";\n", ivl_expr_string(expr)); + break; + + case IVL_EX_SIGNAL: + string_ex_signal(expr); + break; + + case IVL_EX_CONCAT: + string_ex_concat(expr); + break; + + case IVL_EX_SELECT: + string_ex_select(expr); + break; + + default: + fallback_eval(expr); + break; + } +} diff --git a/tgt-vvp/modpath.c b/tgt-vvp/modpath.c index 89f316fdc..4c904496d 100644 --- a/tgt-vvp/modpath.c +++ b/tgt-vvp/modpath.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 13f2e2391..8ac438195 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" @@ -530,7 +530,7 @@ static int show_stmt_assign_vector(ivl_statement_t net) result to a vector. Then store that vector into the l-value. */ if (ivl_expr_value(rval) == IVL_VT_REAL) { - int word = draw_eval_real(rval); + draw_eval_real(rval); /* This is the accumulated with of the l-value of the assignment. */ unsigned wid = ivl_stmt_lwidth(net); @@ -546,10 +546,7 @@ static int show_stmt_assign_vector(ivl_statement_t net) vvp_errors += 1; } - fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n", - res.base, word, res.wid); - - clr_word(word); + fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid); } else { res = draw_eval_expr(rval, 0); @@ -696,13 +693,12 @@ static int show_stmt_assign_vector(ivl_statement_t net) */ static int show_stmt_assign_sig_real(ivl_statement_t net) { - int res; ivl_lval_t lval; ivl_signal_t var; assert(ivl_stmt_opcode(net) == 0); - res = draw_eval_real(ivl_stmt_rval(net)); + draw_eval_real(ivl_stmt_rval(net)); assert(ivl_stmt_lvals(net) == 1); lval = ivl_stmt_lval(net, 0); @@ -710,8 +706,7 @@ static int show_stmt_assign_sig_real(ivl_statement_t net) assert(var != 0); if (ivl_signal_dimensions(var) == 0) { - clr_word(res); - fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res); + fprintf(vvp_out, " %%store/real v%p_0;\n", var); return 0; } @@ -723,14 +718,142 @@ static int show_stmt_assign_sig_real(ivl_statement_t net) int word_ix = allocate_word(); draw_eval_expr_into_integer(word_ex, word_ix); // Generate an assignment to write to the array. - fprintf(vvp_out, " %%set/ar v%p, %d, %d;\n", var, word_ix, res); + fprintf(vvp_out, " %%store/reala v%p, %d;\n", var, word_ix); - clr_word(res); clr_word(word_ix); return 0; } +static int show_stmt_assign_sig_string(ivl_statement_t net) +{ + ivl_lval_t lval = ivl_stmt_lval(net, 0); + ivl_expr_t rval = ivl_stmt_rval(net); + ivl_expr_t part = ivl_lval_part_off(lval); + ivl_signal_t var= ivl_lval_sig(lval); + + assert(ivl_stmt_lvals(net) == 1); + assert(ivl_stmt_opcode(net) == 0); + assert(ivl_lval_mux(lval) == 0); + + /* Simplest case: no mux. Evaluate the r-value as a string and + store the result into the variable. Note that the + %store/str opcode pops the string result. */ + if (part == 0) { + draw_eval_string(rval); + fprintf(vvp_out, " %%store/str v%p_0;\n", var); + return 0; + } + + /* Calculate the character select for the word. */ + int mux_word = allocate_word(); + draw_eval_expr_into_integer(part, mux_word); + + /* Evaluate the r-value as a vector. */ + struct vector_info rvec = draw_eval_expr_wid(rval, 8, STUFF_OK_XZ); + + assert(rvec.wid == 8); + fprintf(vvp_out, " %%putc/str/v v%p_0, %d, %u;\n", var, mux_word, rvec.base); + + clr_vector(rvec); + clr_word(mux_word); + return 0; +} + +static int show_stmt_assign_sig_darray(ivl_statement_t net) +{ + int errors = 0; + ivl_lval_t lval = ivl_stmt_lval(net, 0); + ivl_expr_t rval = ivl_stmt_rval(net); + ivl_expr_t part = ivl_lval_part_off(lval); + ivl_signal_t var= ivl_lval_sig(lval); + ivl_type_t var_type= ivl_signal_net_type(var); + assert(ivl_type_base(var_type) == IVL_VT_DARRAY); + ivl_type_t element_type = ivl_type_element(var_type); + + ivl_expr_t mux = ivl_lval_idx(lval); + + assert(ivl_stmt_lvals(net) == 1); + assert(ivl_stmt_opcode(net) == 0); + assert(ivl_lval_mux(lval) == 0); + assert(part == 0); + + if (mux && (ivl_type_base(element_type)==IVL_VT_REAL)) { + draw_eval_real(rval); + + /* The %set/dar expects the array index to be in index + register 3. Calculate the index in place. */ + draw_eval_expr_into_integer(mux, 3); + + fprintf(vvp_out, " %%store/dar/r v%p_0;\n", var); + + } else if (mux && ivl_type_base(element_type)==IVL_VT_STRING) { + + /* Evaluate the rval into the top of the string stack. */ + draw_eval_string(rval); + + /* The %store/dar/s expects the array index to me in index + register 3. Calculate the index in place. */ + draw_eval_expr_into_integer(mux, 3); + + fprintf(vvp_out, " %%store/dar/str v%p_0;\n", var); + + } else if (mux) { + struct vector_info rvec = draw_eval_expr_wid(rval, ivl_lval_width(lval), + STUFF_OK_XZ); + /* The %set/dar expects the array index to be in index + register 3. Calculate the index in place. */ + draw_eval_expr_into_integer(mux, 3); + + fprintf(vvp_out, " %%set/dar v%p_0, %u, %u;\n", + var, rvec.base, rvec.wid); + + if (rvec.base >= 4) clr_vector(rvec); + + } else { + /* There is no l-value mux, so this must be an + assignment to the array as a whole. Evaluate the + "object", and store the evaluated result. */ + errors += draw_eval_object(rval); + fprintf(vvp_out, " %%store/obj v%p_0;\n", var); + } + + return errors; +} + +static int show_stmt_assign_sig_cobject(ivl_statement_t net) +{ + int errors = 0; + ivl_lval_t lval = ivl_stmt_lval(net, 0); + ivl_expr_t rval = ivl_stmt_rval(net); + ivl_signal_t sig= ivl_lval_sig(lval); + + int prop_idx = ivl_lval_property_idx(lval); + + if (prop_idx >= 0) { + ivl_type_t sig_type = ivl_signal_net_type(sig); + ivl_type_t prop_type = ivl_type_prop_type(sig_type, prop_idx); + assert(ivl_type_base(prop_type) == IVL_VT_BOOL); + assert(ivl_type_packed_dimensions(prop_type) == 1); + assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0)); + int wid = ivl_type_packed_msb(prop_type,0) - ivl_type_packed_lsb(prop_type,0) + 1; + + struct vector_info val = draw_eval_expr_wid(rval, wid, STUFF_OK_XZ); + + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + fprintf(vvp_out, " %%store/prop/v %d, %u, %u;\n", prop_idx, val.base, val.wid); + clr_vector(val); + + } else { + /* There is no property select, so evaluate the r-value + as an object and assign the entire object to the + variable. */ + errors += draw_eval_object(rval); + fprintf(vvp_out, " %%store/obj v%p_0;\n", sig); + } + + return errors; +} int show_stmt_assign(ivl_statement_t net) { @@ -746,5 +869,17 @@ int show_stmt_assign(ivl_statement_t net) return show_stmt_assign_sig_real(net); } + if (sig && (ivl_signal_data_type(sig) == IVL_VT_STRING)) { + return show_stmt_assign_sig_string(net); + } + + if (sig && (ivl_signal_data_type(sig) == IVL_VT_DARRAY)) { + return show_stmt_assign_sig_darray(net); + } + + if (sig && (ivl_signal_data_type(sig) == IVL_VT_CLASS)) { + return show_stmt_assign_sig_cobject(net); + } + return show_stmt_assign_vector(net); } diff --git a/tgt-vvp/vector.c b/tgt-vvp/vector.c index 7835b997c..6dce423d0 100644 --- a/tgt-vvp/vector.c +++ b/tgt-vvp/vector.c @@ -13,7 +13,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" diff --git a/tgt-vvp/vvp.c b/tgt-vvp/vvp.c index 07c946695..c7af7e4ce 100644 --- a/tgt-vvp/vvp.c +++ b/tgt-vvp/vvp.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "version_base.h" diff --git a/tgt-vvp/vvp_config.h.in b/tgt-vvp/vvp_config.h.in index f523107b4..6f9f029cf 100644 --- a/tgt-vvp/vvp_config.h.in +++ b/tgt-vvp/vvp_config.h.in @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if defined(__cplusplus) diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 64fb94571..3c4800fe2 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_config.h" @@ -100,7 +100,7 @@ extern int draw_scope(ivl_scope_t scope, ivl_scope_t parent); extern void draw_lpm_mux(ivl_lpm_t net); extern struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid); -extern int draw_ufunc_real(ivl_expr_t expr); +extern void draw_ufunc_real(ivl_expr_t expr); extern void pad_expr_in_place(ivl_expr_t expr, struct vector_info res, unsigned swid); @@ -129,7 +129,9 @@ extern void draw_vpi_task_call(ivl_statement_t net); extern struct vector_info draw_vpi_func_call(ivl_expr_t expr, unsigned wid); -extern int draw_vpi_rfunc_call(ivl_expr_t expr); +extern void draw_vpi_rfunc_call(ivl_expr_t expr); + +extern void draw_class_in_scope(ivl_type_t classtype); /* * Enumeration draw routine. @@ -298,11 +300,10 @@ extern long get_number_immediate(ivl_expr_t ex); extern uint64_t get_number_immediate64(ivl_expr_t ex); /* - * draw_eval_real evaluates real value expressions. The return code - * from the function is the index of the word register that contains - * the result. + * draw_eval_real evaluates real value expressions. The result of the + * evaluation is the real result in the top of the real expression stack. */ -extern int draw_eval_real(ivl_expr_t ex); +extern void draw_eval_real(ivl_expr_t ex); /* * draw_eval_bool64 evaluates a bool expression. The return code from @@ -313,6 +314,18 @@ extern int draw_eval_real(ivl_expr_t ex); */ extern int draw_eval_bool64(ivl_expr_t ex); +/* + * The draw_eval_string functio evaluates the expression as a string, + * and pushes the string onto the string stack. + */ +extern void draw_eval_string(ivl_expr_t ex); + +/* + * The draw_eval_string functio evaluates the expression as an object, + * and pushes the object onto the object stack. + */ +extern int draw_eval_object(ivl_expr_t ex); + extern int show_stmt_assign(ivl_statement_t net); extern void show_stmt_file_line(ivl_statement_t net, const char*desc); diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 7a0e9c1e7..e352fcccf 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" @@ -39,9 +39,10 @@ unsigned transient_id = 0; * executable code for the processes. */ -/* Support a non-blocking assignment to a real array word. */ +/* Support a non-blocking assignment to a real array word. The real + value to be written is already in the top of the stack. */ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix, - unsigned bit, uint64_t delay, + uint64_t delay, ivl_expr_t dexp, unsigned nevents) { unsigned skip_assign = transient_id++; @@ -62,12 +63,12 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix, /* Calculated delay... */ int delay_index = allocate_word(); draw_eval_expr_into_integer(dexp, delay_index); - fprintf(vvp_out, " %%assign/ar/d v%p, %d, %u;\n", lsig, - delay_index, bit); + fprintf(vvp_out, " %%assign/ar/d v%p, %d;\n", lsig, + delay_index); clr_word(delay_index); } else if (nevents != 0) { /* Event control delay... */ - fprintf(vvp_out, " %%assign/ar/e v%p, %u;\n", lsig, bit); + fprintf(vvp_out, " %%assign/ar/e v%p;\n", lsig); } else { /* Constant delay... */ unsigned long low_d = delay % UINT64_C(0x100000000); @@ -81,12 +82,12 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix, int delay_index = allocate_word(); fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n", delay_index, low_d, hig_d); - fprintf(vvp_out, " %%assign/ar/d v%p, %d, %u;\n", lsig, - delay_index, bit); + fprintf(vvp_out, " %%assign/ar/d v%p, %d;\n", lsig, + delay_index); clr_word(delay_index); } else { - fprintf(vvp_out, " %%assign/ar v%p, %lu, %u;\n", - lsig, low_d, bit); + fprintf(vvp_out, " %%assign/ar v%p, %lu;\n", + lsig, low_d); } } @@ -345,7 +346,7 @@ void show_stmt_file_line(ivl_statement_t net, const char* desc) * should be reported/fixed. */ unsigned lineno = ivl_stmt_lineno(net); assert(lineno); - fprintf(vvp_out, " %%file_line %d %d \"%s\";\n", + fprintf(vvp_out, " %%file_line %d %u \"%s\";\n", ivl_file_table_index(ivl_stmt_file(net)), lineno, desc); } } @@ -376,8 +377,6 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) ivl_expr_t del = ivl_stmt_delay_expr(net); /* variables for the selection of word from an array. */ unsigned long use_word = 0; - /* thread address for a word value. */ - int word; uint64_t delay = 0; unsigned nevents = ivl_stmt_nevent(net); @@ -395,13 +394,12 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) } /* Evaluate the r-value */ - word = draw_eval_real(rval); + draw_eval_real(rval); if (ivl_signal_dimensions(sig) > 0) { ivl_expr_t word_ix = ivl_lval_idx(lval); assert(word_ix); - assign_to_array_r_word(sig, word_ix, word, delay, del, nevents); - clr_word(word); + assign_to_array_r_word(sig, word_ix, delay, del, nevents); return 0; } @@ -410,12 +408,12 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) assert(nevents == 0); int delay_index = allocate_word(); draw_eval_expr_into_integer(del, delay_index); - fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n", - sig, use_word, delay_index, word); + fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d;\n", + sig, use_word, delay_index); clr_word(delay_index); } else if (nevents) { - fprintf(vvp_out, " %%assign/wr/e v%p_%lu, %u;\n", - sig, use_word, word); + fprintf(vvp_out, " %%assign/wr/e v%p_%lu;\n", + sig, use_word); } else { unsigned long low_d = delay % UINT64_C(0x100000000); unsigned long hig_d = delay / UINT64_C(0x100000000); @@ -428,17 +426,15 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) int delay_index = allocate_word(); fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n", delay_index, low_d, hig_d); - fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n", - sig, use_word, delay_index, word); + fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d;\n", + sig, use_word, delay_index); clr_word(delay_index); } else { - fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", - sig, use_word, low_d, word); + fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu;\n", + sig, use_word, low_d); } } - clr_word(word); - return 0; } @@ -525,7 +521,7 @@ static int show_stmt_assign_nb(ivl_statement_t net) value. Evaluate the real expression, then convert the result to a vector. */ if (ivl_expr_value(rval) == IVL_VT_REAL) { - int word = draw_eval_real(rval); + draw_eval_real(rval); /* This is the accumulated with of the l-value of the assignment. */ wid = ivl_stmt_lwidth(net); @@ -541,10 +537,8 @@ static int show_stmt_assign_nb(ivl_statement_t net) vvp_errors += 1; } - fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n", - res.base, word, res.wid); - - clr_word(word); + fprintf(vvp_out, " %%cvt/vr %u, %u;\n", + res.base, res.wid); } else { res = draw_eval_expr(rval, 0); @@ -595,7 +589,7 @@ static int show_stmt_block(ivl_statement_t net, ivl_scope_t sscope) static int show_stmt_block_named(ivl_statement_t net, ivl_scope_t scope) { int rc; - int out_id, sub_id; + unsigned out_id, sub_id; ivl_scope_t subscope = ivl_stmt_block_scope(net); out_id = transient_id++; @@ -665,7 +659,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope) fprintf(vvp_out, " %%cmpi/u %u, %lu, %u;\n", cond.base, imm, cond.wid); - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 6;\n", + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 6;\n", thread_count, local_base+idx); continue; @@ -681,21 +675,21 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope) case IVL_ST_CASE: fprintf(vvp_out, " %%cmp/u %u, %u, %u;\n", cond.base, cvec.base, cond.wid); - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 6;\n", + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 6;\n", thread_count, local_base+idx); break; case IVL_ST_CASEX: fprintf(vvp_out, " %%cmp/x %u, %u, %u;\n", cond.base, cvec.base, cond.wid); - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count, local_base+idx); break; case IVL_ST_CASEZ: fprintf(vvp_out, " %%cmp/z %u, %u, %u;\n", cond.base, cvec.base, cond.wid); - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count, local_base+idx); break; @@ -717,7 +711,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope) } /* Jump to the out of the case. */ - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, local_base+count); for (idx = 0 ; idx < count ; idx += 1) { @@ -726,18 +720,18 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope) if (idx == default_case) continue; - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_base+idx); clear_expression_lookaside(); rc += show_statement(cst, sscope); - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, local_base+count); } /* The out of the case. */ - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+count); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_base+count); clear_expression_lookaside(); return rc; @@ -747,7 +741,6 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope) { int rc = 0; ivl_expr_t expr = ivl_stmt_cond_expr(net); - int cond = draw_eval_real(expr); unsigned count = ivl_stmt_case_count(net); unsigned local_base = local_count; @@ -756,6 +749,11 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope) show_stmt_file_line(net, "Case statement."); + /* Build the reference value into the top of the stack. All + the case comparisons will make duplicates of this value in + order to do their tests. */ + draw_eval_real(expr); + local_count += count + 1; /* First draw the branch table. All the non-default cases @@ -765,26 +763,23 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope) for (idx = 0 ; idx < count ; idx += 1) { ivl_expr_t cex = ivl_stmt_case_expr(net, idx); - int cvec; if (cex == 0) { default_case = idx; continue; } - cvec = draw_eval_real(cex); - - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", cond, cvec); - fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", + /* The referene value... */ + fprintf(vvp_out, " %%dup/real;\n"); + /* The guard value... */ + draw_eval_real(cex); + /* The comparison. */ + fprintf(vvp_out, " %%cmp/wr;\n"); + fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count, local_base+idx); - /* Done with the guard expression value. */ - clr_word(cvec); } - /* Done with the case expression. */ - clr_word(cond); - /* Emit code for the case default. The above jump table will fall through to this statement. */ if (default_case < count) { @@ -793,7 +788,7 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope) } /* Jump to the out of the case. */ - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, local_base+count); for (idx = 0 ; idx < count ; idx += 1) { @@ -802,23 +797,25 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope) if (idx == default_case) continue; - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_base+idx); clear_expression_lookaside(); rc += show_statement(cst, sscope); - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, local_base+count); - } - /* The out of the case. */ - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+count); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_base+count); + fprintf(vvp_out, " %%pop/real 1;\n"); return rc; } -static void force_real_to_lval(ivl_statement_t net, int res) +/* + * The real value is already pushed to the top of the real value stack. + */ +static void force_real_to_lval(ivl_statement_t net) { const char*command_name; ivl_lval_t lval; @@ -847,7 +844,7 @@ static void force_real_to_lval(ivl_statement_t net, int res) /* L-Value must be a signal: reg or wire */ assert(lsig != 0); - fprintf(vvp_out, " %s v%p_0, %d;\n", command_name, lsig, res); + fprintf(vvp_out, " %s v%p_0;\n", command_name, lsig); } @@ -1051,12 +1048,10 @@ static int show_stmt_cassign(ivl_statement_t net) sig = ivl_lval_sig(ivl_stmt_lval(net, 0)); if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) { - int res; - res = draw_eval_real(ivl_stmt_rval(net)); - clr_word(res); + draw_eval_real(ivl_stmt_rval(net)); + force_real_to_lval(net); - force_real_to_lval(net, res); } else { struct vector_info rvec; @@ -1149,7 +1144,7 @@ static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope) lab_false = local_count++; lab_out = local_count++; - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, %u;\n", + fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %u;\n", thread_count, lab_false, cond.base); /* Done with the condition expression. */ @@ -1161,17 +1156,17 @@ static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope) if (ivl_stmt_cond_false(net)) { - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_out); - fprintf(vvp_out, "T_%d.%u ;\n", thread_count, lab_false); + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_out); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_false); clear_expression_lookaside(); rc += show_statement(ivl_stmt_cond_false(net), sscope); - fprintf(vvp_out, "T_%d.%u ;\n", thread_count, lab_out); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out); clear_expression_lookaside(); } else { - fprintf(vvp_out, "T_%d.%u ;\n", thread_count, lab_false); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_false); clear_expression_lookaside(); } @@ -1232,9 +1227,8 @@ static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope) } case IVL_VT_REAL: { - int word = draw_eval_real(expr); - fprintf(vvp_out, " %%cvt/ur 0, %d;\n", word); - clr_word(word); + draw_eval_real(expr); + fprintf(vvp_out, " %%cvt/ur 0;\n"); break; } @@ -1274,12 +1268,10 @@ static int show_stmt_force(ivl_statement_t net) sig = ivl_lval_sig(ivl_stmt_lval(net, 0)); if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) { - int res; - res = draw_eval_real(ivl_stmt_rval(net)); - clr_word(res); + draw_eval_real(ivl_stmt_rval(net)); + force_real_to_lval(net); - force_real_to_lval(net, res); } else { struct vector_info rvec; @@ -1314,55 +1306,85 @@ static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope) { unsigned idx; int rc = 0; - unsigned cnt = ivl_stmt_block_count(net); + unsigned join_count = ivl_stmt_block_count(net); + unsigned join_detach_count = 0; ivl_scope_t scope = ivl_stmt_block_scope(net); - unsigned is_named = (scope != 0); + int is_named = (scope != 0); + /* This is TRUE if it is allowed to embed one of the threads + into this thread. */ + int is_embeddable = 1; unsigned out = transient_id++; unsigned id_base = transient_id; + /* Children are certainly not embeddable if they are going + into a new scope. */ + if (is_named) + is_embeddable = 0; + + switch (ivl_statement_type(net)) { + case IVL_ST_FORK: + break; + case IVL_ST_FORK_JOIN_ANY: + if (join_count < 2) + break; + is_embeddable = 0; + join_detach_count = join_count - 1; + join_count = 1; + break; + case IVL_ST_FORK_JOIN_NONE: + is_embeddable = 0; + join_detach_count = join_count; + join_count = 0; + break; + default: + assert(0); + } + /* cnt is the number of sub-threads. If the fork-join has no name, then we can put one of the sub-threads in the current thread, so decrement the count by one and use the current scope for all the threads. */ - if (! is_named) { - cnt -= 1; + if (is_embeddable) + join_count -= 1; + if (scope==0) scope = sscope; - } - transient_id += cnt; + transient_id += join_count; /* Draw a fork statement for all but one of the threads of the fork/join. Send the threads off to a bit of code where they are implemented. */ - for (idx = 0 ; idx < cnt ; idx += 1) { + for (idx = 0 ; idx < (join_count+join_detach_count) ; idx += 1) { fprintf(vvp_out, " %%fork t_%u, S_%p;\n", id_base+idx, scope); } /* If we are putting one sub-thread into the current thread, then draw its code here. */ - if (! is_named) - rc += show_statement(ivl_stmt_block_stmt(net, cnt), scope); + if (is_embeddable) + rc += show_statement(ivl_stmt_block_stmt(net, join_count), scope); /* Generate enough joins to collect all the sub-threads. */ - for (idx = 0 ; idx < cnt ; idx += 1) { + for (idx = 0 ; idx < join_count ; idx += 1) fprintf(vvp_out, " %%join;\n"); - } + if (join_detach_count > 0) + fprintf(vvp_out, " %%join/detach %u;\n", join_detach_count); + /* Jump around all the threads that I'm creating. */ fprintf(vvp_out, " %%jmp t_%u;\n", out); /* Change the compiling scope to be the named forks scope. */ if (is_named) fprintf(vvp_out, " .scope S_%p;\n", scope); /* Generate the sub-threads themselves. */ - for (idx = 0 ; idx < cnt ; idx += 1) { + for (idx = 0 ; idx < (join_count + join_detach_count) ; idx += 1) { fprintf(vvp_out, "t_%u ;\n", id_base+idx); clear_expression_lookaside(); rc += show_statement(ivl_stmt_block_stmt(net, idx), scope); fprintf(vvp_out, " %%end;\n"); } /* Return to the previous scope. */ - if (is_named) fprintf(vvp_out, " .scope S_%p;\n", sscope); + if (sscope) fprintf(vvp_out, " .scope S_%p;\n", sscope); /* This is the label for the out. Use this to branch around the implementations of all the child threads. */ @@ -1590,7 +1612,7 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope) /* Start the loop. The top of the loop starts a basic block because it can be entered from above or from the bottom of the loop. */ - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, top_label); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, top_label); clear_expression_lookaside(); /* Draw the evaluation of the condition expression, and test @@ -1600,7 +1622,7 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope) if (cvec.wid > 1) cvec = reduction_or(cvec); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, %u;\n", + fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %u;\n", thread_count, out_label, cvec.base); if (cvec.base >= 8) clr_vector(cvec); @@ -1610,14 +1632,35 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope) /* This is the bottom of the loop. branch to the top where the test is repeated, and also draw the out label. */ - fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, top_label); - fprintf(vvp_out, "T_%d.%d ;\n", thread_count, out_label); + fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, top_label); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, out_label); clear_expression_lookaside(); return rc; } +static int show_delete_method(ivl_statement_t net) +{ + show_stmt_file_line(net, "Delete object"); + + unsigned parm_count = ivl_stmt_parm_count(net); + if (parm_count < 1) + return 1; + + ivl_expr_t parm = ivl_stmt_parm(net, 0); + assert(ivl_expr_type(parm) == IVL_EX_SIGNAL); + ivl_signal_t var = ivl_expr_signal(parm); + + fprintf(vvp_out, " %%delete/obj v%p_0;\n", var); + return 0; +} + static int show_system_task_call(ivl_statement_t net) { + const char*stmt_name = ivl_stmt_name(net); + + if (strcmp(stmt_name,"$ivl_darray_method$delete") == 0) + return show_delete_method(net); + show_stmt_file_line(net, "System task call."); draw_vpi_task_call(net); @@ -2073,6 +2116,8 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope) break; case IVL_ST_FORK: + case IVL_ST_FORK_JOIN_ANY: + case IVL_ST_FORK_JOIN_NONE: rc += show_stmt_fork(net, sscope); break; @@ -2113,7 +2158,7 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope) break; default: - fprintf(stderr, "vvp.tgt: Unable to draw statement type %u\n", + fprintf(stderr, "vvp.tgt: Unable to draw statement type %d\n", code); rc += 1; break; @@ -2158,7 +2203,7 @@ int draw_process(ivl_process_t net, void*x) /* Generate the entry label. Just give the thread a number so that we ar certain the label is unique. */ - fprintf(vvp_out, "T_%d ;\n", thread_count); + fprintf(vvp_out, "T_%u ;\n", thread_count); clear_expression_lookaside(); /* Draw the contents of the thread. */ @@ -2176,7 +2221,7 @@ int draw_process(ivl_process_t net, void*x) break; case IVL_PR_ALWAYS: - fprintf(vvp_out, " %%jmp T_%d;\n", thread_count); + fprintf(vvp_out, " %%jmp T_%u;\n", thread_count); break; } @@ -2187,14 +2232,14 @@ int draw_process(ivl_process_t net, void*x) case IVL_PR_INITIAL: case IVL_PR_ALWAYS: if (push_flag) { - fprintf(vvp_out, " .thread T_%d, $push;\n", thread_count); + fprintf(vvp_out, " .thread T_%u, $push;\n", thread_count); } else { - fprintf(vvp_out, " .thread T_%d;\n", thread_count); + fprintf(vvp_out, " .thread T_%u;\n", thread_count); } break; case IVL_PR_FINAL: - fprintf(vvp_out, " .thread T_%d, $final;\n", thread_count); + fprintf(vvp_out, " .thread T_%u, $final;\n", thread_count); break; } diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index edb29b5e7..04bada083 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vvp_priv.h" @@ -417,6 +417,36 @@ const char*draw_input_from_net(ivl_nexus_t nex) } +/* Create flag string for port nature */ + +static const char *port_type_str( ivl_signal_port_t ptype ) +{ + switch( ptype ) + { + case IVL_SIP_INPUT : + return "INPUT"; + case IVL_SIP_OUTPUT : + return "OUTPUT"; + case IVL_SIP_INOUT : + return "INOUT"; + case IVL_SIP_NONE : + default : + return "NOT_PORT"; + } +} +/* Create flag string for et nature" port nature / localness */ + +static const char *port_nature_flag_str( ivl_signal_t sig ) +{ + return port_type_str( ivl_signal_port(sig) ); +} + + +static const char *local_flag_str( ivl_signal_t sig ) +{ + return ivl_signal_local(sig)? "*" : ""; +} + /* * This function draws a reg/int/variable in the scope. This is a very * simple device to draw as there are no inputs to connect so no need @@ -427,19 +457,24 @@ static void draw_reg_in_scope(ivl_signal_t sig) { int msb; int lsb; - if (ivl_signal_packed_dimensions(sig) > 1) { - // FIX ME: Improve this when vvp becomes aware of packed - // arrays. + switch (ivl_signal_packed_dimensions(sig)) { + case 0: + msb = 0; + lsb = 0; + break; + case 1: + msb = ivl_signal_packed_msb(sig, 0); + lsb = ivl_signal_packed_lsb(sig, 0); + break; + default: msb = ivl_signal_width(sig) - 1; lsb = 0; - } else { - msb = ivl_signal_msb(sig); - lsb = ivl_signal_lsb(sig); + break; } - const char*datatype_flag = ivl_signal_integer(sig) ? "/i" : + const char *datatype_flag = ivl_signal_integer(sig) ? "/i" : ivl_signal_signed(sig)? "/s" : ""; - const char*local_flag = ivl_signal_local(sig)? "*" : ""; + const char *local_flag = local_flag_str(sig); switch (ivl_signal_data_type(sig)) { case IVL_VT_BOOL: @@ -467,12 +502,27 @@ static void draw_reg_in_scope(ivl_signal_t sig) vvp_mangle_name(ivl_signal_basename(sig)), swapped ? first: last, swapped ? last : first, msb, lsb); + } else if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) { + fprintf(vvp_out, "v%p_0 .var/darray \"%s\";%s\n", sig, + vvp_mangle_name(ivl_signal_basename(sig)), + ivl_signal_local(sig)? " Local signal" : ""); + + } else if (ivl_signal_data_type(sig) == IVL_VT_STRING) { + fprintf(vvp_out, "v%p_0 .var/str \"%s\";%s\n", sig, + vvp_mangle_name(ivl_signal_basename(sig)), + ivl_signal_local(sig)? " Local signal" : ""); + + } else if (ivl_signal_data_type(sig) == IVL_VT_CLASS) { + fprintf(vvp_out, "v%p_0 .var/cobj \"%s\";%s\n", sig, + vvp_mangle_name(ivl_signal_basename(sig)), + ivl_signal_local(sig)? " Local signal" : ""); + } else { fprintf(vvp_out, "v%p_0 .var%s %s\"%s\", %d %d;%s\n", sig, datatype_flag, local_flag, vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb, - ivl_signal_local(sig)? " Local signal" : ""); + ivl_signal_local(sig)? " Local signal" : "" ); } } @@ -483,11 +533,26 @@ static void draw_reg_in_scope(ivl_signal_t sig) */ static void draw_net_in_scope(ivl_signal_t sig) { - int msb = ivl_signal_msb(sig); - int lsb = ivl_signal_lsb(sig); + int msb; + int lsb; + switch (ivl_signal_packed_dimensions(sig)) { + case 0: + msb = 0; + lsb = 0; + break; + case 1: + msb = ivl_signal_packed_msb(sig, 0); + lsb = ivl_signal_packed_lsb(sig, 0); + break; + default: + msb = ivl_signal_width(sig) - 1; + lsb = 0; + break; + } const char*datatype_flag = ivl_signal_signed(sig)? "/s" : ""; - const char*local_flag = ivl_signal_local(sig)? "*" : ""; + const char *local_flag = local_flag_str(sig); + unsigned iword; switch (ivl_signal_data_type(sig)) { @@ -543,7 +608,7 @@ static void draw_net_in_scope(ivl_signal_t sig) sig, iword, vec8, datatype_flag, sig, iword, msb, lsb, driver, nex_data->drivers_count, - strength_aware_flag?", strength-aware":""); + strength_aware_flag?", strength-aware":"" ); } else if (ivl_signal_local(sig) && ivl_scope_is_auto(ivl_signal_scope(sig))) { assert(word_count == 1); @@ -559,13 +624,13 @@ static void draw_net_in_scope(ivl_signal_t sig) /* If this is an isolated word, it uses its own name. */ assert(word_count == 1); - fprintf(vvp_out, "v%p_%u .net%s%s %s\"%s\", %d %d, %s;" + fprintf(vvp_out, "v%p_%u .net%s%s %s\"%s\", %d %d, %s; " " %u drivers%s\n", sig, iword, vec8, datatype_flag, local_flag, vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb, driver, nex_data->drivers_count, - strength_aware_flag?", strength-aware":""); + strength_aware_flag?", strength-aware":"" ); } nex_data->net = sig; nex_data->net_word = iword; @@ -581,7 +646,7 @@ static void draw_net_in_scope(ivl_signal_t sig) if (word_count == ivl_signal_array_count(nex_data->net)) { if (iword == 0) { - fprintf(vvp_out, "v%p .array \"%s\", v%p; Alias to %s\n", + fprintf(vvp_out, "v%p .array \"%s\", v%p; Alias to %s \n", sig, vvp_mangle_name(ivl_signal_basename(sig)), nex_data->net, ivl_signal_basename(nex_data->net)); @@ -596,7 +661,7 @@ static void draw_net_in_scope(ivl_signal_t sig) sig, vvp_mangle_name(ivl_signal_basename(sig)), swapped ? first : last, - swapped ? last : first); + swapped ? last : first ); } fprintf(vvp_out, "v%p_%u .alias%s v%p %u, %d %d, " @@ -618,7 +683,7 @@ static void draw_net_in_scope(ivl_signal_t sig) if (strength_aware_flag) vec8 = "8"; - fprintf(vvp_out, "v%p_%u .net%s%s %s\"%s\", %d %d, %s;" + fprintf(vvp_out, "v%p_%u .net%s%s %s\"%s\", %d %d, %s; " " alias, %u drivers%s\n", sig, iword, vec8, datatype_flag, local_flag, vvp_mangle_name(ivl_signal_basename(sig)), @@ -725,7 +790,7 @@ static void draw_udp_def(ivl_udp_t udp) if (ivl_udp_sequ(udp)) fprintf(vvp_out, - "UDP_%s .udp/sequ \"%s\", %d, %d", + "UDP_%s .udp/sequ \"%s\", %d, %u", vvp_mangle_id(ivl_udp_name(udp)), vvp_mangle_name(ivl_udp_name(udp)), ivl_udp_nin(udp), @@ -1001,7 +1066,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) unsigned inst; for (inst = 0; inst < (unsigned)ninp; inst += 4) { if (ninp > 4) - fprintf(vvp_out, "L_%p/%d/%d .functor %s %u", + fprintf(vvp_out, "L_%p/%d/%u .functor %s %u", lptr, level, inst, lcasc, vector_width); else { fprintf(vvp_out, "L_%p%s .functor %s %u", @@ -1009,7 +1074,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) ltype, vector_width); if (str0 != IVL_DR_STRONG || str1 != IVL_DR_STRONG) - fprintf(vvp_out, " [%u %u]", str0, str1); + fprintf(vvp_out, " [%d %d]", str0, str1); } for (pdx = inst; pdx < (unsigned)ninp && pdx < inst+4 ; pdx += 1) { @@ -2056,6 +2121,20 @@ static void draw_lpm_in_scope(ivl_lpm_t net) } } + +static const char *vvp_port_info_type_str(ivl_signal_port_t ptype) +{ + switch( ptype ) + { + case IVL_SIP_INPUT : return "/INPUT"; + case IVL_SIP_OUTPUT : return "/OUTPUT"; + case IVL_SIP_INOUT : return "/INOUT"; + case IVL_SIP_NONE : return "/NODIR"; + default : + abort(); // NO SUPPORT FOR ANYTHING ELSE YET... + } +} + int draw_scope(ivl_scope_t net, ivl_scope_t parent) { unsigned idx; @@ -2090,20 +2169,36 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) fprintf(vvp_out, " .timescale %d %d;\n", ivl_scope_time_units(net), ivl_scope_time_precision(net)); + if( ivl_scope_type(net) == IVL_SCT_MODULE ) { + + // Port data for VPI: needed for vpiPorts property of vpiModule + for( idx = 0; idx < ivl_scope_mod_module_ports(net); ++idx ) { + const char *name = ivl_scope_mod_module_port_name(net,idx); + ivl_signal_port_t ptype = ivl_scope_mod_module_port_type(net,idx); + unsigned width = ivl_scope_mod_module_port_width(net,idx); + if( name == 0 ) + name = ""; + fprintf( vvp_out, " .port_info %u %s %u \"%s\"\n", + idx, vvp_port_info_type_str(ptype), width, name ); + } + } + for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) { ivl_parameter_t par = ivl_scope_param(net, idx); ivl_expr_t pex = ivl_parameter_expr(par); switch (ivl_expr_type(pex)) { case IVL_EX_STRING: - fprintf(vvp_out, "P_%p .param/str \"%s\" %d %d, \"%s\";\n", + fprintf(vvp_out, "P_%p .param/str \"%s\" %d %d %d, \"%s\";\n", par, ivl_parameter_basename(par), + ivl_parameter_local(par), ivl_file_table_index(ivl_parameter_file(par)), ivl_parameter_lineno(par), ivl_expr_string(pex)); break; case IVL_EX_NUMBER: - fprintf(vvp_out, "P_%p .param/l \"%s\" %d %d, %sC4<", + fprintf(vvp_out, "P_%p .param/l \"%s\" %d %d %d, %sC4<", par, ivl_parameter_basename(par), + ivl_parameter_local(par), ivl_file_table_index(ivl_parameter_file(par)), ivl_parameter_lineno(par), ivl_expr_signed(pex)? "+":""); @@ -2117,8 +2212,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) break; case IVL_EX_REALNUM: { char *res = draw_Cr_to_string(ivl_expr_dvalue(pex)); - fprintf(vvp_out, "P_%p .param/real \"%s\" %d %d, %s; " + fprintf(vvp_out, "P_%p .param/real \"%s\" %d %d %d, %s; " "value=%#g\n", par, ivl_parameter_basename(par), + ivl_parameter_local(par), ivl_file_table_index(ivl_parameter_file(par)), ivl_parameter_lineno(par), res, ivl_expr_dvalue(pex)); @@ -2132,6 +2228,11 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) } } + for (idx = 0 ; idx < ivl_scope_classes(net) ; idx += 1) { + ivl_type_t class_type = ivl_scope_class(net,idx); + draw_class_in_scope(class_type); + } + /* Scan the scope for enumeration types, and write out enumeration typespecs. */ diff --git a/util.h b/util.h index 64de121a2..4e66fc708 100644 --- a/util.h +++ b/util.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/verilog.spec b/verilog.spec index 9f6cbe645..2a67e0af3 100644 --- a/verilog.spec +++ b/verilog.spec @@ -1,6 +1,6 @@ #norootforbuild # -%define rev_date 20120501 +%define rev_date 20121218 # Normally, the suff-ix is %nil, meaning the suffix is to not be used. # But if the builder wants to make a suffixed package, he may set this # to a value (i.e. -test) to cause suffixes to be put in all the right @@ -83,6 +83,9 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) %{_libdir}/ivl%{suff}/vlog95.tgt %attr(-,root,root) %{_libdir}/ivl%{suff}/vlog95.conf %attr(-,root,root) %{_libdir}/ivl%{suff}/vlog95-s.conf +%attr(-,root,root) %{_libdir}/ivl%{suff}/pcb.tgt +%attr(-,root,root) %{_libdir}/ivl%{suff}/pcb.conf +%attr(-,root,root) %{_libdir}/ivl%{suff}/pcb-s.conf %attr(-,root,root) %{_libdir}/ivl%{suff}/system.sft %attr(-,root,root) %{_libdir}/ivl%{suff}/system.vpi %attr(-,root,root) %{_libdir}/ivl%{suff}/va_math.sft diff --git a/verinum.cc b/verinum.cc index d59d47c81..685ffb4a7 100644 --- a/verinum.cc +++ b/verinum.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" @@ -367,6 +367,13 @@ verinum::V verinum::set(unsigned idx, verinum::V val) return bits_[idx] = val; } +void verinum::set(unsigned off, const verinum&val) +{ + assert(off + val.len() <= nbits_); + for (unsigned idx = 0 ; idx < val.len() ; idx += 1) + bits_[off+idx] = val[idx]; +} + unsigned long verinum::as_ulong() const { if (nbits_ == 0) diff --git a/verinum.h b/verinum.h index 24ea075d7..f8c5bcc46 100644 --- a/verinum.h +++ b/verinum.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -90,6 +90,7 @@ class verinum { // methods. V get(unsigned idx) const; V set(unsigned idx, V val); + void set(unsigned idx, const verinum&val); V operator[] (unsigned idx) const { return get(idx); } diff --git a/verireal.cc b/verireal.cc index 22838e737..4ef092af4 100644 --- a/verireal.cc +++ b/verireal.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/verireal.h b/verireal.h index 4dbb74778..1538add19 100644 --- a/verireal.h +++ b/verireal.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" diff --git a/veriuser.h b/veriuser.h index a92c69e0c..6d08dceff 100644 --- a/veriuser.h +++ b/veriuser.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/version.c b/version.c index 810679bcd..9367e2792 100644 --- a/version.c +++ b/version.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "version_base.h" diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index b7c9115c8..de6e0b8df 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh @@ -68,7 +67,7 @@ O = main.o architec.o compiler.o entity.o \ lexor.o lexor_keyword.o parse.o \ parse_misc.o library.o vhdlreal.o vhdlint.o \ architec_emit.o entity_emit.o expression_emit.o sequential_emit.o vtype_emit.o \ - debug.o architec_debug.o sequential_debug.o \ + debug.o architec_debug.o expression_debug.o sequential_debug.o \ $M all: dep vhdlpp@EXEEXT@ diff --git a/vhdlpp/README.txt b/vhdlpp/README.txt index e904d94c0..7ee8efe50 100644 --- a/vhdlpp/README.txt +++ b/vhdlpp/README.txt @@ -49,4 +49,4 @@ in your VHDL code, access packages like this: The *.pkg files are just VHDL code containing only the package with the same name. When Icarus Verilog encounters the "use ..*;" statement, it looks for the .pkg file in the library and -parses that file to get the package header declared therin. +parses that file to get the package header declared therein. diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index 05a31809b..acf9eafad 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "architec.h" @@ -22,6 +22,7 @@ # include "parse_types.h" // Need this for parse_errors? # include "parse_api.h" +# include using namespace std; @@ -38,6 +39,54 @@ Architecture::~Architecture() ScopeBase::cleanup(); } +void Architecture::push_genvar_type(perm_string gname, const VType*gtype) +{ + genvar_type_t tmp; + tmp.name = gname; + tmp.vtype = gtype; + genvar_type_stack_.push_back(tmp); +} + +void Architecture::pop_genvar_type(void) +{ + assert(! genvar_type_stack_.empty()); + genvar_type_stack_.pop_back(); +} + +const VType* Architecture::probe_genvar_type(perm_string gname) +{ + for (std::list::reverse_iterator cur = genvar_type_stack_.rbegin() + ; cur != genvar_type_stack_.rend() ; ++cur) { + if (cur->name == gname) + return cur->vtype; + } + return 0; +} + +void Architecture::push_genvar_emit(perm_string gname, const GenerateStatement*gen) +{ + genvar_emit_t tmp; + tmp.name = gname; + tmp.gen = gen; + genvar_emit_stack_.push_back(tmp); +} + +void Architecture::pop_genvar_emit(void) +{ + assert(! genvar_emit_stack_.empty()); + genvar_emit_stack_.pop_back(); +} + +const GenerateStatement* Architecture::probe_genvar_emit(perm_string gname) +{ + for (std::list::reverse_iterator cur = genvar_emit_stack_.rbegin() + ; cur != genvar_emit_stack_.rend() ; ++cur) { + if (cur->name == gname) + return cur->gen; + } + return 0; +} + Architecture::Statement::Statement() { } @@ -69,6 +118,16 @@ ForGenerate::~ForGenerate() { } +IfGenerate::IfGenerate(perm_string gname, Expression*cond, + std::list&s) +: GenerateStatement(gname, s), cond_(cond) +{ +} + +IfGenerate::~IfGenerate() +{ +} + SignalAssignment::SignalAssignment(ExpName*name, list&rv) : lval_(name) { diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 2a40189ef..33224f485 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "StringHeap.h" @@ -29,6 +29,7 @@ class ComponentBase; class Entity; class Expression; class ExpName; +class GenerateStatement; class SequentialStmt; class Signal; class named_expr_t; @@ -71,6 +72,18 @@ class Architecture : public Scope, public LineInfo { // Elaborate this architecture in the context of the given entity. int elaborate(Entity*entity); + // These methods are used while in the scope of a generate + // block to mark that a name is a genvar at this point. + const VType* probe_genvar_type(perm_string); + void push_genvar_type(perm_string gname, const VType*gtype); + void pop_genvar_type(void); + + // These methods are used during EMIT to check for names that + // are genvar names. + const GenerateStatement* probe_genvar_emit(perm_string); + void push_genvar_emit(perm_string gname, const GenerateStatement*); + void pop_genvar_emit(void); + // Emit this architecture to the given out file in the context // of the specified entity. This method is used by the // elaborate code to display generated code to the specified @@ -85,6 +98,18 @@ class Architecture : public Scope, public LineInfo { // Concurrent statements local to this architecture std::list statements_; + struct genvar_type_t { + perm_string name; + const VType*vtype; + }; + std::list genvar_type_stack_; + + struct genvar_emit_t { + perm_string name; + const GenerateStatement*gen; + }; + std::list genvar_emit_stack_; + private: // Not implemented }; @@ -98,9 +123,9 @@ class GenerateStatement : public Architecture::Statement { GenerateStatement(perm_string gname, std::list&s); ~GenerateStatement(); - protected: - inline perm_string get_name() { return name_; } + inline perm_string get_name() const { return name_; } + protected: int elaborate_statements(Entity*ent, Architecture*arc); int emit_statements(ostream&out, Entity*ent, Architecture*arc); void dump_statements(ostream&out, int indent) const; @@ -127,6 +152,19 @@ class ForGenerate : public GenerateStatement { Expression*msb_; }; +class IfGenerate : public GenerateStatement { + + public: + IfGenerate(perm_string gname, Expression*cond, + std::list&s); + ~IfGenerate(); + + int elaborate(Entity*ent, Architecture*arc); + int emit(ostream&out, Entity*entity, Architecture*arc); + + private: + Expression*cond_; +}; /* * The SignalAssignment class represents the diff --git a/vhdlpp/architec_debug.cc b/vhdlpp/architec_debug.cc index c2dcfce26..d60bf48fb 100644 --- a/vhdlpp/architec_debug.cc +++ b/vhdlpp/architec_debug.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "architec.h" diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 4a289a466..0e85dd05d 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "architec.h" @@ -28,13 +28,33 @@ int Architecture::elaborate(Entity*entity) { int errors = 0; + // Constant assignments in the architecture get their types + // from the constant declaration itself. Elaborate the value + // expression with the declared type. + + for (map::iterator cur = old_constants_.begin() + ; cur != old_constants_.end() ; ++cur) { + cur->second->val->elaborate_expr(entity, this, cur->second->typ); + } + for (map::iterator cur = new_constants_.begin() + ; cur != new_constants_.end() ; ++cur) { + cur->second->val->elaborate_expr(entity, this, cur->second->typ); + } + for (list::iterator cur = statements_.begin() ; cur != statements_.end() ; ++cur) { - errors += (*cur)->elaborate(entity, this); + int cur_errors = (*cur)->elaborate(entity, this); + errors += cur_errors; } - return errors; + if (errors > 0) { + cerr << errors << " errors in " + << name_ << " architecture of " + << entity->get_name() << "." << endl; + } + + return errors; } int Architecture::Statement::elaborate(Entity*, Architecture*) @@ -111,6 +131,15 @@ int GenerateStatement::elaborate_statements(Entity*ent, Architecture*arc) } int ForGenerate::elaborate(Entity*ent, Architecture*arc) +{ + int errors = 0; + arc->push_genvar_type(genvar_, lsb_->probe_type(ent, arc)); + errors += elaborate_statements(ent, arc); + arc->pop_genvar_type(); + return errors; +} + +int IfGenerate::elaborate(Entity*ent, Architecture*arc) { int errors = 0; errors += elaborate_statements(ent, arc); @@ -120,11 +149,11 @@ int ForGenerate::elaborate(Entity*ent, Architecture*arc) /* * This method attempts to rewrite the process content as an * always-@(n-edge ) version of the same statement. This makes - * for a more natural translation to verilog, if it comes to that. + * for a more natural translation to Verilog, if it comes to that. */ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*) { - // If thare are multiple sensitivity expressions, I give up. + // If there are multiple sensitivity expressions, I give up. if (sensitivity_list_.size() != 1) return -1; @@ -269,7 +298,10 @@ int SignalAssignment::elaborate(Entity*ent, Architecture*arc) // r-value. const VType*lval_type = lval_->peek_type(); if (lval_type == 0) { - if (errors == 0) errors += 1; + if (errors == 0) { + errors += 1; + cerr << get_fileline() << ": error: Unable to calculate type for l-value expression." << endl; + } return errors; } diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index c2a855b61..0f517294b 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "architec.h" @@ -67,6 +67,8 @@ int Architecture::emit(ostream&out, Entity*entity) // Find typedefs that are present in the architecture body and // emit them, so that following code can use the name instead // of the full definition. + + typedef_context_t typedef_ctx; for (map::iterator cur = old_types_.begin() ; cur != old_types_.end() ; ++cur) { @@ -74,7 +76,7 @@ int Architecture::emit(ostream&out, Entity*entity) if (def == 0) continue; - errors += def->emit_typedef(out); + errors += def->emit_typedef(out, typedef_ctx); } for (map::iterator cur = old_constants_.begin() @@ -181,29 +183,59 @@ int GenerateStatement::emit_statements(ostream&out, Entity*ent, Architecture*arc int ForGenerate::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; - out << "generate genvar \\" << genvar_ << " ;" << endl; - out << "for (\\" << genvar_ << " = "; + out << "genvar \\" << get_name() << ":" << genvar_ << " ;" << endl; + out << "for (\\" << get_name() << ":" << genvar_ << " = "; errors += lsb_->emit(out, ent, arc); - out << "; \\" << genvar_ << " <= "; + out << "; \\" << get_name() << ":" << genvar_ << " <= "; errors += msb_->emit(out, ent, arc); - out << "; \\" << genvar_ << " = \\" << genvar_ << " + 1)" + out << "; \\" << get_name() << ":" << genvar_ << " = \\" << get_name() << ":" << genvar_ << " + 1)" << " begin : \\" << get_name() << endl; + arc->push_genvar_emit(genvar_, this); + + errors += emit_statements(out, ent, arc); + + arc->pop_genvar_emit(); + out << "end" << endl; + + return errors; +} + +int IfGenerate::emit(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + out << "if ("; + cond_->emit(out, ent, arc); + out << ") begin : \\" << get_name() << endl; + errors += emit_statements(out, ent, arc); out << "end" << endl; - out << "endgenerate" << endl; + return errors; } +/* + * Emit a process statement using "always" syntax. + * + * Note that VHDL is different from Verilog, in that the sensitivity + * list goes at the END of the statement list, not at the + * beginning. In VHDL, all the statements are initially executed once + * before blocking in the first wait on the sensitivity list. + */ int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; - out << "always"; + out << "always begin" << endl; + + for (list::iterator cur = statements_list_.begin() + ; cur != statements_list_.end() ; ++cur) { + errors += (*cur)->emit(out, ent, arc); + } if (! sensitivity_list_.empty()) { - out << " @("; + out << "@("; const char*comma = 0; for (list::iterator cur = sensitivity_list_.begin() ; cur != sensitivity_list_.end() ; ++cur) { @@ -212,14 +244,7 @@ int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc) errors += (*cur)->emit(out, ent, arc); comma = ", "; } - out << ")"; - } - - out << " begin" << endl; - - for (list::iterator cur = statements_list_.begin() - ; cur != statements_list_.end() ; ++cur) { - errors += (*cur)->emit(out, ent, arc); + out << ") /* sensitivity list for process */;" << endl; } out << "end" << endl; diff --git a/vhdlpp/compiler.cc b/vhdlpp/compiler.cc index ab9d66166..66193a370 100644 --- a/vhdlpp/compiler.cc +++ b/vhdlpp/compiler.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "compiler.h" diff --git a/vhdlpp/compiler.h b/vhdlpp/compiler.h index a5eeb111f..f0ae81ad5 100644 --- a/vhdlpp/compiler.h +++ b/vhdlpp/compiler.h @@ -16,16 +16,20 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "StringHeap.h" +# include const int GN_KEYWORD_2008 = 0x0001; // TRUE if processing is supposed to dump progress to stderr. extern bool verbose_flag; +extern bool debug_elaboration; +extern std::ofstream debug_log_file; + extern StringHeapLex lex_strings; extern StringHeapLex filename_strings; diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 1c2569139..972150778 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704. */ @@ -208,47 +208,17 @@ void ExpAggregate::choice_t::dump(ostream&out, int indent) const return; } - if (expr_) { + if (expr_.get()) { expr_->dump(out, indent); return; } - out << setw(indent) << "" << "?choice_t?" << endl; -} - -void ExpArithmetic::dump(ostream&out, int indent) const -{ - const char*fun_name = "?"; - switch (fun_) { - case PLUS: - fun_name = "+"; - break; - case MINUS: - fun_name = "-"; - break; - case MULT: - fun_name = "*"; - break; - case DIV: - fun_name = "/"; - break; - case MOD: - fun_name = "mod"; - break; - case REM: - fun_name = "rem"; - break; - case POW: - fun_name = "**"; - break; - case CONCAT: - fun_name = "&"; - break; + if (range_.get()) { + range_->dump(out, indent); + return; } - out << setw(indent) << "" << "Arithmetic " << fun_name - << " at " << get_fileline() << endl; - dump_operands(out, indent+4); + out << setw(indent) << "" << "?choice_t?" << endl; } void ExpAttribute::dump(ostream&out, int indent) const @@ -292,11 +262,22 @@ void ExpConditional::dump(ostream&out, int indent) const (*cur)->dump(out, indent+4); } - out << setw(indent) << "" << " else:" << endl; - for (list::const_iterator cur = else_clause_.begin() + for (list::const_iterator cur = else_clause_.begin() ; cur != else_clause_.end() ; ++cur) { + (*cur)->dump(out, indent); + } +} + +void ExpConditional::else_t::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "when:" << endl; + if (cond_) cond_->dump(out, indent+4); + out << setw(indent) << "" << "do:" << endl; + for (list::const_iterator cur = true_clause_.begin() + ; cur != true_clause_.end() ; ++cur) { (*cur)->dump(out, indent+4); } + } void ExpEdge::dump(ostream&out, int indent) const @@ -364,6 +345,8 @@ void ExpName::dump(ostream&out, int indent) const { out << setw(indent) << "" << "ExpName(\"" << name_ << "\")" << " at " << get_fileline() << endl; + if (prefix_.get()) + prefix_->dump(out, indent+8); if (index_) index_->dump(out, indent+6); if (lsb_) @@ -441,3 +424,15 @@ void prange_t::dump(ostream&out, int indent) const out << setw(indent) << "" << (direction_ ? "downto" : "to"); right_->dump(out, indent); } + +ostream& Expression::dump_inline(ostream&out) const +{ + out << typeid(*this).name(); + return out; +} + +ostream& ExpInteger::dump_inline(ostream&out) const +{ + out << value_; + return out; +} diff --git a/vhdlpp/entity.cc b/vhdlpp/entity.cc index 68d3c6280..4df745412 100644 --- a/vhdlpp/entity.cc +++ b/vhdlpp/entity.cc @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "entity.h" diff --git a/vhdlpp/entity.h b/vhdlpp/entity.h index 850a4a587..5e37bca4b 100644 --- a/vhdlpp/entity.h +++ b/vhdlpp/entity.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -104,7 +104,7 @@ class Entity : public ComponentBase { // After the architecture is bound, elaboration calls this // method to elaborate this entity. This method arranges for - // elaboration to hapen all the way through the architecture + // elaboration to happen all the way through the architecture // that is bound to this entity. int elaborate(); diff --git a/vhdlpp/entity_elaborate.cc b/vhdlpp/entity_elaborate.cc index 6a8867a2d..2727bd34e 100644 --- a/vhdlpp/entity_elaborate.cc +++ b/vhdlpp/entity_elaborate.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "entity.h" diff --git a/vhdlpp/entity_emit.cc b/vhdlpp/entity_emit.cc index 6361c6eaf..41fb1eef8 100644 --- a/vhdlpp/entity_emit.cc +++ b/vhdlpp/entity_emit.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "entity.h" @@ -67,7 +67,7 @@ int Entity::emit(ostream&out) VType::decl_t&decl = declarations_[port->name]; - if (sep) out << sep; + if (sep) out << sep << endl; else sep = ", "; switch (port->mode) { diff --git a/vhdlpp/entity_stream.cc b/vhdlpp/entity_stream.cc index 90f85719e..5b04938ee 100644 --- a/vhdlpp/entity_stream.cc +++ b/vhdlpp/entity_stream.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "entity.h" diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index ed767565c..ecd1fe19d 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "expression.h" @@ -50,28 +50,6 @@ bool Expression::symbolic_compare(const Expression*) const return false; } -bool ExpName::symbolic_compare(const Expression*that) const -{ - const ExpName*that_name = dynamic_cast (that); - if (that_name == 0) - return false; - - if (name_ != that_name->name_) - return false; - - if (that_name->index_ && !index_) - return false; - if (index_ && !that_name->index_) - return false; - - if (index_) { - assert(that_name->index_); - return index_->symbolic_compare(that_name->index_); - } - - return true; -} - ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam) : base_(bas), name_(nam) { @@ -137,28 +115,34 @@ ExpAggregate::choice_t::choice_t(Expression*exp) } ExpAggregate::choice_t::choice_t() -: expr_(0) +{ +} + +ExpAggregate::choice_t::choice_t(prange_t*rang) +: range_(rang) { } ExpAggregate::choice_t::~choice_t() { - if (expr_) delete expr_; } bool ExpAggregate::choice_t::others() const { - return expr_ == 0; + return expr_.get() == 0 && range_.get() == 0; } Expression*ExpAggregate::choice_t::simple_expression(bool detach_flag) { - Expression*res = expr_; - if (detach_flag) - expr_ = 0; + Expression*res = detach_flag? expr_.release() : expr_.get(); return res; } +prange_t*ExpAggregate::choice_t::range_expressions(void) +{ + return range_.get(); +} + ExpAggregate::element_t::element_t(list*fields, Expression*val) : fields_(fields? fields->size() : 0), val_(val) { @@ -183,56 +167,14 @@ ExpAggregate::element_t::~element_t() ExpArithmetic::ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2) : ExpBinary(op1, op2), fun_(op) { + // The xCONCAT type is not actually used. + assert(op != xCONCAT); } ExpArithmetic::~ExpArithmetic() { } -bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const -{ - int64_t val1, val2; - bool rc; - - rc = eval_operand1(scope, val1); - if (rc == false) - return false; - - rc = eval_operand2(scope, val2); - if (rc == false) - return false; - - switch (fun_) { - case PLUS: - val = val1 + val2; - break; - case MINUS: - val = val1 - val2; - break; - case MULT: - val = val1 * val2; - break; - case DIV: - if (val2 == 0) - return false; - val = val1 / val2; - break; - case MOD: - if (val2 == 0) - return false; - val = val1 % val2; - break; - case REM: - return false; - case POW: - return false; - case CONCAT: - return false; - } - - return true; -} - /* * Store bitstrings in little-endian order. */ @@ -256,11 +198,23 @@ ExpCharacter::~ExpCharacter() { } -ExpConditional::ExpConditional(Expression*co, list*tru, list*els) +ExpConcat::ExpConcat(Expression*op1, Expression*op2) +: operand1_(op1), operand2_(op2) +{ +} + +ExpConcat::~ExpConcat() +{ + delete operand1_; + delete operand2_; +} + +ExpConditional::ExpConditional(Expression*co, list*tru, + list*fal) : cond_(co) { if (tru) true_clause_.splice(true_clause_.end(), *tru); - if (els) else_clause_.splice(else_clause_.end(), *els); + if (fal) else_clause_.splice(else_clause_.end(), *fal); } ExpConditional::~ExpConditional() @@ -272,12 +226,29 @@ ExpConditional::~ExpConditional() delete tmp; } while (! else_clause_.empty()) { - Expression*tmp = else_clause_.front(); + else_t*tmp = else_clause_.front(); else_clause_.pop_front(); delete tmp; } } +ExpConditional::else_t::else_t(Expression*cond, std::list*tru) +: cond_(cond) +{ + if (tru) true_clause_.splice(true_clause_.end(), *tru); +} + +ExpConditional::else_t::~else_t() +{ + delete cond_; + while (! true_clause_.empty()) { + Expression*tmp = true_clause_.front(); + true_clause_.pop_front(); + delete tmp; + } +} + + ExpEdge::ExpEdge(ExpEdge::fun_t typ, Expression*op) : ExpUnary(op), fun_(typ) { @@ -353,6 +324,16 @@ ExpName::ExpName(perm_string nn, Expression*msb, Expression*lsb) { } +ExpName::ExpName(ExpName*prefix, perm_string nn) +: prefix_(prefix), name_(nn), index_(0), lsb_(0) +{ +} + +ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb) +: prefix_(prefix), name_(nn), index_(msb), lsb_(lsb) +{ +} + ExpName::~ExpName() { delete index_; @@ -363,6 +344,36 @@ const char* ExpName::name() const return name_; } +bool ExpName::symbolic_compare(const Expression*that) const +{ + const ExpName*that_name = dynamic_cast (that); + if (that_name == 0) + return false; + + if (name_ != that_name->name_) + return false; + + if (that_name->index_ && !index_) + return false; + if (index_ && !that_name->index_) + return false; + + if (index_) { + assert(that_name->index_); + return index_->symbolic_compare(that_name->index_); + } + + return true; +} + +void ExpName::set_range(Expression*msb, Expression*lsb) +{ + assert(index_==0); + index_ = msb; + assert(lsb_==0); + lsb_ = lsb; +} + ExpRelation::ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2) : ExpBinary(op1, op2), fun_(ty) { diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 5e6c49c5a..0271abe37 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -1,7 +1,7 @@ #ifndef __expression_H #define __expression_H /* - * 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 @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "StringHeap.h" @@ -24,8 +24,10 @@ # include "entity.h" # include # include +# include # include +class prange_t; class Entity; class Architecture; class ScopeBase; @@ -59,6 +61,14 @@ class Expression : public LineInfo { // this may be called before the elaborate_expr method. virtual const VType*probe_type(Entity*ent, Architecture*arc) const; + // The fit_type virtual method is used by the ExpConcat class + // to probe the type of operands. The atype argument is the + // type of the ExpConcat expression itself. This expression + // returns its type as interpreted in this context. Really, + // this is mostly about helping aggregate expressions within + // concatenations to figure out their type. + virtual const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; + // This virtual method elaborates an expression. The ltype is // the type of the lvalue expression, if known, and can be // used to calculate the type for the expression being @@ -101,6 +111,7 @@ class Expression : public LineInfo { // Debug dump of the expression. virtual void dump(ostream&out, int indent = 0) const =0; + virtual ostream& dump_inline(ostream&out) const; protected: // This function is called by the derived class during @@ -121,12 +132,19 @@ static inline void FILE_NAME(Expression*tgt, const LineInfo*src) tgt->set_line(*src); } +static inline ostream& operator <<(ostream&out, const Expression&exp) +{ + return exp.dump_inline(out); +} + class ExpUnary : public Expression { public: ExpUnary(Expression*op1); virtual ~ExpUnary() =0; + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; + protected: inline void write_to_stream_operand1(std::ostream&fd) { operand1_->write_to_stream(fd); } @@ -177,6 +195,10 @@ class ExpBinary : public Expression { class ExpAggregate : public Expression { public: + // A "choice" is only part of an element. It is the thing that + // is used to identify an element of the aggregate. It can + // represent the index (or range) of an array, or the name of + // a record member. class choice_t { public: // Create an "others" choice @@ -185,17 +207,23 @@ class ExpAggregate : public Expression { explicit choice_t(Expression*exp); // Create a named choice explicit choice_t(perm_string name); + // discreate_range choice + explicit choice_t(prange_t*ran); ~choice_t(); // true if this represents an "others" choice bool others() const; - // Return expression if this reprents simple_expression. + // Return expression if this represents a simple_expression. Expression*simple_expression(bool detach_flag =true); + // Return prange_t if this represents a range_expression + prange_t*range_expressions(void); + void write_to_stream(std::ostream&fd); void dump(ostream&out, int indent) const; private: - Expression*expr_; + std::auto_ptrexpr_; + std::auto_ptr range_; private: // not implemented choice_t(const choice_t&); choice_t& operator= (const choice_t&); @@ -207,6 +235,9 @@ class ExpAggregate : public Expression { bool alias_flag; }; + // Elements are the syntactic items in an aggregate + // expression. Each element expressions a bunch of fields + // (choices) and binds them to a single expression class element_t { public: explicit element_t(std::list*fields, Expression*val); @@ -215,6 +246,9 @@ class ExpAggregate : public Expression { size_t count_choices() const { return fields_.size(); } void map_choices(choice_element*dst); + inline Expression* extract_expression() { return val_; } + void write_to_stream(std::ostream&fd) const; + void dump(ostream&out, int indent) const; private: @@ -229,6 +263,9 @@ class ExpAggregate : public Expression { ExpAggregate(std::list*el); ~ExpAggregate(); + + const VType*probe_type(Entity*ent, Architecture*arc) const; + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); @@ -250,7 +287,7 @@ class ExpAggregate : public Expression { class ExpArithmetic : public ExpBinary { public: - enum fun_t { PLUS, MINUS, MULT, DIV, MOD, REM, POW, CONCAT }; + enum fun_t { PLUS, MINUS, MULT, DIV, MOD, REM, POW, xCONCAT }; public: ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2); @@ -262,9 +299,6 @@ class ExpArithmetic : public ExpBinary { virtual bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; - private: - int emit_concat_(ostream&out, Entity*ent, Architecture*arc); - private: fun_t fun_; }; @@ -298,6 +332,7 @@ class ExpBitstring : public Expression { explicit ExpBitstring(const char*); ~ExpBitstring(); + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); @@ -314,6 +349,7 @@ class ExpCharacter : public Expression { ExpCharacter(char val); ~ExpCharacter(); + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); @@ -330,16 +366,54 @@ class ExpCharacter : public Expression { char value_; }; +class ExpConcat : public Expression { + + public: + ExpConcat(Expression*op1, Expression*op2); + ~ExpConcat(); + + const VType*probe_type(Entity*ent, Architecture*arc) const; + int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); + void write_to_stream(std::ostream&fd); + int emit(ostream&out, Entity*ent, Architecture*arc); + virtual bool evaluate(ScopeBase*scope, int64_t&val) const; + bool is_primary(void) const; + void dump(ostream&out, int indent = 0) const; + + private: + int elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype); + + private: + Expression*operand1_; + Expression*operand2_; +}; + /* * The conditional expression represents the VHDL when-else * expressions. Note that by the VHDL syntax rules, these cannot show - * up other then at the root of an expression. + * up other than at the root of an expression. */ class ExpConditional : public Expression { + public: + class else_t : public LineInfo { + public: + else_t(Expression*cond, std::list*tru); + ~else_t(); + + int elaborate_expr(Entity*ent, Architecture*arc, const VType*lt); + int emit_when_else(ostream&out, Entity*ent, Architecture*arc); + int emit_else(ostream&out, Entity*ent, Architecture*arc); + void dump(ostream&out, int indent = 0) const; + + private: + Expression*cond_; + std::list true_clause_; + }; + public: ExpConditional(Expression*cond, std::list*tru, - std::list*els); + std::list*fal); ~ExpConditional(); const VType*probe_type(Entity*ent, Architecture*arc) const; @@ -351,7 +425,7 @@ class ExpConditional : public Expression { private: Expression*cond_; std::list true_clause_; - std::list else_clause_; + std::list else_clause_; }; /* @@ -407,6 +481,7 @@ class ExpInteger : public Expression { bool is_primary(void) const; bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; + virtual ostream& dump_inline(ostream&out) const; private: int64_t value_; @@ -443,12 +518,15 @@ class ExpName : public Expression { explicit ExpName(perm_string nn); ExpName(perm_string nn, std::list*indices); ExpName(perm_string nn, Expression*msb, Expression*lsb); + ExpName(ExpName*prefix, perm_string nn); + ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb); ~ExpName(); public: // Base methods int elaborate_lval(Entity*ent, Architecture*arc, bool); int elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*); const VType* probe_type(Entity*ent, Architecture*arc) const; + const VType* fit_type(Entity*ent, Architecture*arc, const VTypeArray*host) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); @@ -459,7 +537,19 @@ class ExpName : public Expression { void dump(ostream&out, int indent = 0) const; const char* name() const; + void set_range(Expression*msb, Expression*lsb); + private: + const VType* elaborate_adjust_type_with_range_(Entity*ent, Architecture*arc, const VType*type); + + int elaborate_lval_(Entity*ent, Architecture*arc, bool, ExpName*suffix); + const VType* probe_prefix_type_(Entity*ent, Architecture*arc) const; + const VType* probe_prefixed_type_(Entity*ent, Architecture*arc) const; + + int emit_as_prefix_(ostream&out, Entity*ent, Architecture*arc); + + private: + std::auto_ptr prefix_; perm_string name_; Expression*index_; Expression*lsb_; @@ -503,6 +593,7 @@ class ExpString : public Expression { explicit ExpString(const char*); ~ExpString(); + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); diff --git a/vhdlpp/expression_debug.cc b/vhdlpp/expression_debug.cc new file mode 100644 index 000000000..befd6ea84 --- /dev/null +++ b/vhdlpp/expression_debug.cc @@ -0,0 +1,70 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "entity.h" +# include "architec.h" +# include "expression.h" +# include +# include +# include +# include + +using namespace std; + +void ExpArithmetic::dump(ostream&out, int indent) const +{ + const char*fun_name = "?"; + switch (fun_) { + case PLUS: + fun_name = "+"; + break; + case MINUS: + fun_name = "-"; + break; + case MULT: + fun_name = "*"; + break; + case DIV: + fun_name = "/"; + break; + case MOD: + fun_name = "mod"; + break; + case REM: + fun_name = "rem"; + break; + case POW: + fun_name = "**"; + break; + case xCONCAT: + ivl_assert(*this, 0); + break; + } + + out << setw(indent) << "" << "Arithmetic " << fun_name + << " at " << get_fileline() << endl; + dump_operands(out, indent+4); +} + +void ExpConcat::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Concatenation at " << get_fileline() << endl; + operand1_->dump(out, indent); + operand2_->dump(out, indent); +} diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index d93db16ba..ffc2301b0 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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 @@ -14,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704. */ @@ -24,6 +25,8 @@ # include "vsignal.h" # include # include +# include "parse_types.h" +# include "compiler.h" # include "ivl_assert.h" using namespace std; @@ -39,10 +42,175 @@ const VType* Expression::probe_type(Entity*, Architecture*) const return 0; } +const VType* Expression::fit_type(Entity*ent, Architecture*arc, const VTypeArray*) const +{ + const VType*res = probe_type(ent,arc); + if (res == 0) { + cerr << get_fileline() << ": internal error: " + << "fit_type for " << typeid(*this).name() + << " is not implemented." << endl; + } + + return res; +} + +const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, Architecture*arc, const VType*type) +{ + + if (const VTypeArray*array = dynamic_cast(type)) { + if (index_ && !lsb_) { + // If the name is an array or a vector, then an + // indexed name has the type of the element. + type = array->element_type(); + + } else if (index_ && lsb_) { + // If the name is an array, then a part select is + // also an array, but with different bounds. + int64_t use_msb, use_lsb; + bool flag; + + flag = index_->evaluate(arc, use_msb); + ivl_assert(*this, flag); + flag = lsb_->evaluate(arc, use_lsb); + ivl_assert(*this, flag); + + Expression*exp_msb = new ExpInteger(use_msb); + Expression*exp_lsb = new ExpInteger(use_lsb); + vector use_dims (1); + use_dims[0] = VTypeArray::range_t(exp_msb, exp_lsb); + type = new VTypeArray(array->element_type(), use_dims); + } + } + + return type; +} + +int ExpName::elaborate_lval_(Entity*ent, Architecture*arc, bool is_sequ, ExpName*suffix) +{ + int errors = 0; + + if (debug_elaboration) { + debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: " + << "name_=" << name_ + << ", suffix->name()=" << suffix->name(); + if (index_) + debug_log_file << ", index_=" << *index_; + if (lsb_) + debug_log_file << ", lsb_=" << *lsb_; + debug_log_file << endl; + } + + if (prefix_.get()) { + cerr << get_fileline() << ": sorry: I don't know how to elaborate " + << "ExpName prefix of " << name_ + << " in l-value expressions." << endl; + errors += 1; + } + + const VType*found_type = 0; + + if (const InterfacePort*cur = ent->find_port(name_)) { + if (cur->mode != PORT_OUT) { + cerr << get_fileline() << ": error: Assignment to " + "input port " << name_ << "." << endl; + return errors + 1; + } + + if (is_sequ) + ent->set_declaration_l_value(name_, is_sequ); + + found_type = cur->type; + + } else if (ent->find_generic(name_)) { + + cerr << get_fileline() << ": error: Assignment to generic " + << name_ << " from entity " + << ent->get_name() << "." << endl; + return errors + 1; + + } else if (Signal*sig = arc->find_signal(name_)) { + // Tell the target signal that this may be a sequential l-value. + if (is_sequ) sig->count_ref_sequ(); + + found_type = sig->peek_type(); + + } else if (Variable*var = arc->find_variable(name_)) { + // Tell the target signal that this may be a sequential l-value. + if (is_sequ) var->count_ref_sequ(); + + found_type = var->peek_type(); + } + + // Resolve type definition to get an actual type. + while (const VTypeDef*tdef = dynamic_cast (found_type)) { + found_type = tdef->peek_definition(); + + if (debug_elaboration) { + debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: " + << "Resolve typedef " << tdef->peek_name() + << " to defined type=" << typeid(*found_type).name() + << endl; + } + } + + ivl_assert(*this, found_type); + + // If the prefix type is an array, then we may actually have a + // case of an array of structs. For example: + // foo(n).bar + // where foo is an array, (n) is an array index and foo(n) is + // something that takes a suffix. For the purpose of our + // expression type calculations, we need the element type. + if (const VTypeArray*array = dynamic_cast (found_type)) { + found_type = array->element_type(); + + while (const VTypeDef*tdef = dynamic_cast (found_type)) { + found_type = tdef->peek_definition(); + } + + if (debug_elaboration) { + debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: " + << "Extract array element type=" << typeid(*found_type).name() + << endl; + } + } + + const VType*suffix_type = 0; + + if (const VTypeRecord*record = dynamic_cast (found_type)) { + const VTypeRecord::element_t*element = record->element_by_name(suffix->name_); + ivl_assert(*this, element); + + const VType*element_type = element->peek_type(); + ivl_assert(*this, element_type); + + suffix_type = element_type; + + } + + if (suffix_type == 0) { + cerr << get_fileline() << ": error: I don't know how to handle prefix " << name_ + << " with suffix " << suffix->name_ << endl; + errors += 1; + return errors; + } + + suffix_type = suffix->elaborate_adjust_type_with_range_(ent, arc, suffix_type); + + ivl_assert(*this, suffix_type); + suffix->set_type(suffix_type); + + return errors; +} + int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) { int errors = 0; + if (prefix_.get()) { + return prefix_->elaborate_lval_(ent, arc, is_sequ, this); + } + const VType*found_type = 0; if (const InterfacePort*cur = ent->find_port(name_)) { @@ -83,30 +251,7 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) return errors + 1; } - if (const VTypeArray*array = dynamic_cast(found_type)) { - if (index_ && !lsb_) { - // If the name is an array or a vector, then an - // indexed name has the type of the element. - found_type = array->element_type(); - - } else if (index_ && lsb_) { - // If the name is an array, then a part select is - // also an array, but with different bounds. - int64_t use_msb, use_lsb; - bool flag; - - flag = index_->evaluate(arc, use_msb); - ivl_assert(*this, flag); - flag = lsb_->evaluate(arc, use_lsb); - ivl_assert(*this, flag); - - Expression*exp_msb = new ExpInteger(use_msb); - Expression*exp_lsb = new ExpInteger(use_lsb); - vector use_dims (1); - use_dims[0] = VTypeArray::range_t(exp_msb, exp_lsb); - found_type = new VTypeArray(array->element_type(), use_dims); - } - } + found_type = elaborate_adjust_type_with_range_(ent, arc, found_type); set_type(found_type); return errors; @@ -116,11 +261,17 @@ int ExpName::elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*lv { int errors = 0; + if (prefix_.get()) { + cerr << get_fileline() << ": sorry: I don't know how to elaborate " + << "ExpName prefix parts in r-value expressions." << endl; + errors += 1; + } + if (const InterfacePort*cur = ent->find_port(name_)) { /* IEEE 1076-2008, p.80: * For a formal port IN, associated port should be IN, OUT, INOUT or BUFFER * For a formal port OUT, associated port should be OUT, INOUT or BUFFER - * For a formal port INOUT, associated prot should be OUT, INOUT or BUFFER + * For a formal port INOUT, associated port should be OUT, INOUT or BUFFER * For a formal port BUFFER, associated port should be OUT, INOUT or BUFFER */ switch(lval->mode) { @@ -177,7 +328,12 @@ const VType* ExpBinary::probe_type(Entity*ent, Architecture*arc) const if (t1 == t2) return t1; + // FIXME: I should at this point try harder to find an + // operator that has the proper argument list and use this + // here, but for now we leave it for the back-end to figure out. +#if 0 cerr << get_fileline() << ": internal error: I don't know how to resolve types of generic binary expressions." << endl; +#endif return 0; } @@ -190,15 +346,60 @@ int ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype) return errors; } +/* + * the default fit_type method for unary operator expressions is to + * return the fit_type for the operand. The assumption is that the + * operator doesn't change the type. + */ +const VType*ExpUnary::fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const +{ + return operand1_->fit_type(ent, arc, atype); +} + +const VType*ExpAggregate::probe_type(Entity*ent, Architecture*arc) const +{ + return Expression::probe_type(ent, arc); +} + +const VType*ExpAggregate::fit_type(Entity*, Architecture*, const VTypeArray*host) const +{ + ivl_assert(*this, elements_.size() == 1); + size_t choice_count = elements_[0]->count_choices(); + + ivl_assert(*this, choice_count > 0); + vector ce (choice_count); + elements_[0]->map_choices(&ce[0]); + + ivl_assert(*this, ce.size() == 1); + prange_t*prange = ce[0].choice->range_expressions(); + ivl_assert(*this, prange); + + Expression*use_msb = prange->msb(); + Expression*use_lsb = prange->lsb(); + + ivl_assert(*this, host->dimensions() == 1); + vector range (1); + + range[0] = VTypeArray::range_t(use_msb, use_lsb); + + const VTypeArray*res = new VTypeArray(host->element_type(), range); + + return res; +} + int ExpAggregate::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) { if (ltype == 0) { - cerr << get_fileline() << ": error: Elaboration of aggregate types needs wel known type context?" << endl; + cerr << get_fileline() << ": error: Elaboration of aggregate types needs well known type context?" << endl; return 1; } set_type(ltype); + while (const VTypeDef*cur = dynamic_cast(ltype)) { + ltype = cur->peek_definition(); + } + if (const VTypeArray*larray = dynamic_cast(ltype)) { return elaborate_expr_array_(ent, arc, larray); } @@ -209,8 +410,8 @@ int ExpAggregate::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype /* * Elaboration of array aggregates is elaboration of the element - * expressions using the element type as the ltype for the - * subexpression. + * expressions (the elements_ member) using the element type as the + * ltype for the subexpression. */ int ExpAggregate::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype) { @@ -218,22 +419,42 @@ int ExpAggregate::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTyp int errors = 0; size_t choice_count = 0; + // Figure out how many total elements we have here. Note that + // each parsed element may be bound to multiple choices, so + // account for that. for (size_t edx = 0 ; edx < elements_.size() ; edx += 1) { element_t*ecur = elements_[edx]; - choice_count += ecur->count_choices(); + if (ecur->count_choices() == 0) + choice_count += 1; + else + choice_count += ecur->count_choices(); } aggregate_.resize(choice_count); + // Translate the elements_ array to the aggregate_ array. In + // the target array, each expression is attached to a single + // choice. size_t cdx = 0; for (size_t edx = 0 ; edx < elements_.size() ; edx += 1) { element_t*ecur = elements_[edx]; - ecur->map_choices(&aggregate_[cdx]); - cdx += ecur->count_choices(); + if (ecur->count_choices() == 0) { + // positional associations have no "choice" + // associated with them. + aggregate_[cdx].choice = 0; + aggregate_[cdx].expr = ecur->extract_expression(); + aggregate_[cdx].alias_flag; + cdx += 1; + } else { + ecur->map_choices(&aggregate_[cdx]); + cdx += ecur->count_choices(); + } } ivl_assert(*this, cdx == choice_count); + // Now run through the more convenient mapping and elaborate + // all the expressions that I find. for (size_t idx = 0 ; idx < aggregate_.size() ; idx += 1) { if (aggregate_[idx].alias_flag) continue; @@ -241,7 +462,9 @@ int ExpAggregate::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTyp errors += aggregate_[idx].expr->elaborate_expr(ent, arc, element_type); } + // done with the obsolete elements_ vector. elements_.clear(); + return errors; } @@ -287,12 +510,26 @@ int ExpAttribute::elaborate_expr(Entity*ent, Architecture*arc, const VType*) return errors; } +const VType*ExpBitstring::fit_type(Entity*, Architecture*, const VTypeArray*atype) const +{ + // Really should check that this string can work with the + // array element type? + return atype->element_type(); +} + int ExpBitstring::elaborate_expr(Entity*, Architecture*, const VType*) { int errors = 0; return errors; } +const VType*ExpCharacter::fit_type(Entity*, Architecture*, const VTypeArray*atype) const +{ + // Really should check that this character can work with the + // array element type? + return atype->element_type(); +} + int ExpCharacter::elaborate_expr(Entity*, Architecture*, const VType*ltype) { ivl_assert(*this, ltype != 0); @@ -300,6 +537,54 @@ int ExpCharacter::elaborate_expr(Entity*, Architecture*, const VType*ltype) return 0; } +/* + * I don't know how to probe the type of a concatenation, quite yet. + */ +const VType*ExpConcat::probe_type(Entity*, Architecture*) const +{ + ivl_assert(*this, 0); + return 0; +} + +int ExpConcat::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +{ + int errors = 0; + + if (ltype == 0) { + ltype = probe_type(ent, arc); + } + + ivl_assert(*this, ltype != 0); + + if (const VTypeArray*atype = dynamic_cast(ltype)) { + errors += elaborate_expr_array_(ent, arc, atype); + } else { + errors += operand1_->elaborate_expr(ent, arc, ltype); + errors += operand2_->elaborate_expr(ent, arc, ltype); + } + + return errors; +} + +int ExpConcat::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*atype) +{ + int errors = 0; + + // For now, only support single-dimension arrays here. + ivl_assert(*this, atype->dimensions() == 1); + + const VType*type1 = operand1_->fit_type(ent, arc, atype); + ivl_assert(*this, type1); + + const VType*type2 = operand2_->fit_type(ent, arc, atype); + ivl_assert(*this, type2); + + errors += operand1_->elaborate_expr(ent, arc, type1); + errors += operand2_->elaborate_expr(ent, arc, type2); + + return errors; +} + const VType* ExpConditional::probe_type(Entity*, Architecture*) const { return 0; @@ -325,7 +610,7 @@ int ExpConditional::elaborate_expr(Entity*ent, Architecture*arc, const VType*lty errors += (*cur)->elaborate_expr(ent, arc, ltype); } - for (list::const_iterator cur = else_clause_.begin() + for (list::const_iterator cur = else_clause_.begin() ; cur != else_clause_.end() ; ++cur) { errors += (*cur)->elaborate_expr(ent, arc, ltype); } @@ -333,6 +618,21 @@ int ExpConditional::elaborate_expr(Entity*ent, Architecture*arc, const VType*lty return errors; } +int ExpConditional::else_t::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +{ + int errors = 0; + + if (cond_) + errors += cond_->elaborate_expr(ent, arc, 0); + + for (list::const_iterator cur = true_clause_.begin() + ; cur != true_clause_.end() ; ++cur) { + errors += (*cur)->elaborate_expr(ent, arc, ltype); + } + + return errors; +} + int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*) { int errors = 0; @@ -376,8 +676,58 @@ int ExpLogical::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) return errors; } +const VType* ExpName::probe_prefix_type_(Entity*ent, Architecture*arc) const +{ + if (prefix_.get()) { + cerr << get_fileline() << ": sorry: I do not know how to support nested prefix parts." << endl; + return 0; + } + + const VType*type = probe_type(ent, arc); + return type; +} + +/* + * This method is the probe_type() imlementation for ExpName objects + * that have prefix parts. In this case we try to get the type of the + * prefix and interpret the name in that context. + */ +const VType* ExpName::probe_prefixed_type_(Entity*ent, Architecture*arc) const +{ + // First, get the type of the prefix. + const VType*prefix_type = prefix_->probe_prefix_type_(ent, arc); + if (prefix_type == 0) { + return 0; + } + + while (const VTypeDef*def = dynamic_cast (prefix_type)) { + prefix_type = def->peek_definition(); + } + + // If the prefix type is a record, then the current name is + // the name of a member. + if (const VTypeRecord*pref_record = dynamic_cast (prefix_type)) { + const VTypeRecord::element_t*element = pref_record->element_by_name(name_); + ivl_assert(*this, element); + + const VType*element_type = element->peek_type(); + ivl_assert(*this, element_type); + + return element_type; + } + + cerr << get_fileline() << ": sorry: I don't know how to probe " + << "prefix type " << typeid(*prefix_type).name() + << " of " << name_ << "." << endl; + + return 0; +} + const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const { + if (prefix_.get()) + return probe_prefixed_type_(ent, arc); + if (const InterfacePort*cur = ent->find_port(name_)) { ivl_assert(*this, cur->type); return cur->type; @@ -399,15 +749,26 @@ const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const if (arc->find_constant(name_, ctype, cval)) return ctype; + if (const VType*gtype = arc->probe_genvar_type(name_)) { + return gtype; + } + cerr << get_fileline() << ": error: Signal/variable " << name_ << " not found in this context." << endl; return 0; } +const VType* ExpName::fit_type(Entity*ent, Architecture*arc, const VTypeArray*)const +{ + return probe_type(ent, arc); +} + int ExpName::elaborate_expr(Entity*, Architecture*, const VType*ltype) { - ivl_assert(*this, ltype != 0); - set_type(ltype); + if (ltype) { + ivl_assert(*this, ltype != 0); + set_type(ltype); + } return 0; } @@ -419,8 +780,8 @@ const VType* ExpNameALL::probe_type(Entity*, Architecture*) const const VType* ExpRelation::probe_type(Entity*ent, Architecture*arc) const { - const VType*type1 = peek_operand1()->probe_type(ent, arc); - const VType*type2 = peek_operand2()->probe_type(ent, arc); + /* const VType*type1 = */ peek_operand1()->probe_type(ent, arc); + /* const VType*type2 = */ peek_operand2()->probe_type(ent, arc); return primitive_BOOLEAN; } @@ -434,10 +795,37 @@ int ExpRelation::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) } ivl_assert(*this, ltype != 0); - errors += elaborate_exprs(ent, arc, ltype); + + // The type of the operands must match, but need not match the + // type for the ExpRelation itself. So get the operand type + // separately. + const VType*otype = ExpBinary::probe_type(ent, arc); + errors += elaborate_exprs(ent, arc, otype); + return errors; } +/* + * When a string appears in a concatenation, then the type of the + * string is an array with the same element type of the concatenation, + * but with elements for each character of the string. + */ +const VType*ExpString::fit_type(Entity*, Architecture*, const VTypeArray*atype) const +{ + vector range (atype->dimensions()); + + // Generate an array range for this string + ivl_assert(*this, range.size() == 1); + ExpInteger*use_msb = new ExpInteger(value_.size()); + ExpInteger*use_lsb = new ExpInteger(0); + FILE_NAME(use_msb, this); + FILE_NAME(use_lsb, this); + range[0] = VTypeArray::range_t(use_msb, use_lsb); + + VTypeArray*type = new VTypeArray(atype->element_type(), range); + return type; +} + int ExpString::elaborate_expr(Entity*, Architecture*, const VType*ltype) { ivl_assert(*this, ltype != 0); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 96e4dec4d..c0d22210b 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -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 @@ -14,12 +14,13 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "expression.h" # include "vtype.h" # include "architec.h" +# include "parse_types.h" # include # include # include @@ -70,10 +71,24 @@ int ExpUnary::emit_operand1(ostream&out, Entity*ent, Architecture*arc) int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc) { - if (const VTypeArray*atype = dynamic_cast (peek_type())) + if (peek_type() == 0) { + out << "/* " << get_fileline() << ": internal error: " + << "Aggregate literal needs well defined type." << endl; + return 1; + } + + const VType*use_type = peek_type(); + while (const VTypeDef*def = dynamic_cast (use_type)) { + use_type = def->peek_definition(); + } + + if (const VTypeArray*atype = dynamic_cast (use_type)) return emit_array_(out, ent, arc, atype); - return Expression::emit(out, ent, arc); + out << "/* " << get_fileline() << ": internal error: " + << "I don't know how to elab/emit aggregate in " << typeid(use_type).name() + << " type context. */"; + return 1; } int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*atype) @@ -126,27 +141,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V const VTypeArray::range_t&rang = atype->dimension(0); assert(! rang.is_box()); - map element_map; - choice_element*element_other = 0; - - for (size_t idx = 0 ; idx < aggregate_.size() ; idx += 1) { - if (aggregate_[idx].choice->others()) { - ivl_assert(*this, element_other == 0); - element_other = &aggregate_[idx]; - continue; - } - - Expression*tmp = aggregate_[idx].choice->simple_expression(false); - int64_t tmp_val; - if (! tmp->evaluate(ent, arc, tmp_val)) { - cerr << tmp->get_fileline() << ": error: Unable to evaluate aggregate choice expression." << endl; - errors += 1; - continue; - } - - element_map[tmp_val] = &aggregate_[idx]; - } - + // Fully calculate the range numbers. int64_t use_msb, use_lsb; bool rc; rc = rang.msb()->evaluate(ent, arc, use_msb); @@ -155,16 +150,105 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V ivl_assert(*this, rc); ivl_assert(*this, use_msb >= use_lsb); + map element_map; + choice_element*element_other = 0; + + bool positional_section = true; + int64_t positional_idx = use_msb; + + for (size_t idx = 0 ; idx < aggregate_.size() ; idx += 1) { + + if (aggregate_[idx].choice == 0) { + // positional association! + if (!positional_section) { + cerr << get_fileline() << ": error: " + << "All positional associations must be before" + << " any named associations." << endl; + errors += 1; + } + element_map[positional_idx] = &aggregate_[idx]; + positional_idx -= 1; + continue; + } + + if (aggregate_[idx].choice->others()) { + ivl_assert(*this, element_other == 0); + element_other = &aggregate_[idx]; + continue; + } + + // If this is a range choice, then calculate the bounds + // of the range and scan through the values, mapping the + // value to the aggregate_[idx] element. + if (prange_t*range = aggregate_[idx].choice->range_expressions()) { + int64_t begin_val, end_val; + + if (! range->msb()->evaluate(ent, arc, begin_val)) { + cerr << range->msb()->get_fileline() << ": error: " + << "Unable to evaluate aggregate choice expression." << endl; + errors += 1; + continue; + } + + if (! range->lsb()->evaluate(ent, arc, end_val)) { + cerr << range->msb()->get_fileline() << ": error: " + << "Unable to evaluate aggregate choice expression." << endl; + errors += 1; + continue; + } + + if (begin_val < end_val) { + int64_t tmp = begin_val; + begin_val = end_val; + end_val = tmp; + } + + while (begin_val >= end_val) { + element_map[begin_val] = &aggregate_[idx]; + begin_val -= 1; + } + + continue; + } + + int64_t tmp_val; + Expression*tmp = aggregate_[idx].choice->simple_expression(false); + ivl_assert(*this, tmp); + + // Named aggregate element. Once we see one of + // these, we can no longer accept positional + // elements so disable further positional + // processing. + positional_section = false; + if (! tmp->evaluate(ent, arc, tmp_val)) { + cerr << tmp->get_fileline() << ": error: " + << "Unable to evaluate aggregate choice expression." << endl; + errors += 1; + continue; + } + + element_map[tmp_val] = &aggregate_[idx]; + } + + // Emit the elements as a concatenation. This works great for + // vectors of bits. We implement VHDL arrays as packed arrays, + // so this should be generally correct. out << "{"; for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) { choice_element*cur = element_map[idx]; if (cur == 0) cur = element_other; - ivl_assert(*this, cur != 0); if (idx < use_msb) out << ", "; - errors += cur->expr->emit(out, ent, arc); + if (cur == 0) { + out << "/* Missing element " << idx << " */"; + cerr << get_fileline() << ": error: " + << "Missing element " << idx << "." << endl; + errors += 1; + } else { + errors += cur->expr->emit(out, ent, arc); + } } out << "}"; @@ -206,9 +290,6 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; - if (fun_ == CONCAT) - return emit_concat_(out, ent, arc); - errors += emit_operand1(out, ent, arc); switch (fun_) { @@ -233,7 +314,8 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) case REM: out << " /* ?remainder? */ "; break; - case CONCAT: + case xCONCAT: + ivl_assert(*this, 0); out << " /* ?concat? */ "; break; } @@ -243,17 +325,6 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } -int ExpArithmetic::emit_concat_(ostream&out, Entity*ent, Architecture*arc) -{ - int errors = 0; - out << "{"; - errors += emit_operand1(out, ent, arc); - out << ", "; - errors += emit_operand2(out, ent, arc); - out << "}"; - return errors; -} - int ExpBitstring::emit(ostream&out, Entity*, Architecture*) { int errors = 0; @@ -320,6 +391,26 @@ bool ExpCharacter::is_primary(void) const return true; } +/* + * This is not exactly a "primary", but it is wrapped in its own + * parentheses (braces) so we return true here. + */ +bool ExpConcat::is_primary(void) const +{ + return true; +} + +int ExpConcat::emit(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + out << "{"; + errors += operand1_->emit(out, ent, arc); + out << ", "; + errors += operand2_->emit(out, ent, arc); + out << "}"; + return errors; +} + int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; @@ -328,7 +419,7 @@ int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc) out << ")? ("; if (true_clause_.size() > 1) { - cerr << get_fileline() << ": sorry: Multiple expressions not supported here." << endl; + cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl; errors += 1; } @@ -337,15 +428,66 @@ int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc) out << ") : ("; + // Draw out any when-else expressions. These are all the else_ + // clauses besides the last. if (else_clause_.size() > 1) { - cerr << get_fileline() << ": sorry: Multiple expressions not supported here." << endl; + list::iterator last = else_clause_.end(); + -- last; + + for (list::iterator cur = else_clause_.begin() + ; cur != last ; ++cur) { + errors += (*cur) ->emit_when_else(out, ent, arc); + } + } + + errors += else_clause_.back()->emit_else(out, ent, arc); + out << ")"; + + // The emit_when_else() functions do not close the last + // parentheses so that the following expression can be + // nested. But that means come the end, we have some + // expressions to close. + for (size_t idx = 1 ; idx < else_clause_.size() ; idx += 1) + out << ")"; + + return errors; +} + +int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + assert(cond_ != 0); + + out << "("; + errors += cond_->emit(out, ent, arc); + out << ")? ("; + + if (true_clause_.size() > 1) { + cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl; errors += 1; } - tmp = else_clause_.front(); + Expression*tmp = true_clause_.front(); errors += tmp->emit(out, ent, arc); - out << ")"; + out << ") : ("; + + return errors; +} + +int ExpConditional::else_t::emit_else(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + // Trailing else must have no condition. + assert(cond_ == 0); + + if (true_clause_.size() > 1) { + cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl; + errors += 1; + } + + Expression*tmp = true_clause_.front(); + errors += tmp->emit(out, ent, arc); return errors; } @@ -460,11 +602,38 @@ int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } +int ExpName::emit_as_prefix_(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + if (prefix_.get()) { + errors += prefix_->emit_as_prefix_(out, ent, arc); + } + + out << "\\" << name_ << " "; + if (index_) { + out << "["; + errors += index_->emit(out, ent, arc); + out << "]"; + ivl_assert(*this, lsb_ == 0); + } + out << "."; + return errors; +} + int ExpName::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; - out << "\\" << name_ << " "; + if (prefix_.get()) { + errors += prefix_->emit_as_prefix_(out, ent, arc); + } + + const GenerateStatement*gs = 0; + if (arc && (gs = arc->probe_genvar_emit(name_))) + out << "\\" << gs->get_name() << ":" << name_ << " "; + else + out << "\\" << name_ << " "; + if (index_) { out << "["; errors += index_->emit(out, ent, arc); diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 3596e9fd5..2671b23f0 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "expression.h" @@ -32,6 +32,50 @@ bool Expression::evaluate(Entity*, Architecture*arc, int64_t&val) const } +bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const +{ + int64_t val1, val2; + bool rc; + + rc = eval_operand1(scope, val1); + if (rc == false) + return false; + + rc = eval_operand2(scope, val2); + if (rc == false) + return false; + + switch (fun_) { + case PLUS: + val = val1 + val2; + break; + case MINUS: + val = val1 - val2; + break; + case MULT: + val = val1 * val2; + break; + case DIV: + if (val2 == 0) + return false; + val = val1 / val2; + break; + case MOD: + if (val2 == 0) + return false; + val = val1 % val2; + break; + case REM: + return false; + case POW: + return false; + case xCONCAT: // not possible + return false; + } + + return true; +} + bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const { /* Special Case: The length attribute can be calculated all @@ -71,11 +115,25 @@ bool ExpAttribute::evaluate(Entity*, Architecture*arc, int64_t&val) const return evaluate(arc, val); } +/* + * I don't yet know how to evaluate concatenations. It is not likely + * to come up anyhow. + */ +bool ExpConcat::evaluate(ScopeBase*scope, int64_t&val) const +{ + return false; +} + bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const { const VType*type; Expression*exp; + if (prefix_.get()) { + cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl; + return false; + } + bool rc = scope->find_constant(name_, type, exp); if (rc == false) return false; @@ -85,6 +143,11 @@ bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const bool ExpName::evaluate(Entity*ent, Architecture*arc, int64_t&val) const { + if (prefix_.get()) { + cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl; + return false; + } + const InterfacePort*gen = ent->find_generic(name_); if (gen) { cerr << get_fileline() << ": sorry: I don't necessarily handle generic overrides." << endl; diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index 2427f7fba..b8da43179 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -14,18 +14,59 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "expression.h" +# include "parse_types.h" # include # include using namespace std; -void ExpAggregate::write_to_stream(ostream&) +void ExpAggregate::write_to_stream(ostream&fd) { - ivl_assert(*this, !"Not supported"); + fd << "("; + for (vector::const_iterator cur = elements_.begin() + ; cur != elements_.end() ; ++cur) { + (*cur)->write_to_stream(fd); + } + fd << ")"; +} + +void ExpAggregate::element_t::write_to_stream(ostream&fd) const +{ + for (vector::const_iterator cur = fields_.begin() + ; cur != fields_.end() ; ++cur) { + (*cur)->write_to_stream(fd); + } + + fd << "=>"; + val_->write_to_stream(fd); +} + +void ExpAggregate::choice_t::write_to_stream(ostream&fd) +{ + if (others()) { + fd << "others"; + return; + } + + if (Expression*sim = simple_expression()) { + sim->write_to_stream(fd); + return; + } + + if (prange_t*rp = range_expressions()) { + rp->msb()->write_to_stream(fd); + if (rp->is_downto()) + fd << " downto "; + else + fd << " to "; + rp->msb()->write_to_stream(fd); + } + + fd << "/* ERROR */"; } void ExpArithmetic::write_to_stream(ostream&out) @@ -56,8 +97,8 @@ void ExpArithmetic::write_to_stream(ostream&out) case POW: out << "**"; break; - case CONCAT: - out << "&"; + case xCONCAT: + ivl_assert(*this, 0); break; } @@ -76,9 +117,23 @@ void ExpBitstring::write_to_stream(ostream&) ivl_assert(*this, !"Not supported"); } -void ExpCharacter::write_to_stream(ostream&) +void ExpCharacter::write_to_stream(ostream&fd) { - ivl_assert(*this, !"Not supported"); + char buf[4]; + buf[0] = '\''; + buf[1] = value_; + buf[2] = '\''; + buf[3] = 0; + fd << buf; +} + +void ExpConcat::write_to_stream(ostream&fd) +{ + fd << "("; + operand1_->write_to_stream(fd); + fd << ")&("; + operand2_->write_to_stream(fd); + fd << ")"; } void ExpConditional::write_to_stream(ostream&) @@ -91,9 +146,17 @@ void ExpEdge::write_to_stream(ostream&) ivl_assert(*this, !"Not supported"); } -void ExpFunc::write_to_stream(ostream&) +void ExpFunc::write_to_stream(ostream&fd) { - ivl_assert(*this, !"Not supported"); + const char*comma = ""; + fd << name_ << "("; + for (vector::iterator cur = argv_.begin() + ; cur != argv_.end() ; ++cur) { + fd << comma; + (*cur)->write_to_stream(fd); + comma = ", "; + } + fd << ")"; } void ExpInteger::write_to_stream(ostream&fd) @@ -108,6 +171,11 @@ void ExpLogical::write_to_stream(ostream&) void ExpName::write_to_stream(ostream&fd) { + if (prefix_.get()) { + prefix_->write_to_stream(fd); + fd << "."; + } + fd << name_; if (index_) { fd << "("; diff --git a/vhdlpp/ivl_assert.h b/vhdlpp/ivl_assert.h index ebf473754..6c4f9c0b9 100644 --- a/vhdlpp/ivl_assert.h +++ b/vhdlpp/ivl_assert.h @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __ivl_assert_h diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index 9ab591168..2f3fd197b 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -21,7 +21,7 @@ * * You should have received a copy of the GNU General Public License * aint64_t with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "parse_api.h" @@ -44,10 +44,10 @@ extern int lexor_keyword_code (const char*str, unsigned len); /* - * Lexical location information is passed in the yylloc variable to th + * Lexical location information is passed in the yylloc variable to the * parser. The file names, strings, are kept in a list so that I can * re-use them. The set_file_name function will return a pointer to - * the name as it exists in the list (and delete the passed string.) + * the name as it exists in the list (and delete the passed string). * If the name is new, it will be added to the list. */ #define yylloc (*yyllocp) @@ -89,7 +89,7 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* [ \t\b\f\r] { ; } \n { yylloc.first_line += 1; } - /* Single-line comments start with - - and run to the end of the + /* Single-line comments start with -- and run to the end of the current line. These are very easy to handle. */ "--".* { comment_enter = YY_START; BEGIN(LCOMMENT); } @@ -635,7 +635,7 @@ static double make_double_from_based(char* text) *first_hash_ptr = '\0'; *second_hash_ptr = '\0'; - //now lets deduce the base + //now let's deduce the base unsigned base = (unsigned)strtol(text, 0, 10) ; double mantissa = 0.0; diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 776789eb1..435778020 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # define __STDC_LIMIT_MACROS @@ -338,6 +338,17 @@ void generate_global_types(ActiveScope*res) res->bind_name(perm_string::literal("natural"), primitive_NATURAL); } +bool is_global_type(perm_string name) +{ + if (name == "boolean") return true; + if (name == "bit") return true; + if (name == "integer") return true; + if (name == "std_logic") return true; + if (name == "bit_vector") return true; + if (name == "natural") return true; + return false; +} + void library_set_work_path(const char*path) { assert(library_work_path == 0); diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index e7cf565ae..ce3fa2df6 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -1,6 +1,7 @@ const char COPYRIGHT[] = - "Copyright (c) 2011 Stephen Williams (steve@icarus.com)"; + "Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)\n" + "Copyright CERN 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 @@ -15,7 +16,7 @@ const char COPYRIGHT[] = * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vhdlpp_config.h" # include "version_base.h" @@ -36,6 +37,10 @@ const char COPYRIGHT[] = * Enable debugging of library support by dumping library * information to the file named . * + * elaboration= + * Enable debugging of elaboratin by dumping elaboration + * process information to the file named . + * * entities= * Enable debugging of elaborated entities by writing the * elaboration results to the file named . @@ -94,7 +99,10 @@ bool verbose_flag = false; // Where to dump design entities const char*dump_design_entities_path = 0; const char*dump_libraries_path = 0; +const char*debug_log_path = 0; +bool debug_elaboration = false; +ofstream debug_log_file; extern void dump_libraries(ostream&file); extern void parser_cleanup(); @@ -109,6 +117,10 @@ static void process_debug_token(const char*word) dump_design_entities_path = strdup(word+9); } else if (strncmp(word, "libraries=", 10) == 0) { dump_libraries_path = strdup(word+10); + } else if (strncmp(word, "log=", 4) == 0) { + debug_log_path = strdup(word+4); + } else if (strcmp(word, "elaboration") == 0) { + debug_elaboration = true; } } @@ -148,6 +160,10 @@ int main(int argc, char*argv[]) break; } + if (debug_log_path) { + debug_log_file.open(debug_log_path); + } + if ( (rc = mkdir(work_path, 0777)) < 0 ) { if (errno != EEXIST) { fprintf(stderr, "Icarus Verilog VHDL unable to create work directory %s, errno=%d\n", work_path, errno); diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 211b422f9..338bbddae 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -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 @@ -14,11 +14,12 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "package.h" # include "entity.h" +# include "parse_misc.h" Package::Package(perm_string n, const ScopeBase&ref) : Scope(ref), name_(n) @@ -30,10 +31,79 @@ Package::~Package() ScopeBase::cleanup(); } +/* + * The Package::write_to_stream is used to write the package to the + * work space (or library) so writes proper VHDL that the library + * parser can bring back in as needed. + */ void Package::write_to_stream(ostream&fd) const { fd << "package " << name_ << " is" << endl; + // Start out pre-declaring all the type definitions so that + // there is no confusion later in the package between types + // and identifiers. + for (map::const_iterator cur = old_types_.begin() + ; cur != old_types_.end() ; ++cur) { + const VTypeDef*def = dynamic_cast (cur->second); + if (def == 0) + continue; + fd << "type " << cur->first << ";" << endl; + } + + for (map::const_iterator cur = new_types_.begin() + ; cur != new_types_.end() ; ++cur) { + const VTypeDef*def = dynamic_cast (cur->second); + if (def == 0) + continue; + fd << "type " << cur->first << ";" << endl; + } + + for (map::const_iterator cur = old_constants_.begin() + ; cur != old_constants_.end() ; ++ cur) { + fd << "constant " << cur->first << ": "; + cur->second->typ->write_to_stream(fd); + fd << " := "; + cur->second->val->write_to_stream(fd); + fd << ";" << endl; + } + + for (map::const_iterator cur = new_constants_.begin() + ; cur != new_constants_.end() ; ++ cur) { + fd << "constant " << cur->first << ": "; + cur->second->typ->write_to_stream(fd); + fd << " := "; + cur->second->val->write_to_stream(fd); + fd << ";" << endl; + } + + for (map::const_iterator cur = old_types_.begin() + ; cur != old_types_.end() ; ++cur) { + + // Do not include global types in types dump + if (is_global_type(cur->first)) + continue; + if (cur->first == "std_logic_vector") + continue; + + fd << "type " << cur->first << " is "; + cur->second->write_type_to_stream(fd); + fd << ";" << endl; + } + for (map::const_iterator cur = new_types_.begin() + ; cur != new_types_.end() ; ++cur) { + + // Do not include primitive types in type dump + if (is_global_type(cur->first)) + continue; + if (cur->first == "std_logic_vector") + continue; + + fd << "type " << cur->first << " is "; + cur->second->write_type_to_stream(fd); + fd << ";" << endl; + } + for (map::const_iterator cur = old_components_.begin() ; cur != old_components_.end() ; ++cur) { diff --git a/vhdlpp/package.h b/vhdlpp/package.h index c648eea50..8f9fd04ae 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "scope.h" diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 8b519537e..3c4d0b174 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -6,7 +6,8 @@ %parse-param {perm_string parse_library_name} %{ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright CERN 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,7 +22,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vhdlpp_config.h" @@ -139,6 +140,47 @@ const VType*parse_type_by_name(perm_string name) return active_scope->find_type(name); } +// This function is called when an aggregate expression is detected by +// the parser. It makes the ExpAggregate. It also tries to detect the +// special case that the aggregate is really a primary. The problem is +// that this: +// ( ) +// also matches the pattern: +// ( [ choices => ] ... ) +// so try to assume that a single expression in parentheses is a +// primary and fix the parse by returning an Expression instead of an +// ExpAggregate. +static Expression*aggregate_or_primary(const YYLTYPE&loc, std::list*el) +{ + if (el->size() != 1) { + ExpAggregate*tmp = new ExpAggregate(el); + FILE_NAME(tmp,loc); + return tmp; + } + + ExpAggregate::element_t*el1 = el->front(); + if (el1->count_choices() > 0) { + ExpAggregate*tmp = new ExpAggregate(el); + FILE_NAME(tmp,loc); + return tmp; + } + + return el1->extract_expression(); +} + +static list* record_elements(list*names, + const VType*type) +{ + list*res = new list; + + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++cur) { + res->push_back(new VTypeRecord::element_t(*cur, type)); + } + + return res; +} + %} @@ -148,8 +190,6 @@ const VType*parse_type_by_name(perm_string name) char*text; std::list* name_list; - std::vector* compound_name; - std::list* >* compound_name_list; bool flag; int64_t uni_integer; @@ -164,6 +204,9 @@ const VType*parse_type_by_name(perm_string name) IfSequential::Elsif*elsif; std::list*elsif_list; + ExpConditional::else_t*exp_else; + std::list*exp_else_list; + CaseSeqStmt::CaseStmtAlternative* case_alt; std::list* case_alt_list; @@ -185,6 +228,8 @@ const VType*parse_type_by_name(perm_string name) ExpAggregate::element_t*element; std::list*element_list; + std::list*record_elements; + std::list* interface_list; Architecture::Statement* arch_statement; @@ -239,8 +284,11 @@ const VType*parse_type_by_name(perm_string name) %type instantiation_list %type component_specification -%type concurrent_statement component_instantiation_statement concurrent_signal_assignment_statement -%type for_generate_statement process_statement +%type concurrent_statement component_instantiation_statement +%type concurrent_conditional_signal_assignment +%type concurrent_signal_assignment_statement +%type for_generate_statement generate_statement if_generate_statement +%type process_statement %type architecture_statement_part generate_statement_body %type choice @@ -251,7 +299,7 @@ const VType*parse_type_by_name(perm_string name) %type expression factor primary relation %type expression_logical expression_logical_and expression_logical_or %type expression_logical_xnor expression_logical_xor -%type name +%type name prefix selected_name %type shift_expression signal_declaration_assign_opt %type simple_expression term waveform_element %type interface_element_expression @@ -259,24 +307,27 @@ const VType*parse_type_by_name(perm_string name) %type waveform waveform_elements %type name_list expression_list %type process_sensitivity_list process_sensitivity_list_opt +%type selected_names use_clause %type association_element %type association_list port_map_aspect port_map_aspect_opt %type generic_map_aspect generic_map_aspect_opt +%type composite_type_definition record_type_definition %type subtype_indication type_definition +%type element_declaration element_declaration_list + %type architecture_body_start package_declaration_start %type identifier_opt identifier_colon_opt logical_name suffix %type logical_name_list identifier_list %type enumeration_literal_list enumeration_literal -%type prefix selected_name -%type selected_names use_clause %type sequence_of_statements if_statement_else %type sequential_statement if_statement signal_assignment_statement %type case_statement procedure_call procedure_call_statement %type loop_statement variable_assignment_statement +%type return_statement %type range %type range_list index_constraint @@ -287,6 +338,9 @@ const VType*parse_type_by_name(perm_string name) %type if_statement_elsif %type if_statement_elsif_list if_statement_elsif_list_opt +%type else_when_waveform +%type else_when_waveforms + %% /* The design_file is the root for the VHDL parse. This rule is also @@ -296,13 +350,13 @@ design_file : { yylloc.text = file_path; } design_units ; adding_operator : '+' { $$ = ExpArithmetic::PLUS; } | '-' { $$ = ExpArithmetic::MINUS; } - | '&' { $$ = ExpArithmetic::CONCAT; } + | '&' { $$ = ExpArithmetic::xCONCAT; } ; architecture_body : architecture_body_start K_of IDENTIFIER - { bind_entity_to_active_scope($3, active_scope) } + { bind_entity_to_active_scope($3, active_scope); } K_is block_declarative_items_opt K_begin architecture_statement_part K_end K_architecture_opt identifier_opt ';' { Architecture*tmp = new Architecture(lex_strings.make($1), @@ -506,6 +560,8 @@ choice { $$ = new ExpAggregate::choice_t($1);} | K_others { $$ = new ExpAggregate::choice_t; } + | range /* discrete_range: range */ + { $$ = new ExpAggregate::choice_t($1); } ; choices @@ -595,7 +651,81 @@ component_specification } ; -concurrent_signal_assignment_statement +composite_type_definition + /* constrained_array_definition */ + : K_array index_constraint K_of subtype_indication + { VTypeArray*tmp = new VTypeArray($4, $2); + delete $2; + $$ = tmp; + } + | record_type_definition + { $$ = $1; } + ; + + + /* The when...else..when...else syntax is not a general expression + in VHDL but a specific sort of assignment statement model. We + create Exppression objects for it, but the parser will only + recognize it it in specific situations. */ +concurrent_conditional_signal_assignment /* IEEE 1076-2008 P11.6 */ + : name LEQ waveform K_when expression else_when_waveforms ';' + { ExpConditional*tmp = new ExpConditional($5, $3, $6); + FILE_NAME(tmp, @3); + delete $3; + delete $6; + + ExpName*name = dynamic_cast ($1); + assert(name); + SignalAssignment*tmpa = new SignalAssignment(name, tmp); + FILE_NAME(tmpa, @1); + + $$ = tmpa; + } + + /* Error recovery rules. */ + + | name LEQ error K_when expression else_when_waveforms ';' + { errormsg(@3, "Syntax error in waveform of conditional signal assignment.\n"); + ExpConditional*tmp = new ExpConditional($5, 0, $6); + FILE_NAME(tmp, @3); + delete $6; + + ExpName*name = dynamic_cast ($1); + assert(name); + SignalAssignment*tmpa = new SignalAssignment(name, tmp); + FILE_NAME(tmpa, @1); + + $$ = tmpa; + } + ; + +else_when_waveforms + : else_when_waveforms else_when_waveform + { list*tmp = $1; + tmp ->push_back($2); + $$ = tmp; + } + | else_when_waveform + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + ; + +else_when_waveform + : K_else waveform K_when expression + { ExpConditional::else_t*tmp = new ExpConditional::else_t($4, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_else waveform + { ExpConditional::else_t*tmp = new ExpConditional::else_t(0, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + +concurrent_signal_assignment_statement /* IEEE 1076-2008 P11.6 */ : name LEQ waveform ';' { ExpName*name = dynamic_cast ($1); assert(name); @@ -605,19 +735,9 @@ concurrent_signal_assignment_statement $$ = tmp; delete $3; } - | name LEQ waveform K_when expression K_else waveform ';' - { ExpConditional*tmp = new ExpConditional($5, $3, $7); - FILE_NAME(tmp, @3); - delete $3; - delete $7; - ExpName*name = dynamic_cast ($1); - assert(name); - SignalAssignment*tmpa = new SignalAssignment(name, tmp); - FILE_NAME(tmpa, @1); + | concurrent_conditional_signal_assignment - $$ = tmpa; - } | name LEQ error ';' { errormsg(@2, "Syntax error in signal assignment waveform.\n"); delete $1; @@ -635,7 +755,7 @@ concurrent_signal_assignment_statement concurrent_statement : component_instantiation_statement | concurrent_signal_assignment_statement - | for_generate_statement + | generate_statement | process_statement ; @@ -699,6 +819,29 @@ constant_declaration { sorrymsg(@1, "Deferred constant declarations not supported\n"); delete $2; } + + /* Some error handling... */ + + | K_constant identifier_list ':' subtype_indication VASSIGN error ';' + { // The syntax allows mutliple names to have the same type/value. + errormsg(@6, "Error in value expression for constants.\n"); + yyerrok; + for (std::list::iterator cur = $2->begin() + ; cur != $2->end() ; ++cur) { + active_scope->bind_name(*cur, $4, 0); + } + delete $2; + } + | K_constant identifier_list ':' error ';' + { errormsg(@4, "Syntax error in constant declaration type.\n"); + yyerrok; + delete $2; + } + | K_constant error ';' + { errormsg(@2, "Syntax error in constant declaration.\n"); + yyerrok; + } + ; context_clause : context_items | ; @@ -732,6 +875,10 @@ element_association { ExpAggregate::element_t*tmp = new ExpAggregate::element_t($1, $3); $$ = tmp; } + | expression + { ExpAggregate::element_t*tmp = new ExpAggregate::element_t(0, $1); + $$ = tmp; + } ; element_association_list @@ -747,6 +894,21 @@ element_association_list } ; +element_declaration + : identifier_list ':' subtype_indication ';' + { $$ = record_elements($1, $3); } + ; + +element_declaration_list + : element_declaration_list element_declaration + { $$ = $1; + $$->splice($$->end(), *$2); + delete $2; + } + | element_declaration + { $$ = $1; } + ; + /* As an entity is declared, add it to the map of design entities. */ entity_aspect : K_entity name @@ -979,6 +1141,15 @@ for_generate_statement } ; +function_specification /* IEEE 1076-2008 P4.2.1 */ + : K_function IDENTIFIER '(' interface_list ')' K_return IDENTIFIER + ; + +generate_statement /* IEEE 1076-2008 P11.8 */ + : if_generate_statement + | for_generate_statement + ; + generate_statement_body : architecture_statement_part { $$ = $1; } ; @@ -1034,6 +1205,29 @@ identifier_opt : IDENTIFIER { $$ = $1; } | { $$ = 0; } ; identifier_colon_opt : IDENTIFIER ':' { $$ = $1; } | { $$ = 0; }; + /* The if_generate_statement rule describes the if_generate syntax. + + NOTE: This does not yet implement the elsif and else parts of the + syntax. This shouldn't be hard, but is simply not done yet. */ +if_generate_statement /* IEEE 1076-2008 P11.8 */ + : IDENTIFIER ':' K_if expression + K_generate generate_statement_body + K_end K_generate identifier_opt ';' + { perm_string name = lex_strings.make($1); + IfGenerate*tmp = new IfGenerate(name, $4, *$6); + FILE_NAME(tmp, @3); + + if ($9 && name != $9) { + errormsg(@1, "if-generate name %s does not match closing name %s\n", + name.str(), $9); + } + delete[]$1; + delete $6; + delete[]$9; + $$ = tmp; + } + ; + if_statement : K_if expression K_then sequence_of_statements if_statement_elsif_list_opt if_statement_else @@ -1115,6 +1309,11 @@ if_statement_else index_constraint : '(' range_list ')' { $$ = $2; } + | '(' error ')' + { errormsg(@2, "Errors in the index constraint.\n"); + yyerrok; + $$ = new list; + } ; instantiation_list @@ -1147,7 +1346,6 @@ interface_element port->name = *(cur); port->type = $4; port->expr = $5; - ivl_assert(*port, port->type); tmp->push_back(port); } delete $1; @@ -1275,18 +1473,22 @@ mode mode_opt : mode {$$ = $1;} | {$$ = PORT_NONE;} ; -name - : IDENTIFIER +name /* IEEE 1076-2008 P8.1 */ + : IDENTIFIER /* simple_name (IEEE 1076-2008 P8.2) */ { ExpName*tmp = new ExpName(lex_strings.make($1)); FILE_NAME(tmp, @1); delete[]$1; $$ = tmp; } + + | selected_name + { $$ = $1; } + /* Note that this rule can match array element selects and various function calls. The only way we can tell the difference is from left context, namely whether the name is a type name or function name. If none of the above, treat it as a array element select. */ - | IDENTIFIER '(' expression_list ')' + | IDENTIFIER '(' expression_list ')' { perm_string name = lex_strings.make($1); delete[]$1; if (active_scope->is_vector_name(name)) { @@ -1298,12 +1500,17 @@ name } FILE_NAME($$, @1); } - | IDENTIFIER '(' range ')' + | IDENTIFIER '(' range ')' { ExpName*tmp = new ExpName(lex_strings.make($1), $3->msb(), $3->lsb()); FILE_NAME(tmp, @1); delete[]$1; $$ = tmp; } + | selected_name '(' range ')' + { ExpName*tmp = dynamic_cast ($1); + tmp->set_range($3->msb(), $3->lsb()); + $$ = tmp; + } ; /* Handle name lists as lists of expressions. */ @@ -1355,8 +1562,9 @@ package_declaration_start /* TODO: this list must be extended in the future presently it is only a sketch */ -package_body_declarative_item +package_body_declarative_item /* IEEE1076-2008 P4.8 */ : use_clause + | subprogram_body ; package_body_declarative_items @@ -1371,8 +1579,14 @@ package_body_declarative_part_opt package_declarative_item : component_declaration | constant_declaration + | subprogram_declaration | subtype_declaration + | type_declaration | use_clause + | error ';' + { errormsg(@1, "Syntax error in package declarative item.\n"); + yyerrok; + } ; package_declarative_items @@ -1389,17 +1603,16 @@ package_body : K_package K_body IDENTIFIER K_is package_body_declarative_part_opt K_end K_package_opt identifier_opt ';' - { - sorrymsg(@1, "Package body is not yet supported.\n"); - delete[] $3; - if($8) delete[] $8; + { sorrymsg(@1, "Package body is not yet supported.\n"); + delete[] $3; + if($8) delete[] $8; } | K_package K_body IDENTIFIER K_is error K_end K_package_opt identifier_opt ';' - { - errormsg(@1, "Errors in package body.\n"); + { errormsg(@1, "Errors in package body.\n"); + yyerrok; } ; @@ -1420,6 +1633,7 @@ port_map_aspect { $$ = $4; } | K_port K_map '(' error ')' { errormsg(@1, "Syntax error in port map aspect.\n"); + yyerrok; } ; @@ -1428,20 +1642,9 @@ port_map_aspect_opt | { $$ = 0; } ; -prefix - : IDENTIFIER - { std::vector* tmp = new std::vector(); - tmp->push_back(lex_strings.make($1)); - delete[] $1; - $$ = tmp; - } - | STRING_LITERAL - { std::vector* tmp = new std::vector(); - tmp->push_back(lex_strings.make($1)); - delete[] $1; - $$ = tmp; - } - | selected_name + +prefix /* IEEE 1076-2008 P8.1 */ + : name { $$ = $1; } ; @@ -1479,7 +1682,10 @@ primary delete[]$1; $$ = tmp; } - +/*XXXX Caught up in element_association_list? + | '(' expression ')' + { $$ = $2; } +*/ /* This catches function calls that use association lists for the argument list. The position argument list is discovered elsewhere and must be discovered by elaboration (thanks to the ambiguity of @@ -1489,11 +1695,10 @@ primary $$ = 0; } - | '(' expression ')' - { $$ = $2; } + /* Aggregates */ + | '(' element_association_list ')' - { ExpAggregate*tmp = new ExpAggregate($2); - FILE_NAME(tmp,@1); + { Expression*tmp = aggregate_or_primary(@1, $2); $$ = tmp; } ; @@ -1638,6 +1843,13 @@ range_list } ; +record_type_definition + : K_record element_declaration_list K_end K_record + { VTypeRecord*tmp = new VTypeRecord($2); + $$ = tmp; + } + ; + relation : shift_expression { $$ = $1; } @@ -1673,41 +1885,67 @@ relation } ; +return_statement + : K_return expression ';' + { ReturnStmt*tmp = new ReturnStmt($2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_return ';' + { ReturnStmt*tmp = new ReturnStmt(0); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_return error ';' + { ReturnStmt*tmp = new ReturnStmt(0); + FILE_NAME(tmp, @1); + $$ = tmp; + errormsg(@2, "Error in expression in return statement.\n"); + yyerrok; + } + ; + secondary_unit : architecture_body | package_body ; -selected_name +selected_name /* IEEE 1076-2008 P8.3 */ : prefix '.' suffix - { - std::vector* tmp = $1; - tmp->push_back(lex_strings.make($3)); - delete[] $3; - - $$ = tmp; + { Expression*pfx = $1; + ExpName*pfx1 = dynamic_cast(pfx); + assert(pfx1); + perm_string tmp = lex_strings.make($3); + $$ = new ExpName(pfx1, tmp); + FILE_NAME($$, @3); + delete[]$3; + } + | error '.' suffix + { errormsg(@1, "Syntax error in prefix in front of \"%s\".\n", $3); + yyerrok; + $$ = new ExpName(lex_strings.make($3)); + FILE_NAME($$, @3); + delete[]$3; } ; selected_names : selected_names ',' selected_name - { - std::list* >* tmp = $1; - tmp->push_back($3); - $$ = tmp; + { std::list* tmp = $1; + tmp->push_back($3); + $$ = tmp; } | selected_name - { - std::list* >* tmp = new std::list* >(); - tmp->push_back($1); - $$ = tmp; + { std::list* tmp = new std::list(); + tmp->push_back($1); + $$ = tmp; } ; - /* The *_use variant of selected_name is used by the "use" + /* The *_lib variant of selected_name is used by the "use" clause. It is syntactically identical to other selected_name rules, but is a convenient place to attach use_clause actions. */ -selected_name_use +selected_name_lib : IDENTIFIER '.' K_all { library_use(@1, active_scope, 0, $1, 0); delete[]$1; @@ -1725,9 +1963,9 @@ selected_name_use } ; -selected_names_use - : selected_names_use ',' selected_name_use - | selected_name_use +selected_names_lib + : selected_names_lib ',' selected_name_lib + | selected_name_lib ; @@ -1753,6 +1991,7 @@ sequential_statement | case_statement { $$ = $1; } | procedure_call_statement { $$ = $1; } | loop_statement { $$ = $1; } + | return_statement { $$ = $1; } | K_null ';' { $$ = 0; } | error ';' { errormsg(@1, "Syntax error in sequential statement.\n"); @@ -1777,12 +2016,21 @@ signal_declaration_assign_opt * however, is right-recursive, which is not to nice is real LALR * parsers. The solution is to rewrite it as below, to make it * left-recursive. This is must more effecient use of the parse stack. + * + * Note that although the concatenation operator '&' is syntactically + * an addition operator, it is handled differently during elaboration + * so detect it and create a different expression type. */ simple_expression : term { $$ = $1; } | simple_expression adding_operator term - { ExpArithmetic*tmp = new ExpArithmetic($2, $1, $3); + { Expression*tmp; + if ($2 == ExpArithmetic::xCONCAT) { + tmp = new ExpConcat($1, $3); + } else { + tmp = new ExpArithmetic($2, $1, $3); + } FILE_NAME(tmp, @2); $$ = tmp; } @@ -1803,6 +2051,66 @@ signal_assignment_statement } ; +subprogram_body /* IEEE 1076-2008 P4.3 */ + : subprogram_specification K_is + subprogram_declarative_part + K_begin subprogram_statement_part K_end + subprogram_kind_opt identifier_opt ';' + { sorrymsg(@2, "Subprogram bodies not supported.\n"); + if ($8) delete[]$8; + } + + | subprogram_specification K_is + subprogram_declarative_part + K_begin error K_end + subprogram_kind_opt identifier_opt ';' + { errormsg(@2, "Syntax errors in subprogram body.\n"); + yyerrok; + if ($8) delete[]$8; + } + ; + +subprogram_declaration + : subprogram_specification ';' + { sorrymsg(@1, "Subprogram specifications not supported.\n"); + } + ; + +subprogram_declarative_item /* IEEE 1079-2008 P4.3 */ + : variable_declaration + ; + +subprogram_declarative_item_list + : subprogram_declarative_item_list subprogram_declarative_item + | subprogram_declarative_item + ; + +subprogram_declarative_part /* IEEE 1076-2008 P4.3 */ + : subprogram_declarative_item_list + | + ; + +subprogram_kind /* IEEE 1076-2008 P4.3 */ + : K_function + | K_procedure + ; + +subprogram_kind_opt : subprogram_kind | ; + +subprogram_specification + : function_specification + ; + + /* This is an implementation of the rule: + subprogram_statement_part ::= { sequential_statement } + where the sequence_of_statements rule is a list of + sequential_statement. Also handle the special case of an empty + list here. */ +subprogram_statement_part + : sequence_of_statements + | + ; + subtype_declaration : K_subtype IDENTIFIER K_is subtype_indication ';' { perm_string name = lex_strings.make($2); @@ -1819,6 +2127,7 @@ subtype_indication { const VType*tmp = parse_type_by_name(lex_strings.make($1)); if (tmp == 0) { errormsg(@1, "Can't find type name `%s'\n", $1); + tmp = new VTypeERROR; } delete[]$1; $$ = tmp; @@ -1840,24 +2149,20 @@ subtype_indication $$ = tmp; } | IDENTIFIER '(' error ')' - { - errormsg(@1, "Syntax error in subtype indication.\n"); + { errormsg(@1, "Syntax error in subtype indication.\n"); + yyerrok; + $$ = new VTypeERROR; } ; suffix : IDENTIFIER - { - $$ = $1; - } + { $$ = $1; } | CHARACTER_LITERAL - { - $$ = $1; - } + { $$ = $1; } | K_all - { - //do not have now better idea than using char constant - $$ = strcpy(new char[strlen("all"+1)], "all"); + { //do not have now better idea than using char constant + $$ = strcpy(new char[strlen("all"+1)], "all"); } ; @@ -1892,17 +2197,35 @@ type_declaration if ($4 == 0) { errormsg(@1, "Failed to declare type name %s.\n", name.str()); } else { - //VTypeDef*tmp = new VTypeDef(name, $4); - //active_scope->bind_name(name, tmp); - active_scope->bind_name(name, $4); + VTypeDef*tmp; + map::iterator cur = active_scope->incomplete_types.find(name); + if (cur == active_scope->incomplete_types.end()) { + tmp = new VTypeDef(name, $4); + active_scope->bind_name(name, tmp); + } else { + tmp = cur->second; + tmp->set_definition($4); + active_scope->incomplete_types.erase(cur); + } } delete[]$2; } + | K_type IDENTIFIER ';' + { perm_string name = lex_strings.make($2); + VTypeDef*tmp = new VTypeDef(name); + active_scope->incomplete_types[name] = tmp; + active_scope->bind_name(name, tmp); + delete[]$2; + } | K_type IDENTIFIER K_is error ';' { errormsg(@4, "Error in type definition for %s\n", $2); yyerrok; delete[]$2; } + | K_type error ';' + { errormsg(@1, "Error in type definition\n"); + yyerrok; + } ; type_definition @@ -1911,40 +2234,35 @@ type_definition delete $2; $$ = tmp; } - /* constrained_array_definition */ - | K_array index_constraint K_of subtype_indication - { VTypeArray*tmp = new VTypeArray($4, $2); - delete $2; - $$ = tmp; - } + | composite_type_definition + { $$ = $1; } + ; use_clause : K_use selected_names ';' - { - $$ = $2; - } + { $$ = $2; } | K_use error ';' { errormsg(@1, "Syntax error in use clause.\n"); yyerrok; } ; use_clause_lib - : K_use selected_names_use ';' + : K_use selected_names_lib ';' | K_use error ';' { errormsg(@1, "Syntax error in use clause.\n"); yyerrok; } ; -use_clauses - : use_clauses use_clause - | use_clause +use_clauses_lib + : use_clauses_lib use_clause_lib + | use_clause_lib ; use_clauses_opt - : use_clauses + : use_clauses_lib | ; -variable_assignment_statement +variable_assignment_statement /* IEEE 1076-2008 P10.6.1 */ : name VASSIGN expression ';' { VariableSeqAssignment*tmp = new VariableSeqAssignment($1, $3); FILE_NAME(tmp, @1); @@ -1964,6 +2282,16 @@ variable_assignment_statement } ; +variable_declaration /* IEEE 1076-2008 P6.4.2.4 */ + : K_shared_opt K_variable identifier_list ':' subtype_indication ';' + { sorrymsg(@2, "variable_declaration not supported.\n"); } + + | K_shared_opt K_variable error ';' + { errormsg(@2, "Syntax error in variable declaration.\n"); + yyerrok; + } + ; + waveform : waveform_elements { $$ = $1; } @@ -1997,9 +2325,10 @@ K_architecture_opt : K_architecture | ; K_component_opt : K_component | ; K_configuration_opt: K_configuration| ; K_entity_opt : K_entity | ; +K_is_opt : K_is | ; K_package_opt : K_package | ; K_postponed_opt : K_postponed | ; -K_is_opt : K_is | ; +K_shared_opt : K_shared | ; %% static void yyerror(YYLTYPE*, yyscan_t, const char*, bool, const char* /*msg*/) diff --git a/vhdlpp/parse_api.h b/vhdlpp/parse_api.h index d4da8543b..0bfd6587a 100644 --- a/vhdlpp/parse_api.h +++ b/vhdlpp/parse_api.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -25,7 +25,7 @@ typedef void*yyscan_t; /* - * The vlltype supports the passing of detailed source file location + * The yyltype supports the passing of detailed source file location * information between the lexical analyzer and the parser. Defining * YYLTYPE compels the lexor to use this type and not something other. */ diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 045988f6c..10c058966 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704. */ diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index d62c3e92c..da1fd0135 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "parse_api.h" @@ -63,4 +63,6 @@ extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, extern void generate_global_types(ActiveScope*res); +extern bool is_global_type(perm_string type_name); + #endif diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 7f24a0025..2a8b27520 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "StringHeap.h" diff --git a/vhdlpp/parse_wrap.h b/vhdlpp/parse_wrap.h index d3df89cc4..d129fec43 100644 --- a/vhdlpp/parse_wrap.h +++ b/vhdlpp/parse_wrap.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index a0c51bb2e..0455f7a88 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "scope.h" @@ -24,6 +24,12 @@ using namespace std; +/* + * If the merge_flag is passed in, then the new scope is a merge of + * the parent scopes. This brings in all of the parent scopes into the + * "old_*_" variables. This clears up the "new_*_" variables to + * accumulate new scope values. + */ ScopeBase::ScopeBase(const ScopeBase&ref) { merge(ref.old_constants_.begin(), ref.old_constants_.end(), diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 121b46627..e0fbfb0b3 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -1,7 +1,7 @@ #ifndef __scope_H #define __scope_H /* - * 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 @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include @@ -95,7 +95,7 @@ class ScopeBase { class Scope : public ScopeBase { public: - Scope(const ScopeBase&ref); + explicit Scope(const ScopeBase&ref); ~Scope(); ComponentBase* find_component(perm_string by_name); @@ -179,6 +179,10 @@ class ActiveScope : public ScopeBase { cleanup(); } + // Keep track of incomplete types until their proper + // definition shows up. + std::map incomplete_types; + private: Entity*context_entity_; }; diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index 894f0b667..9d5d8d6e3 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sequential.h" @@ -153,6 +153,16 @@ ProcedureCall::~ProcedureCall() } } +ReturnStmt::ReturnStmt(Expression*val) +: val_(val) +{ +} + +ReturnStmt::~ReturnStmt() +{ + delete val_; +} + LoopStatement::LoopStatement(perm_string name, list* stmts) : name_(name) { diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 4f7b4ae68..bd553fef6 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "LineInfo.h" @@ -110,6 +110,18 @@ class IfSequential : public SequentialStmt { std::list else_; }; +class ReturnStmt : public SequentialStmt { + public: + ReturnStmt(Expression*val); + ~ReturnStmt(); + + public: + void dump(ostream&out, int indent) const; + + private: + Expression*val_; +}; + class SignalSeqAssignment : public SequentialStmt { public: SignalSeqAssignment(Expression*sig, std::list*wav); diff --git a/vhdlpp/sequential_debug.cc b/vhdlpp/sequential_debug.cc index f122e41ad..b28d0f8cc 100644 --- a/vhdlpp/sequential_debug.cc +++ b/vhdlpp/sequential_debug.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sequential.h" @@ -65,6 +65,15 @@ void IfSequential::Elsif::dump(ostream&out, int indent) const } +void ReturnStmt::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "ReturnStmt at file=" << get_fileline() << endl; + if (val_) + val_->dump(out, indent+4); + else + out << setw(indent+4) << "" << "()" << endl; +} + void SignalSeqAssignment::dump(ostream&out, int indent) const { out << setw(indent) << "" << "SignalSeqAssignment at file=" << get_fileline() << endl; diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index dc0fe0c0a..184f85d56 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sequential.h" diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 92e49b821..a7e8e40f4 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sequential.h" diff --git a/vhdlpp/vhdlint.cc b/vhdlpp/vhdlint.cc index 9828f6349..0ca117fe9 100644 --- a/vhdlpp/vhdlint.cc +++ b/vhdlpp/vhdlint.cc @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "vhdlint.h" diff --git a/vhdlpp/vhdlint.h b/vhdlpp/vhdlint.h index 4b3e535f6..849a82485 100644 --- a/vhdlpp/vhdlint.h +++ b/vhdlpp/vhdlint.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/vhdlpp/vhdlpp_config.h.in b/vhdlpp/vhdlpp_config.h.in index b48d2caef..65120e08b 100644 --- a/vhdlpp/vhdlpp_config.h.in +++ b/vhdlpp/vhdlpp_config.h.in @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if defined(__cplusplus) diff --git a/vhdlpp/vhdlreal.cc b/vhdlpp/vhdlreal.cc index 6651b2d14..72662fba3 100644 --- a/vhdlpp/vhdlreal.cc +++ b/vhdlpp/vhdlreal.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "vhdlreal.h" diff --git a/vhdlpp/vhdlreal.h b/vhdlpp/vhdlreal.h index 25b0616e1..9753a6ad3 100644 --- a/vhdlpp/vhdlreal.h +++ b/vhdlpp/vhdlreal.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index f0d60fee7..29627f924 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vsignal.h" diff --git a/vhdlpp/vsignal.h b/vhdlpp/vsignal.h index 14cbe586f..777daa80f 100644 --- a/vhdlpp/vsignal.h +++ b/vhdlpp/vsignal.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "StringHeap.h" diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 4a8e4ced7..b8e704d11 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -14,13 +14,14 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vtype.h" # include "parse_types.h" # include # include +# include using namespace std; @@ -162,6 +163,49 @@ void VTypeEnum::show(ostream&out) const out << ")"; } +VTypeRecord::VTypeRecord(std::list*elements) +: elements_(elements->size()) +{ + for (size_t idx = 0 ; idx < elements_.size() ; idx += 1) { + elements_[idx] = elements->front(); + elements->pop_front(); + } + delete elements; +} + +VTypeRecord::~VTypeRecord() +{ + for (size_t idx = 0 ; idx < elements_.size() ; idx += 1) + delete elements_[idx]; +} + +void VTypeRecord::show(ostream&out) const +{ + write_to_stream(out); +} + +const VTypeRecord::element_t* VTypeRecord::element_by_name(perm_string name) const +{ + for (vector::const_iterator cur = elements_.begin() + ; cur != elements_.end() ; ++cur) { + element_t*curp = *cur; + if (curp->peek_name() == name) + return curp; + } + + return 0; +} + +VTypeRecord::element_t::element_t(perm_string name, const VType*typ) +: name_(name), type_(typ) +{ +} + +VTypeDef::VTypeDef(perm_string nam) +: name_(nam), type_(0) +{ +} + VTypeDef::VTypeDef(perm_string nam, const VType*typ) : name_(nam), type_(typ) { @@ -170,3 +214,9 @@ VTypeDef::VTypeDef(perm_string nam, const VType*typ) VTypeDef::~VTypeDef() { } + +void VTypeDef::set_definition(const VType*typ) +{ + assert(type_ == 0); + type_ = typ; +} diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index bd3ffb788..4da22363d 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -16,11 +16,12 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include # include +# include # include # include # include @@ -28,6 +29,10 @@ class Expression; class prange_t; +class VTypeDef; + +typedef enum typedef_topo_e { NONE=0, PENDING, MARKED } typedef_topo_t; +typedef std::map typedef_context_t; /* * A description of a VHDL type consists of a graph of VType @@ -44,6 +49,10 @@ class VType { // of this type to the designated stream. This is used for // writing parsed types to library files. virtual void write_to_stream(std::ostream&fd) const; + // This is like the above, but is the root function called + // directly after the "type is..." when writing type + // definitions. Most types accept the default definition of this. + virtual void write_type_to_stream(std::ostream&fd) const; // This virtual method writes a human-readable version of the // type to a given file for debug purposes. (Question: is this @@ -52,13 +61,19 @@ class VType { // This virtual method emits a definition for the specific // type. It is used to emit typedef's. - virtual int emit_def(std::ostream&out, perm_string name) const =0; + virtual int emit_def(std::ostream&out) const =0; + + // This virtual method causes VTypeDef types to emit typedefs + // of themselves. The VTypeDef implementation of this method + // uses this method recursively to do a depth-first emit of + // all the types that it emits. + virtual int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; private: friend class decl_t; // This virtual method is called to emit the declaration. This // is used by the decl_t object to emit variable/wire/port declarations. - virtual int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const =0; + virtual int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; public: // A couple places use the VType along with a few @@ -83,7 +98,15 @@ inline std::ostream&operator << (std::ostream&out, const VType&item) extern void preload_global_types(void); /* - * This class represents the primative types that are available to the + * This type is a placeholder for ERROR types. + */ +class VTypeERROR : public VType { + public: + int emit_def(std::ostream&out) const; +}; + +/* + * This class represents the primitive types that are available to the * type subsystem. */ class VTypePrimitive : public VType { @@ -101,10 +124,7 @@ class VTypePrimitive : public VType { type_t type() const { return type_; } int emit_primitive_type(std::ostream&fd) const; - - int emit_def(std::ostream&out, perm_string name) const; - private: - int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; + int emit_def(std::ostream&out) const; private: type_t type_; @@ -155,10 +175,8 @@ class VTypeArray : public VType { const VType* element_type() const; - int emit_def(std::ostream&out, perm_string name) const; - - private: - int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; + int emit_def(std::ostream&out) const; + int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; private: const VType*etype_; @@ -173,9 +191,8 @@ class VTypeRange : public VType { VTypeRange(const VType*base, int64_t max_val, int64_t min_val); ~VTypeRange(); - int emit_def(std::ostream&out, perm_string name) const; - private: - int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; + void write_to_stream(std::ostream&fd) const; + int emit_def(std::ostream&out) const; private: const VType*base_; @@ -189,24 +206,69 @@ class VTypeEnum : public VType { ~VTypeEnum(); void show(std::ostream&) const; - - int emit_def(std::ostream&out, perm_string name) const; - private: - int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; + int emit_def(std::ostream&out) const; private: std::vectornames_; }; +class VTypeRecord : public VType { + + public: + class element_t { + public: + element_t(perm_string name, const VType*type); + + void write_to_stream(std::ostream&) const; + + inline perm_string peek_name() const { return name_; } + inline const VType* peek_type() const { return type_; } + + private: + perm_string name_; + const VType*type_; + + private:// Not implement + element_t(const element_t&); + element_t& operator= (const element_t); + }; + + public: + explicit VTypeRecord(std::list*elements); + ~VTypeRecord(); + + void write_to_stream(std::ostream&fd) const; + void show(std::ostream&) const; + int emit_def(std::ostream&out) const; + + const element_t* element_by_name(perm_string name) const; + + private: + std::vector elements_; +}; + class VTypeDef : public VType { public: - VTypeDef(perm_string name, const VType*is); + explicit VTypeDef(perm_string name); + explicit VTypeDef(perm_string name, const VType*is); ~VTypeDef(); - int emit_typedef(std::ostream&out) const; + inline perm_string peek_name() const { return name_; } - int emit_def(std::ostream&out, perm_string name) const; + // If the type is not given a definition in the constructor, + // then this must be used to set the definition later. + void set_definition(const VType*is); + + // In some situations, we only need the definition of the + // type, and this method gets it for us. + inline const VType* peek_definition(void) const { return type_; } + + void write_to_stream(std::ostream&fd) const; + void write_type_to_stream(ostream&fd) const; + int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; + + int emit_def(std::ostream&out) const; private: int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index e9a59c3b0..a3ca1add5 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -33,56 +33,76 @@ int VType::decl_t::emit(ostream&out, perm_string name) const } -int VTypeArray::emit_def(ostream&out, perm_string name) const +int VType::emit_decl(ostream&out, perm_string name, bool reg_flag) const { int errors = 0; - if (const VTypeArray*sub = dynamic_cast (etype_)) { - sub->emit_def(out, name); - assert(dimensions() == 1); - out << "["; - errors += dimension(0).msb()->emit(out, 0, 0); - out << ":"; - errors += dimension(0).lsb()->emit(out, 0, 0); - out << "] "; - return errors; - } - - const VTypePrimitive*base = dynamic_cast (etype_); - assert(base != 0); - assert(dimensions() == 1); - - base->emit_primitive_type(out); - if (signed_flag_) - out << "signed "; - - out << "["; - errors += dimension(0).msb()->emit(out, 0, 0); - out << ":"; - errors += dimension(0).lsb()->emit(out, 0, 0); - out << "] "; - - out << "\\" << name << " "; - - return errors; -} - -int VTypeArray::emit_decl(ostream&out, perm_string name, bool reg_flag) const -{ - int errors = 0; - assert(dimensions() == 1); - - if (reg_flag) - out << "reg "; - else + if (!reg_flag) out << "wire "; - errors += emit_def(out, name); + errors += emit_def(out); + + out << " \\" << name << " "; + return errors; +} + +int VType::emit_typedef(std::ostream&, typedef_context_t&) const +{ + return 0; +} + +int VTypeERROR::emit_def(ostream&out) const +{ + out << "/* ERROR */"; + return 1; +} + +int VTypeArray::emit_def(ostream&out) const +{ + int errors = 0; + + list dims; + const VTypeArray*cur = this; + while (const VTypeArray*sub = dynamic_cast (cur->etype_)) { + dims.push_back(cur); + cur = sub; + } + + const VType*raw_base = cur->etype_; + + const VTypePrimitive*base = dynamic_cast (raw_base); + + if (base) { + assert(dimensions() == 1); + + base->emit_def(out); + if (signed_flag_) + out << " signed"; + } else { + raw_base->emit_def(out); + } + + dims.push_back(cur); + + while (! dims.empty()) { + cur = dims.front(); + dims.pop_front(); + out << "["; + errors += cur->dimension(0).msb()->emit(out, 0, 0); + out << ":"; + errors += cur->dimension(0).lsb()->emit(out, 0, 0); + out << "]"; + } return errors; } -int VTypeEnum::emit_def(ostream&out, perm_string name) const +int VTypeArray::emit_typedef(std::ostream&out, typedef_context_t&ctx) const +{ + return etype_->emit_typedef(out, ctx); +} + +int VTypeEnum::emit_def(ostream&out) const { int errors = 0; out << "enum {"; @@ -91,31 +111,24 @@ int VTypeEnum::emit_def(ostream&out, perm_string name) const for (size_t idx = 1 ; idx < names_.size() ; idx += 1) out << ", \\" << names_[idx] << " "; - out << "} \\" << name << " "; + out << "}"; return errors; } -int VTypeEnum::emit_decl(ostream&out, perm_string name, bool reg_flag) const -{ - int errors = 0; - errors += emit_def(out, name); - return errors; -} - int VTypePrimitive::emit_primitive_type(ostream&out) const { int errors = 0; switch (type_) { case BOOLEAN: case BIT: - out << "bool "; + out << "bool"; break; case STDLOGIC: - out << "logic "; + out << "logic"; break; case INTEGER: - out << "bool [31:0] "; + out << "bool [31:0]"; break; default: assert(0); @@ -124,45 +137,47 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const return errors; } -int VTypePrimitive::emit_def(ostream&out, perm_string name) const +int VTypePrimitive::emit_def(ostream&out) const { int errors = 0; errors += emit_primitive_type(out); - out << "\\" << name << " "; return errors; } -int VTypePrimitive::emit_decl(ostream&out, perm_string name, bool reg_flag) const +int VTypeRange::emit_def(ostream&out) const { int errors = 0; - if (reg_flag) - out << "reg "; - else - out << "wire "; - - errors += emit_def(out, name); - + out << "/* Internal error: Don't know how to emit range */"; + errors += base_->emit_def(out); return errors; } -int VTypeRange::emit_def(ostream&out, perm_string name) const +int VTypeRecord::emit_def(ostream&out) const { int errors = 0; - assert(0); + out << "struct packed {"; + + for (vector::const_iterator cur = elements_.begin() + ; cur != elements_.end() ; ++cur) { + perm_string element_name = (*cur)->peek_name(); + const VType*element_type = (*cur)->peek_type(); + element_type->emit_def(out); + out << " \\" << element_name << " ; "; + } + + out << "}"; return errors; } -int VTypeRange::emit_decl(ostream&out, perm_string name, bool reg_flag) const +/* + * For VTypeDef objects, use the name of the defined type as the + * type. (We are defining a variable here, not the type itself.) The + * emit_typedef() method was presumably called to define type already. + */ +int VTypeDef::emit_def(ostream&out) const { int errors = 0; - assert(0); - return errors; -} - -int VTypeDef::emit_def(ostream&out, perm_string name) const -{ - int errors = 0; - assert(0); + out << "\\" << name_ << " "; return errors; } @@ -174,15 +189,35 @@ int VTypeDef::emit_decl(ostream&out, perm_string name, bool reg_flag) const else out << "wire "; - out << "\\" << name_ << " \\" << name << " "; + errors += type_->emit_def(out); + out << " \\" << name << " "; return errors; } -int VTypeDef::emit_typedef(ostream&out) const +int VTypeDef::emit_typedef(ostream&out, typedef_context_t&ctx) const { - int errors = 0; + // The typedef_context_t is used by me to determine if this + // typedef has already been emitted in this architecture. If + // it has, then it is MARKED, give up. Otherwise, recurse the + // emit_typedef to make sure all sub-types that I use have + // been emitted, then emit my typedef. + typedef_topo_t&flag = ctx[this]; + switch (flag) { + case MARKED: + return 0; + case PENDING: + out << "typedef \\" << name_ << " ; /* typedef cycle? */" << endl; + return 0; + case NONE: + break; + } + + flag = PENDING; + int errors = type_->emit_typedef(out, ctx); + flag = MARKED; + out << "typedef "; - errors += type_->emit_def(out, name_); - out << ";" << endl; + errors += type_->emit_def(out); + out << " \\" << name_ << " ;" << endl; return errors; } diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index c87b80ecc..661626e6a 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vtype.h" @@ -29,17 +29,28 @@ void VType::write_to_stream(ostream&fd) const fd << "/* UNKNOWN TYPE: " << typeid(*this).name() << " */"; } +void VType::write_type_to_stream(ostream&fd) const +{ + write_to_stream(fd); +} + void VTypeArray::write_to_stream(ostream&fd) const { // Special case: std_logic_vector if (etype_ == primitive_STDLOGIC) { fd << "std_logic_vector"; - if (! ranges_.empty()) { + if (! ranges_.empty() && ! ranges_[0].is_box()) { assert(ranges_.size() < 2); fd << " ("; - ranges_[0].msb()->write_to_stream(fd); + if (ranges_[0].msb()) + ranges_[0].msb()->write_to_stream(fd); + else + fd << "<>"; fd << " downto "; - ranges_[0].lsb()->write_to_stream(fd); + if (ranges_[0].lsb()) + ranges_[0].lsb()->write_to_stream(fd); + else + fd << "<>"; fd << ") "; } return; @@ -48,17 +59,38 @@ void VTypeArray::write_to_stream(ostream&fd) const fd << "array "; if (! ranges_.empty()) { assert(ranges_.size() < 2); - fd << "("; - ranges_[0].msb()->write_to_stream(fd); - fd << " downto "; - ranges_[0].lsb()->write_to_stream(fd); - fd << ") "; + if (ranges_[0].is_box()) { + fd << "(INTEGER range <>) "; + } else { + assert(ranges_[0].msb() && ranges_[0].lsb()); + fd << "("; + if (ranges_[0].msb()) + ranges_[0].msb()->write_to_stream(fd); + else + fd << "<>"; + fd << " downto "; + if (ranges_[0].lsb()) + ranges_[0].lsb()->write_to_stream(fd); + else + fd << "<>"; + fd << ") "; + } } fd << "of "; etype_->write_to_stream(fd); } +void VTypeDef::write_type_to_stream(ostream&fd) const +{ + type_->write_to_stream(fd); +} + +void VTypeDef::write_to_stream(ostream&fd) const +{ + fd << name_; +} + void VTypePrimitive::write_to_stream(ostream&fd) const { switch (type_) { @@ -71,9 +103,34 @@ void VTypePrimitive::write_to_stream(ostream&fd) const case STDLOGIC: fd << "std_logic"; break; + case BOOLEAN: + fd << "boolean"; + break; default: assert(0); fd << "/* PRIMITIVE: " << type_ << " */"; break; } } + +void VTypeRange::write_to_stream(ostream&fd) const +{ + base_->write_to_stream(fd); + fd << " range " << min_ << " to " << max_; +} + +void VTypeRecord::write_to_stream(ostream&fd) const +{ + fd << "record "; + for (size_t idx = 0 ; idx < elements_.size() ; idx += 1) { + elements_[idx]->write_to_stream(fd); + fd << "; "; + } + fd << "end record"; +} + +void VTypeRecord::element_t::write_to_stream(ostream&fd) const +{ + fd << name_ << ": "; + type_->write_to_stream(fd); +} diff --git a/vpi/Makefile.in b/vpi/Makefile.in index a0aa48993..80378e43e 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh @@ -52,11 +51,11 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ # Object files for system.vpi -O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \ - sys_finish.o sys_icarus.o sys_plusargs.o sys_queue.o sys_random.o \ - sys_random_mti.o sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \ - sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o mt19937int.o sys_priv.o \ - sdf_lexor.o sdf_parse.o stringheap.o vams_simparam.o \ +O = sys_table.o sys_convert.o sys_countdrivers.o sys_darray.o sys_deposit.o sys_display.o \ + sys_fileio.o sys_finish.o sys_icarus.o sys_plusargs.o sys_queue.o \ + sys_random.o sys_random_mti.o sys_readmem.o sys_readmem_lex.o sys_scanf.o \ + sys_sdf.o sys_string.o sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o mt19937int.o \ + sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o vams_simparam.o \ table_mod.o table_mod_lexor.o table_mod_parse.o OPP = vcd_priv2.o @@ -96,8 +95,8 @@ distclean: clean rm -f vpi_config.h stamp-vpi_config-h cppcheck: $(O:.o=.c) $(OPP:.o=.cc) $(M:.o=.c) $(V:.o=.c) - cppcheck --enable=all -f --suppressions $(srcdir)/cppcheck.sup \ - $(INCLUDE_PATH) $^ + cppcheck --enable=all -f --suppressions-list=$(srcdir)/cppcheck.sup \ + --relative-paths=$(srcdir) $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in ../config.status cd ..; ./config.status --file=vpi/$@ diff --git a/vpi/cppcheck.sup b/vpi/cppcheck.sup index 1ba0e2488..0ec47e24c 100644 --- a/vpi/cppcheck.sup +++ b/vpi/cppcheck.sup @@ -3,23 +3,26 @@ // problems will not be fixed. // fstapi.c from GTKWave -variableScope:fstapi.c:1713 -variableScope:fstapi.c:1841 -variableScope:fstapi.c:1935 -variableScope:fstapi.c:1936 -variableScope:fstapi.c:2642 -variableScope:fstapi.c:2962 -variableScope:fstapi.c:2966 -variableScope:fstapi.c:2967 -variableScope:fstapi.c:4641 +obsoleteFunctionsasctime:fstapi.c:652 +variableScope:fstapi.c:1707 +variableScope:fstapi.c:1965 +variableScope:fstapi.c:2109 +variableScope:fstapi.c:2268 +variableScope:fstapi.c:2269 +variableScope:fstapi.c:2976 +variableScope:fstapi.c:3304 +variableScope:fstapi.c:3313 +variableScope:fstapi.c:4982 // lxt2_write.c from GTKWave +obsoleteFunctionsalloca:lxt2_write.c:1813 +obsoleteFunctionsalloca:lxt2_write.c:1819 variableScope:lxt2_write.c:63 variableScope:lxt2_write.c:523 variableScope:lxt2_write.c:581 variableScope:lxt2_write.c:587 -variableScope:lxt2_write.c:1600 -variableScope:lxt2_write.c:2047 +variableScope:lxt2_write.c:1613 +variableScope:lxt2_write.c:2060 // lxt_write.c from GTKWave variableScope:lxt_write.c:31 @@ -28,11 +31,11 @@ variableScope:lxt_write.c:640 variableScope:lxt_write.c:1056 variableScope:lxt_write.c:1057 variableScope:lxt_write.c:1058 -variableScope:lxt_write.c:1841 -variableScope:lxt_write.c:2586 -variableScope:lxt_write.c:2587 -variableScope:lxt_write.c:2588 -variableScope:lxt_write.c:2589 +variableScope:lxt_write.c:1850 +variableScope:lxt_write.c:2595 +variableScope:lxt_write.c:2596 +variableScope:lxt_write.c:2597 +variableScope:lxt_write.c:2598 // The routines in sys_random.c are exact copies from IEEE1364-2005 and // they have scope warnings that we need to ignore. diff --git a/vpi/fstapi.c b/vpi/fstapi.c index f59a12fc8..f4f6611b3 100644 --- a/vpi/fstapi.c +++ b/vpi/fstapi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2011 Tony Bybell. + * Copyright (c) 2009-2012 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,13 @@ #include "fstapi.h" #include "fastlz.h" +#ifndef HAVE_LIBPTHREAD +#undef FST_WRITER_PARALLEL +#endif + +#ifdef FST_WRITER_PARALLEL +#include +#endif /* this define is to force writer backward compatibility with old readers */ #ifndef FST_DYNAMIC_ALIAS_DISABLE @@ -47,13 +54,17 @@ void **JenkinsIns(void *base_i, unsigned char *mem, uint32_t length, uint32_t ha #undef FST_DEBUG -#define FST_BREAK_SIZE (128 * 1024 * 1024) -#define FST_BREAK_ADD_SIZE (4 * 1024 * 1024) +#define FST_BREAK_SIZE (1UL << 27) +#define FST_BREAK_ADD_SIZE (1UL << 22) +#define FST_BREAK_SIZE_MAX (1UL << 31) +#define FST_ACTIVATE_HUGE_BREAK (2000000) +#define FST_ACTIVATE_HUGE_INC (2000000) + #define FST_WRITER_STR "fstWriter" #define FST_ID_NAM_SIZ (512) #define FST_DOUBLE_ENDTEST (2.7182818284590452354) #define FST_HDR_SIM_VERSION_SIZE (128) -#define FST_HDR_DATE_SIZE (128) +#define FST_HDR_DATE_SIZE (120) #define FST_GZIO_LEN (32768) #if defined(__i386__) || defined(__x86_64__) || defined(_AIX) @@ -73,9 +84,11 @@ void **JenkinsIns(void *base_i, unsigned char *mem, uint32_t length, uint32_t ha #ifdef __MINGW32__ #include +#ifndef HAVE_FSEEKO #define ftello ftell #define fseeko fseek #endif +#endif /* the recoded "extra" values... */ @@ -160,7 +173,6 @@ return(pnt); */ #ifdef FST_DO_MISALIGNED_OPS #define fstGetUint32(x) (*(uint32_t *)(x)) -#define fstWriterSetUint32(x,y) (*(uint32_t *)(x)) = (y) #else static uint32_t fstGetUint32(unsigned char *mem) { @@ -174,17 +186,6 @@ buf[3] = mem[3]; return(*(uint32_t *)buf); } - - -static void fstWriterSetUint32(unsigned char *mem, uint32_t u32) -{ -unsigned char *buf = (unsigned char *)(&u32); - -mem[0] = buf[0]; -mem[1] = buf[1]; -mem[2] = buf[2]; -mem[3] = buf[3]; -} #endif @@ -480,6 +481,7 @@ unsigned vc_emitted : 1; unsigned is_initial_time : 1; unsigned fastpack : 1; +int64_t timezero; off_t section_header_truncpos; uint32_t tchn_cnt, tchn_idx; uint64_t curtime; @@ -506,10 +508,29 @@ unsigned skip_writing_section_hdr : 1; unsigned size_limit_locked : 1; unsigned section_header_only : 1; unsigned flush_context_pending : 1; +unsigned parallel_enabled : 1; +unsigned parallel_was_enabled : 1; /* should really be semaphores, but are bytes to cut down on read-modify-write window size */ unsigned char already_in_flush; /* in case control-c handlers interrupt */ unsigned char already_in_close; /* in case control-c handlers interrupt */ + +#ifdef FST_WRITER_PARALLEL +pthread_mutex_t mutex; +pthread_t thread; +pthread_attr_t thread_attr; +struct fstWriterContext *xc_parent; +#endif + +size_t fst_orig_break_size; +size_t fst_orig_break_add_size; + +size_t fst_break_size; +size_t fst_break_add_size; + +size_t fst_huge_break_size; + +fstHandle next_huge_break; }; @@ -603,7 +624,7 @@ fstWriterUint64(xc->handle, 0); /* +17 end time */ fstFwrite(&endtest, 8, 1, xc->handle); /* +25 endian test for reals */ #define FST_HDR_OFFS_MEM_USED (FST_HDR_OFFS_ENDIAN_TEST + 8) -fstWriterUint64(xc->handle, FST_BREAK_SIZE); /* +33 memory used by writer */ +fstWriterUint64(xc->handle, xc->fst_break_size);/* +33 memory used by writer */ #define FST_HDR_OFFS_NUM_SCOPES (FST_HDR_OFFS_MEM_USED + 8) fstWriterUint64(xc->handle, 0); /* +41 scope creation count */ @@ -631,7 +652,12 @@ time(&walltime); strcpy(dbuf, asctime(localtime(&walltime))); fstFwrite(dbuf, FST_HDR_DATE_SIZE, 1, xc->handle); /* +202 date */ -#define FST_HDR_LENGTH (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE) +/* date size is deliberately overspecified at 120 bytes in order to provide backfill for new args */ + +#define FST_HDR_OFFS_TIMEZERO (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE) +fstWriterUint64(xc->handle, xc->timezero); /* +322 timezero */ + +#define FST_HDR_LENGTH (FST_HDR_OFFS_TIMEZERO + 8) /* +330 next section starts here */ fflush(xc->handle); } @@ -703,6 +729,79 @@ xc->curval_mem = NULL; } +/* + * set up large and small memory usages + * crossover point in model is FST_ACTIVATE_HUGE_BREAK number of signals + */ +static void fstDetermineBreakSize(struct fstWriterContext *xc) +{ +#if defined(__linux__) || defined(FST_MACOSX) + +#ifdef __linux__ +FILE *f = fopen("/proc/meminfo", "rb"); +#else +FILE *f = popen("system_profiler", "r"); +#endif + +int was_set = 0; + +if(f) + { + char buf[257]; + char *s; + while(!feof(f)) + { + buf[0] = 0; + s = fgets(buf, 256, f); + if(s && *s) + { +#ifdef __linux__ + if(!strncmp(s, "MemTotal:", 9)) + { + size_t v = atol(s+10); + v *= 1024; /* convert to bytes */ +#else + if((s=strstr(s, "Memory:"))) + { + size_t v = atol(s+7); + v <<= 30; /* convert GB to bytes */ +#endif + + v /= 8; /* chop down to 1/8 physical memory */ + if(v > FST_BREAK_SIZE) + { + if(v > FST_BREAK_SIZE_MAX) + { + v = FST_BREAK_SIZE_MAX; + } + + xc->fst_huge_break_size = v; + was_set = 1; + break; + } + } + } + } + +#ifdef __linux__ + fclose(f); +#else + pclose(f); +#endif + } + +if(!was_set) +#endif + { + xc->fst_huge_break_size = FST_BREAK_SIZE; + } + +xc->fst_break_size = xc->fst_orig_break_size = FST_BREAK_SIZE; +xc->fst_break_add_size = xc->fst_orig_break_add_size = FST_BREAK_ADD_SIZE; +xc->next_huge_break = FST_ACTIVATE_HUGE_BREAK; +} + + /* * file creation and close */ @@ -711,6 +810,7 @@ void *fstWriterCreate(const char *nam, int use_compressed_hier) struct fstWriterContext *xc = calloc(1, sizeof(struct fstWriterContext)); xc->compress_hier = use_compressed_hier; +fstDetermineBreakSize(xc); if((!nam)||(!(xc->handle=unlink_fopen(nam, "w+b")))) { @@ -730,7 +830,7 @@ if((!nam)||(!(xc->handle=unlink_fopen(nam, "w+b")))) xc->valpos_handle = tmpfile(); /* .offs */ xc->curval_handle = tmpfile(); /* .bits */ xc->tchn_handle = tmpfile(); /* .tchn */ - xc->vchg_alloc_siz = FST_BREAK_SIZE + FST_BREAK_ADD_SIZE; + xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; xc->vchg_mem = malloc(xc->vchg_alloc_siz); free(hf); @@ -741,6 +841,11 @@ if((!nam)||(!(xc->handle=unlink_fopen(nam, "w+b")))) fstWriterEmitHdrBytes(xc); xc->nan = strtod("NaN", NULL); +#ifdef FST_WRITER_PARALLEL + pthread_mutex_init(&xc->mutex, NULL); + pthread_attr_init(&xc->thread_attr); + pthread_attr_setdetachstate(&xc->thread_attr, PTHREAD_CREATE_DETACHED); +#endif } else { @@ -778,6 +883,9 @@ if(xc) fputc(FST_BL_SKIP, xc->handle); /* temporarily tag the section, use FST_BL_VCDATA on finalize */ xc->section_start = ftello(xc->handle); +#ifdef FST_WRITER_PARALLEL + if(xc->xc_parent) xc->xc_parent->section_start = xc->section_start; +#endif xc->section_header_only = 1; /* indicates truncate might be needed */ fstWriterUint64(xc->handle, 0); /* placeholder = section length */ fstWriterUint64(xc->handle, xc->is_initial_time ? xc->firsttime : xc->curtime); /* begin time of section */ @@ -813,7 +921,11 @@ if(xc) * only to be called directly by fst code...otherwise must * be synced up with time changes */ +#ifdef FST_WRITER_PARALLEL +static void fstWriterFlushContextPrivate2(void *ctx) +#else static void fstWriterFlushContextPrivate(void *ctx) +#endif { #ifdef FST_DEBUG int cnt = 0; @@ -833,6 +945,11 @@ unsigned char *packmem; unsigned int packmemlen; uint32_t *vm4ip; struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +#ifdef FST_WRITER_PARALLEL +struct fstWriterContext *xc2 = xc->xc_parent; +#else +struct fstWriterContext *xc2 = xc; +#endif #ifndef FST_DYNAMIC_ALIAS_DISABLE Pvoid_t PJHSArray = (Pvoid_t) NULL; @@ -880,8 +997,9 @@ for(i=0;imaxhandle;i++) if(vm4ip[1] == 1) { wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ +#ifndef FST_REMOVE_DUPLICATE_VC xc->curval_mem[vm4ip[0]] = vchg_mem[offs + 4 + wrlen]; /* checkpoint variable */ - +#endif while(offs) { unsigned char val; @@ -941,8 +1059,9 @@ for(i=0;imaxhandle;i++) else { wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ +#ifndef FST_REMOVE_DUPLICATE_VC memcpy(xc->curval_mem + vm4ip[0], vchg_mem + offs + 4 + wrlen, vm4ip[1]); /* checkpoint variable */ - +#endif while(offs) { int idx; @@ -1137,7 +1256,7 @@ for(i=0;imaxhandle;i++) #endif } - vm4ip[3] = 0; + /* vm4ip[3] = 0; ...redundant with clearing below */ #ifdef FST_DEBUG cnt++; #endif @@ -1253,21 +1372,21 @@ fflush(xc->handle); fseeko(xc->handle, endpos, SEEK_SET); /* seek to end of file */ -xc->section_header_truncpos = endpos; /* cache in case of need to truncate */ +xc2->section_header_truncpos = endpos; /* cache in case of need to truncate */ if(xc->dump_size_limit) { if(endpos >= xc->dump_size_limit) { - xc->skip_writing_section_hdr = 1; - xc->size_limit_locked = 1; - xc->is_initial_time = 1; /* to trick emit value and emit time change */ + xc2->skip_writing_section_hdr = 1; + xc2->size_limit_locked = 1; + xc2->is_initial_time = 1; /* to trick emit value and emit time change */ #ifdef FST_DEBUG printf("<< dump file size limit reached, stopping dumping >>\n"); #endif } } -if(!xc->skip_writing_section_hdr) +if(!xc2->skip_writing_section_hdr) { fstWriterEmitSectionHeader(xc); /* emit next section header */ } @@ -1277,6 +1396,89 @@ xc->already_in_flush = 0; } +#ifdef FST_WRITER_PARALLEL +static void *fstWriterFlushContextPrivate1(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +fstWriterFlushContextPrivate2(xc); + +pthread_mutex_unlock(&(xc->xc_parent->mutex)); + +#ifdef FST_REMOVE_DUPLICATE_VC +free(xc->curval_mem); +#endif +free(xc->valpos_mem); +free(xc->vchg_mem); +fclose(xc->tchn_handle); +free(xc); + +return(NULL); +} + + +static void fstWriterFlushContextPrivate(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc->parallel_enabled) + { + struct fstWriterContext *xc2 = malloc(sizeof(struct fstWriterContext)); + int i; + + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); + + xc->xc_parent = xc; + memcpy(xc2, xc, sizeof(struct fstWriterContext)); + + xc2->valpos_mem = malloc(xc->maxhandle * 4 * sizeof(uint32_t)); + memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); + + /* curval mem is updated in the thread */ +#ifdef FST_REMOVE_DUPLICATE_VC + xc2->curval_mem = malloc(xc->maxvalpos); + memcpy(xc2->curval_mem, xc->curval_mem, xc->maxvalpos); +#endif + + xc->vchg_mem = malloc(xc->vchg_alloc_siz); + xc->vchg_mem[0] = '!'; + xc->vchg_siz = 1; + + for(i=0;imaxhandle;i++) + { + uint32_t *vm4ip = &(xc->valpos_mem[4*i]); + vm4ip[2] = 0; /* zero out offset val */ + vm4ip[3] = 0; /* zero out last time change val */ + } + + xc->tchn_cnt = xc->tchn_idx = 0; + xc->tchn_handle = tmpfile(); + fseeko(xc->tchn_handle, 0, SEEK_SET); + fstFtruncate(fileno(xc->tchn_handle), 0); + + xc->section_header_only = 0; + xc->secnum++; + + pthread_mutex_lock(&xc->mutex); + + pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2); + } + else + { + if(xc->parallel_was_enabled) /* conservatively block */ + { + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); + } + + xc->xc_parent = xc; + fstWriterFlushContextPrivate2(xc); + } +} +#endif + + /* * queues up a flush context operation */ @@ -1299,6 +1501,15 @@ if(xc) void fstWriterClose(void *ctx) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +#ifdef FST_WRITER_PARALLEL +if(xc) + { + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); + } +#endif + if(xc && !xc->already_in_close && !xc->already_in_flush) { unsigned char *tmem; @@ -1328,6 +1539,10 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) } } fstWriterFlushContextPrivate(xc); +#ifdef FST_WRITER_PARALLEL + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); +#endif } } fstDestroyMmaps(xc, 1); @@ -1556,6 +1771,11 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) } #endif +#ifdef FST_WRITER_PARALLEL + pthread_mutex_destroy(&xc->mutex); + pthread_attr_destroy(&xc->thread_attr); +#endif + free(xc->filename); xc->filename = NULL; free(xc); } @@ -1661,6 +1881,20 @@ if(xc && s) } +void fstWriterSetTimezero(void *ctx, int64_t tim) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + off_t fpos = ftello(xc->handle); + fseeko(xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET); + fstWriterUint64(xc->handle, (xc->timezero = tim)); + fflush(xc->handle); + fseeko(xc->handle, fpos, SEEK_SET); + } +} + + void fstWriterSetPackType(void *ctx, int typ) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; @@ -1681,6 +1915,24 @@ if(xc) } +void fstWriterSetParallelMode(void *ctx, int enable) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + xc->parallel_was_enabled |= xc->parallel_enabled; /* make sticky */ + xc->parallel_enabled = (enable != 0); +#ifndef FST_WRITER_PARALLEL + if(xc->parallel_enabled) + { + fprintf(stderr, "ERROR: fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n"); + exit(255); + } +#endif + } +} + + void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; @@ -1745,6 +1997,22 @@ if(xc && nam) if(aliasHandle > xc->maxhandle) aliasHandle = 0; xc->hier_file_len += fstWriterVarint(xc->hier_handle, aliasHandle); xc->numsigs++; + if(xc->numsigs == xc->next_huge_break) + { + if(xc->fst_break_size < xc->fst_huge_break_size) + { + xc->next_huge_break += FST_ACTIVATE_HUGE_INC; + xc->fst_break_size += xc->fst_orig_break_size; + xc->fst_break_add_size += xc->fst_orig_break_add_size; + + xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; + if(xc->vchg_mem) + { + xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); + } + } + } + if(!aliasHandle) { uint32_t zero = 0; @@ -1863,7 +2131,7 @@ if((xc) && (handle <= xc->maxhandle)) if((fpos + len + 10) > xc->vchg_alloc_siz) { - xc->vchg_alloc_siz += (FST_BREAK_ADD_SIZE + len); /* +len added in the case of extremely long vectors and small break add sizes */ + xc->vchg_alloc_siz += (xc->fst_break_add_size + len); /* +len added in the case of extremely long vectors and small break add sizes */ xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); if(!xc->vchg_mem) { @@ -1871,7 +2139,72 @@ if((xc) && (handle <= xc->maxhandle)) exit(255); } } +#ifdef FST_REMOVE_DUPLICATE_VC + offs = vm4ip[0]; + + if(len != 1) + { + if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2])) + { + unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */ + while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ } + memcpy(old_value, buf, len); /* overlay new value */ + memcpy(xc->curval_mem + offs, buf, len); + return; + } + else + { + if(!memcmp(xc->curval_mem + offs, buf, len)) + { + if(!xc->curtime) + { + int i; + for(i=0;icurval_mem + offs, buf, len); + } + else + { + if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2])) + { + unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */ + while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ } + *old_value = *buf; /* overlay new value */ + + *(xc->curval_mem + offs) = *buf; + return; + } + else + { + if((*(xc->curval_mem + offs)) == (*buf)) + { + if(!xc->curtime) + { + if(*buf != 'x') return; + } + else + { + return; + } + } + } + + *(xc->curval_mem + offs) = *buf; + } +#endif xc->vchg_siz += fstWriterUint32WithVarint32(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */ vm4ip[3] = xc->tchn_idx; vm4ip[2] = fpos; @@ -1912,7 +2245,7 @@ if((xc) && (handle <= xc->maxhandle)) if((fpos + len + 10 + 5) > xc->vchg_alloc_siz) { - xc->vchg_alloc_siz += (FST_BREAK_ADD_SIZE + len + 5); /* +len added in the case of extremely long vectors and small break add sizes */ + xc->vchg_alloc_siz += (xc->fst_break_add_size + len + 5); /* +len added in the case of extremely long vectors and small break add sizes */ xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); if(!xc->vchg_mem) { @@ -1964,7 +2297,7 @@ if(xc) } else { - if((xc->vchg_siz >= FST_BREAK_SIZE) || (xc->flush_context_pending)) + if((xc->vchg_siz >= xc->fst_break_size) || (xc->flush_context_pending)) { xc->flush_context_pending = 0; fstWriterFlushContextPrivate(xc); @@ -2044,9 +2377,6 @@ struct fstReaderContext /* common entries */ FILE *f, *fh; -#ifdef __MINGW32__ -char *fh_name; -#endif uint64_t start_time, end_time; uint64_t mem_used_by_writer; @@ -2071,6 +2401,7 @@ unsigned limit_range_valid : 1; /* valid for limit_range_start, limit_range_end char version[FST_HDR_SIM_VERSION_SIZE + 1]; char date[FST_HDR_DATE_SIZE + 1]; +int64_t timezero; char *filename, *filename_unpacked; off_t hier_pos; @@ -2410,6 +2741,12 @@ struct fstReaderContext *xc = (struct fstReaderContext *)ctx; return(xc ? xc->date : NULL); } +int64_t fstReaderGetTimezero(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->timezero : 0); +} + uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx) { @@ -2562,8 +2899,10 @@ if(!xc->fh) return(0); } +#ifndef __MINGW32__ xc->fh = fopen(fnam, "w+b"); if(!xc->fh) +#endif { xc->fh = tmpfile(); free(fnam); fnam = NULL; @@ -2599,12 +2938,7 @@ if(!xc->fh) } gzclose(zhandle); free(mem); - -#ifndef __MINGW32__ free(fnam); -#else - xc->fh_name = fnam; -#endif fseeko(xc->f, offs_cache, SEEK_SET); } @@ -2762,7 +3096,7 @@ char *pnt; int ch, scopetype; int vartype; uint32_t len, alias; -uint32_t maxvalpos=0; +/* uint32_t maxvalpos=0; */ int num_signal_dyn = 65536; if(!xc) return(0); @@ -2784,10 +3118,13 @@ if(fv) fprintf(fv, "$date\n\t%s\n$end\n", xc->date); fprintf(fv, "$version\n\t%s\n$end\n", xc->version); + if(xc->timezero) fprintf(fv, "$timezero\n\t%"PRId64"\n$end\n", xc->timezero); switch(xc->timescale) { - case 0: break; + case 2: time_scale = 100; time_dimension[0] = ' '; break; + case 1: time_scale = 10; + case 0: time_dimension[0] = ' '; break; case -1: time_scale = 100; time_dimension[0] = 'm'; break; case -2: time_scale = 10; @@ -2898,7 +3235,7 @@ while(!feof(xc->fh)) xc->signal_lens[xc->maxhandle] = len; xc->signal_typs[xc->maxhandle] = vartype; - maxvalpos+=len; + /* maxvalpos+=len; */ if(len > xc->longest_signal_value_len) { xc->longest_signal_value_len = len; @@ -3117,6 +3454,7 @@ if(gzread_pass_status) xc->version[FST_HDR_SIM_VERSION_SIZE] = 0; fstFread(xc->date, FST_HDR_DATE_SIZE, 1, xc->f); xc->date[FST_HDR_DATE_SIZE] = 0; + xc->timezero = fstReaderUint64(xc->f); } } else if((sectype == FST_BL_VCDATA) || (sectype == FST_BL_VCDATA_DYN_ALIAS)) @@ -3254,6 +3592,14 @@ return(hdr_seen); } +void *fstReaderOpenForUtilitiesOnly(void) +{ +struct fstReaderContext *xc = calloc(1, sizeof(struct fstReaderContext)); + +return(xc); +} + + void *fstReaderOpen(const char *nam) { struct fstReaderContext *xc = calloc(1, sizeof(struct fstReaderContext)); @@ -3333,14 +3679,7 @@ if(xc) if(xc->fh) { - fclose(xc->fh); xc->fh = NULL; -#ifdef __MINGW32__ - if(xc->fh_name) - { - unlink(xc->fh_name); - free(xc->fh_name); xc->fh_name = NULL; - } -#endif + fclose(xc->fh); xc->fh = NULL; } if(xc->f) @@ -3481,7 +3820,7 @@ for(;;) uint64_t tpval; int ti; - fseeko(xc->f, blkpos + seclen - 24, SEEK_SET); + if(fseeko(xc->f, blkpos + seclen - 24, SEEK_SET) != 0) break; tsec_uclen = fstReaderUint64(xc->f); tsec_clen = fstReaderUint64(xc->f); tsec_nitems = fstReaderUint64(xc->f); @@ -3489,7 +3828,9 @@ for(;;) printf("\ttime section unc: %d, com: %d (%d items)\n", (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems); #endif + if(tsec_clen > seclen) break; /* corrupted tsec_clen: by definition it can't be larger than size of section */ ucdata = malloc(tsec_uclen); + if(!ucdata) break; /* malloc fail as tsec_uclen out of range from corrupted file */ destlen = tsec_uclen; sourcelen = tsec_clen; @@ -5042,6 +5383,7 @@ int fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len) { unsigned char *src = s; unsigned char *dst = d; +unsigned char val; int i; for(i=0;inumfacs)) lt->sorted_facs[i]->facnum = i; } - lt->facname_offset=lt->position; + if(!lt->timezero) + { + lxt2_wr_emit_u32(lt, lt->numfacs); /* uncompressed */ + } + else + { + lxt2_wr_emit_u32(lt, 0); /* uncompressed, flag to insert extra parameters */ + lxt2_wr_emit_u32(lt, 8); /* uncompressed 8 counts timezero and on */ + lxt2_wr_emit_u32(lt, lt->numfacs); /* uncompressed */ + lxt2_wr_emit_u64(lt, (lt->timezero >> 32) & 0xffffffffL, lt->timezero & 0xffffffffL); /* uncompressed */ + } + - lxt2_wr_emit_u32(lt, lt->numfacs); /* uncompressed */ lxt2_wr_emit_u32(lt, lt->numfacbytes); /* uncompressed */ lxt2_wr_emit_u32(lt, lt->longestname); /* uncompressed */ + + lt->facname_offset=lt->position; + lxt2_wr_emit_u32(lt, 0); /* uncompressed : placeholder for zfacnamesize */ lxt2_wr_emit_u32(lt, 0); /* uncompressed : placeholder for zfacname_predec_size */ lxt2_wr_emit_u32(lt, 0); /* uncompressed : placeholder for zfacgeometrysize */ @@ -720,7 +733,7 @@ if((lt)&&(lt->numfacs)) lt->break_header_size = lt->position; /* in case we need to emit multiple lxt2s with same header */ lt->zfacgeometry_size = lt->position - lt->facgeometry_offset; - fseeko(lt->handle, lt->facname_offset + 12, SEEK_SET); + fseeko(lt->handle, lt->facname_offset, SEEK_SET); lxt2_wr_emit_u32(lt, lt->zfacname_size); /* backpatch sizes... */ lxt2_wr_emit_u32(lt, lt->zfacname_predec_size); lxt2_wr_emit_u32(lt, lt->zfacgeometry_size); @@ -2174,7 +2187,19 @@ void lxt2_wr_set_compression_depth(struct lxt2_wr_trace *lt, unsigned int depth) if(lt) { if(depth > 9) depth = 9; - sprintf(lt->zmode, "wb%d", depth); + sprintf(lt->zmode, "wb%u", depth); } } + +/* + * time zero offset + */ +void lxt2_wr_set_timezero(struct lxt2_wr_trace *lt, lxtstime_t timeval) +{ +if(lt) + { + lt->timezero = timeval; + } +} + diff --git a/vpi/lxt2_write.h b/vpi/lxt2_write.h index cd27ca662..f1487fb34 100644 --- a/vpi/lxt2_write.h +++ b/vpi/lxt2_write.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Tony Bybell. + * Copyright (c) 2003-2012 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -60,6 +60,7 @@ extern "C" { #define LXT2_WR_SYMPRIME 500009 typedef uint64_t lxttime_t; +typedef int64_t lxtstime_t; #ifndef _MSC_VER @@ -170,6 +171,7 @@ int numsections, numblock; off_t facname_offset, facgeometry_offset; lxttime_t mintime, maxtime; +lxtstime_t timezero; unsigned int timegranule; int timescale; int timepos; @@ -291,6 +293,7 @@ void lxt2_wr_set_maxgranule(struct lxt2_wr_trace *lt, unsigned int maxgranule /* time ops */ void lxt2_wr_set_timescale(struct lxt2_wr_trace *lt, int timescale); +void lxt2_wr_set_timezero(struct lxt2_wr_trace *lt, lxtstime_t timeval); int lxt2_wr_set_time(struct lxt2_wr_trace *lt, unsigned int timeval); int lxt2_wr_inc_time_by_delta(struct lxt2_wr_trace *lt, unsigned int timeval); int lxt2_wr_set_time64(struct lxt2_wr_trace *lt, lxttime_t timeval); diff --git a/vpi/lxt_write.c b/vpi/lxt_write.c index 42b452268..9e9cf2ea9 100644 --- a/vpi/lxt_write.c +++ b/vpi/lxt_write.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-9 Tony Bybell. + * Copyright (c) 2001-2012 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -1208,6 +1208,12 @@ if(lt) lt->dumpoffcount = 0; } + if(lt->timezero) + { + lt->timezero_offset = lt->position; + lt_emit_u64(lt, (int)((lt->timezero)>>32), (int)lt->timezero); + } + /* prefix */ lt_emit_u8(lt, LT_SECTION_END); @@ -1237,6 +1243,9 @@ if(lt) /* Version 5 adds */ if(lt->exclude_offset) { lt_emit_u32(lt, lt->exclude_offset); lt_emit_u8(lt, LT_SECTION_EXCLUDE_TABLE); lt->exclude_offset = 0; } + /* Version 6 adds */ + if(lt->timezero_offset) { lt_emit_u32(lt, lt->timezero_offset); lt_emit_u8(lt, LT_SECTION_TIMEZERO); lt->timezero_offset = 0; } + /* suffix */ lt_emit_u8(lt, LT_TRLID); @@ -2808,3 +2817,11 @@ if((lt)&&(lt->dumpoff_active)) } } +void lt_set_timezero(struct lt_trace *lt, lxtotime_t timeval) +{ +if(lt) + { + lt->timezero = timeval; + } +} + diff --git a/vpi/lxt_write.h b/vpi/lxt_write.h index f029b7b4e..8fbb0a797 100644 --- a/vpi/lxt_write.h +++ b/vpi/lxt_write.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-3 Tony Bybell. + * Copyright (c) 2001-2012 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -72,9 +72,11 @@ enum lt_zmode_types { LT_ZMODE_NONE, LT_ZMODE_GZIP, LT_ZMODE_BZIP2 }; #ifndef _MSC_VER typedef uint64_t lxttime_t; #define ULLDescriptor(x) x##ULL +typedef int64_t lxtotime_t; #else typedef unsigned __int64 lxttime_t; #define ULLDescriptor(x) x##i64 +typedef __int64 lxtotime_t; #endif @@ -108,6 +110,7 @@ unsigned int position; #define LT_SECTION_ZDICTIONARY (17) #define LT_SECTION_ZDICTIONARY_SIZE (18) #define LT_SECTION_EXCLUDE_TABLE (19) +#define LT_SECTION_TIMEZERO (20) struct lt_trace { @@ -164,11 +167,13 @@ unsigned int timescale_offset; unsigned int double_test_offset; unsigned int dictionary_offset; unsigned int exclude_offset; +unsigned int timezero_offset; char *compress_fac_str; int compress_fac_len; lxttime_t timeval; /* for clock induction, current time */ +lxtotime_t timezero; /* for allowing negative values */ unsigned dumpoff_active : 1; /* when set we're not dumping */ unsigned double_used : 1; @@ -234,6 +239,7 @@ void lt_set_clock_compress(struct lt_trace *lt); void lt_set_dict_compress(struct lt_trace *lt, unsigned int minwidth); void lt_set_initial_value(struct lt_trace *lt, char value); void lt_set_timescale(struct lt_trace *lt, int timescale); +void lt_set_timezero(struct lt_trace *lt, lxtotime_t timeval); int lt_set_time(struct lt_trace *lt, unsigned int timeval); int lt_inc_time_by_delta(struct lt_trace *lt, unsigned int timeval); diff --git a/vpi/mt19937int.c b/vpi/mt19937int.c index 8e057af63..ef480c690 100644 --- a/vpi/mt19937int.c +++ b/vpi/mt19937int.c @@ -31,8 +31,8 @@ /* See the GNU Library General Public License for more details. */ /* You should have received a copy of the GNU Library General */ /* Public License along with this library; if not, write to the */ -/* Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ -/* 02111-1307 USA */ +/* Free Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, */ +/* MA 02110-1301, USA */ /* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ /* When you use this, send an email to: matumoto@math.keio.ac.jp */ diff --git a/vpi/sdf_lexor.lex b/vpi/sdf_lexor.lex index 0a1210dbb..523550db9 100644 --- a/vpi/sdf_lexor.lex +++ b/vpi/sdf_lexor.lex @@ -20,7 +20,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sdf_priv.h" diff --git a/vpi/sdf_parse.y b/vpi/sdf_parse.y index 8901f241d..793ad120c 100644 --- a/vpi/sdf_parse.y +++ b/vpi/sdf_parse.y @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ extern int sdflex(void); @@ -127,7 +127,7 @@ vendor sdf_parse_path, @2.first_line, $3); free($3); } -; + ; program_name : '(' K_PROGRAM QSTRING ')' diff --git a/vpi/sdf_parse_priv.h b/vpi/sdf_parse_priv.h index bc2751ce1..325071270 100644 --- a/vpi/sdf_parse_priv.h +++ b/vpi/sdf_parse_priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/vpi/sdf_priv.h b/vpi/sdf_priv.h index 98289ae9d..ceec94af8 100644 --- a/vpi/sdf_priv.h +++ b/vpi/sdf_priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/vpi/stringheap.c b/vpi/stringheap.c index 2b419965a..e44a72338 100644 --- a/vpi/stringheap.c +++ b/vpi/stringheap.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/stringheap.h b/vpi/stringheap.h index 2c383d124..af34522d9 100644 --- a/vpi/stringheap.h +++ b/vpi/stringheap.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ struct stringheap_cell; diff --git a/vpi/sys_convert.c b/vpi/sys_convert.c index 88cf7292c..1982ab3ed 100644 --- a/vpi/sys_convert.c +++ b/vpi/sys_convert.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/sys_countdrivers.c b/vpi/sys_countdrivers.c new file mode 100644 index 000000000..304672ec8 --- /dev/null +++ b/vpi/sys_countdrivers.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2012 Martin Whitaker. (icarus@martin-whitaker.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 + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "sys_priv.h" +#include +#include +#include +#include "ivl_alloc.h" + +/* + * Check to see if an argument is a single bit net. + */ +static void check_net_arg(vpiHandle arg, vpiHandle callh, const char *name) +{ + assert(arg); + + switch (vpi_get(vpiType, arg)) { + case vpiPartSelect: + if (vpi_get(vpiType, vpi_handle(vpiParent, arg)) != vpiNet) + break; + case vpiNet: + if (vpi_get(vpiSize, arg) != 1) + break; + return; + default: + break; + } + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's first argument must be a scalar net or " + "a bit-select of a vector net.\n", name); + vpi_control(vpiFinish, 1); +} + +/* + * Check to see if an argument is a variable. + */ +static void check_var_arg(vpiHandle arg, vpiHandle callh, const char *name, + const char *arg_name) +{ + assert(arg); + + switch (vpi_get(vpiType, arg)) { + case vpiPartSelect: + if (vpi_get(vpiType, vpi_handle(vpiParent, arg)) == vpiNet) + break; + case vpiMemoryWord: + case vpiBitVar: + case vpiReg: + case vpiIntegerVar: + case vpiIntVar: + case vpiLongIntVar: + case vpiTimeVar: + return; + default: + break; + } + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's %s argument must be a variable.\n", + name, arg_name); + vpi_control(vpiFinish, 1); +} + +/* + * Check that the given $countdrivers() call has valid arguments. + */ +static PLI_INT32 sys_countdrivers_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + unsigned arg_num; + + /* Check that there are arguments. */ + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least one argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + /* The first argument must be a scalar net or a net bit select. */ + arg = vpi_scan(argv); + check_net_arg(arg, callh, name); + + /* The optional arguments must be variables. */ + for (arg_num = 2; arg_num < 7; arg_num += 1) { + char *arg_name = NULL; + switch (arg_num) { + case 2: arg_name = "second"; break; + case 3: arg_name = "third"; break; + case 4: arg_name = "fourth"; break; + case 5: arg_name = "fifth"; break; + case 6: arg_name = "sixth"; break; + default: assert(0); + } + + arg = vpi_scan(argv); + if (arg == 0) + return 0; + + check_var_arg(arg, callh, name, arg_name); + } + + /* Make sure there are no extra arguments. */ + check_for_extra_args(argv, callh, name, "six arguments", 0); + return 0; +} + +/* + * The runtime code for $countdrivers(). + */ +static PLI_INT32 sys_countdrivers_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + unsigned idx; + unsigned counts[4]; + unsigned num_drivers; + s_vpi_value val; + + /* All returned values are integers. */ + val.format = vpiIntVal; + + /* Get the base net reference and bit select */ + idx = 0; + arg = vpi_scan(argv); + assert(arg); + if (vpi_get(vpiType, arg) == vpiPartSelect) { + idx = vpi_get(vpiLeftRange, arg); + arg = vpi_handle(vpiParent, arg); + assert(arg); + } + + /* Get the net driver counts from the runtime. */ + vpip_count_drivers(arg, idx, counts); + num_drivers = counts[0] + counts[1] + counts[2]; + + /* Handle optional net_is_forced argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = counts[3]; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Handle optional number_of_01x_drivers argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = num_drivers; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Handle optional number_of_0_drivers argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = counts[0]; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Handle optional number_of_1_drivers argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = counts[1]; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Handle optional number_of_x_drivers argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = counts[2]; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Free the argument iterator. */ + vpi_free_object(argv); + +args_done: + val.value.integer = (num_drivers > 1) ? 1 : 0; + vpi_put_value(callh, &val, 0, vpiNoDelay); + return 0; +} + +/* + * Routine to register the system tasks/functions provided in this file. + */ +void sys_countdrivers_register() +{ + s_vpi_systf_data tf_data; + vpiHandle res; + + tf_data.type = vpiSysFunc; + tf_data.tfname = "$countdrivers"; + tf_data.calltf = sys_countdrivers_calltf; + tf_data.compiletf = sys_countdrivers_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$countdrivers"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); +} diff --git a/vpi/sys_darray.c b/vpi/sys_darray.c new file mode 100644 index 000000000..3031252a3 --- /dev/null +++ b/vpi/sys_darray.c @@ -0,0 +1,91 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +# include "sys_priv.h" +# include + +static PLI_INT32 one_darray_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires a string argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if (arg == 0) return 0; + + arg = vpi_scan(argv); + if (arg != 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s has too many arguments.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + return 0; +} + +static PLI_INT32 size_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + assert(argv); + arg = vpi_scan(argv); + assert(arg); + vpi_free_object(argv); + + int res = vpi_get(vpiSize, arg); + + s_vpi_value value; + value.format = vpiIntVal; + value.value.integer = res; + + vpi_put_value(callh, &value, 0, vpiNoDelay); + + return 0; +} + +void sys_darray_register(void) +{ + s_vpi_systf_data tf_data; + vpiHandle res; + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.tfname = "$ivl_darray_method$size"; + tf_data.calltf = size_calltf; + tf_data.compiletf = one_darray_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$ivl_darray_method$size"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); +} diff --git a/vpi/sys_deposit.c b/vpi/sys_deposit.c index 74eae09d2..f2f95f562 100644 --- a/vpi/sys_deposit.c +++ b/vpi/sys_deposit.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/sys_display.c b/vpi/sys_display.c index d5fdb4234..9151051d9 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" @@ -964,6 +964,18 @@ static char *get_display(unsigned int *rtnsz, const struct strobe_cb_info *info) memcpy(rtn+size-1, buf, width); break; + /* Process string variables like string constants: interpret + the contained strings like format strings. */ + case vpiStringVar: + value.format = vpiStringVal; + vpi_get_value(item, &value); + fmt = strdup(value.value.str); + width = get_format(&result, fmt, info, &idx); + free(fmt); + rtn = realloc(rtn, (size+width)*sizeof(char)); + memcpy(rtn+size-1, result, width); + break; + case vpiSysFuncCall: func_name = vpi_get_str(vpiName, item); if (strcmp(func_name, "$time") == 0) { @@ -1071,6 +1083,7 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8*name, case vpiLongIntVar: case vpiTimeVar: case vpiRealVar: + case vpiStringVar: case vpiSysFuncCall: break; @@ -1218,7 +1231,7 @@ static PLI_INT32 strobe_cb(p_cb_data cb) * Which has the same basic effect. */ if ((! IS_MCD(info->fd_mcd) && vpi_get_file(info->fd_mcd) != NULL) || ( IS_MCD(info->fd_mcd) && my_mcd_printf(info->fd_mcd, "") != EOF)) { - char* result = NULL; + char* result; unsigned int size, location=0; /* Because %u and %z may put embedded NULL characters into the * returned string strlen() may not match the real size! */ diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index 667d78fef..5feaa6699 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" @@ -252,7 +252,6 @@ static PLI_INT32 sys_fflush_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpiHandle arg; s_vpi_value val; PLI_UINT32 fd_mcd; - FILE *fp; errno = 0; /* If we have no argument then flush all the streams. */ @@ -286,7 +285,7 @@ static PLI_INT32 sys_fflush_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpi_mcd_flush(fd_mcd); } else { /* If we have a valid file descriptor flush the file. */ - fp = vpi_get_file(fd_mcd); + FILE *fp = vpi_get_file(fd_mcd); if (fp) fflush(fp); } diff --git a/vpi/sys_finish.c b/vpi/sys_finish.c index 56489c05a..642765621 100644 --- a/vpi/sys_finish.c +++ b/vpi/sys_finish.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sys_priv.h" diff --git a/vpi/sys_fst.c b/vpi/sys_fst.c index 228e4ea04..67fcce1d9 100644 --- a/vpi/sys_fst.c +++ b/vpi/sys_fst.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/sys_icarus.c b/vpi/sys_icarus.c index d80a67074..40d8c52e3 100644 --- a/vpi/sys_icarus.c +++ b/vpi/sys_icarus.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2008-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 @@ -301,11 +301,6 @@ void sys_special_register(void) tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; - tf_data.tfname = "$countdrivers"; - tf_data.user_data = "$countdrivers"; - res = vpi_register_systf(&tf_data); - vpip_make_systf_system_defined(res); - tf_data.tfname = "$getpattern"; tf_data.user_data = "$getpattern"; res = vpi_register_systf(&tf_data); diff --git a/vpi/sys_lxt.c b/vpi/sys_lxt.c index 151c058ec..19785944f 100644 --- a/vpi/sys_lxt.c +++ b/vpi/sys_lxt.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* The sys_priv.h include must be before the lxt_write.h include! */ diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index bfd30fd5f..57e0550ca 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* The sys_priv.h include must be before the lxt2_write.h include! */ diff --git a/vpi/sys_plusargs.c b/vpi/sys_plusargs.c index f1d5e23f3..7f7935aee 100644 --- a/vpi/sys_plusargs.c +++ b/vpi/sys_plusargs.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/sys_priv.c b/vpi/sys_priv.c index f14d5f285..cc9bd79ff 100644 --- a/vpi/sys_priv.c +++ b/vpi/sys_priv.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sys_priv.h" diff --git a/vpi/sys_priv.h b/vpi/sys_priv.h index f384cdef7..ce08ba573 100644 --- a/vpi/sys_priv.h +++ b/vpi/sys_priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "vpi_config.h" diff --git a/vpi/sys_random.c b/vpi/sys_random.c index 3300f5fbb..3bc6e8989 100644 --- a/vpi/sys_random.c +++ b/vpi/sys_random.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/sys_random.h b/vpi/sys_random.h index b03bb3a11..90511702c 100644 --- a/vpi/sys_random.h +++ b/vpi/sys_random.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/vpi/sys_random_mti.c b/vpi/sys_random_mti.c index 14f9e1f68..58753ac85 100644 --- a/vpi/sys_random_mti.c +++ b/vpi/sys_random_mti.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/sys_readmem.c b/vpi/sys_readmem.c index 6766abda4..b35154a03 100644 --- a/vpi/sys_readmem.c +++ b/vpi/sys_readmem.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/sys_readmem_lex.h b/vpi/sys_readmem_lex.h index 2083739d5..c638ec6d6 100644 --- a/vpi/sys_readmem_lex.h +++ b/vpi/sys_readmem_lex.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include diff --git a/vpi/sys_readmem_lex.lex b/vpi/sys_readmem_lex.lex index 6cf029c04..c7b90f9ba 100644 --- a/vpi/sys_readmem_lex.lex +++ b/vpi/sys_readmem_lex.lex @@ -19,7 +19,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_readmem_lex.h" diff --git a/vpi/sys_scanf.c b/vpi/sys_scanf.c index 0bca2c5f8..d4b45bab3 100644 --- a/vpi/sys_scanf.c +++ b/vpi/sys_scanf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2011 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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* round() is ISO C99 from math.h. This define should enable it. */ @@ -241,7 +241,7 @@ static int scan_format_float(vpiHandle callh, vpiHandle argv, if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s() ran out of variables for %%%c format code", + vpi_printf("%s() ran out of variables for %%%c format code.", name, code); vpi_control(vpiFinish, 1); return 0; @@ -307,7 +307,7 @@ static int scan_format_float_time(vpiHandle callh, vpiHandle argv, if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s() ran out of variables for %%t format code", name); + vpi_printf("%s() ran out of variables for %%t format code.", name); vpi_control(vpiFinish, 1); return 0; } @@ -383,7 +383,7 @@ static int scan_format_base(vpiHandle callh, vpiHandle argv, if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s() ran out of variables for %%%c format code", + vpi_printf("%s() ran out of variables for %%%c format code.", name, code); vpi_control(vpiFinish, 1); free(strval); @@ -443,7 +443,7 @@ static int scan_format_char(vpiHandle callh, vpiHandle argv, if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s() ran out of variables for %%c format code", name); + vpi_printf("%s() ran out of variables for %%c format code.", name); vpi_control(vpiFinish, 1); return 0; } @@ -563,7 +563,7 @@ static int scan_format_decimal(vpiHandle callh, vpiHandle argv, if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s() ran out of variables for %%d format code", name); + vpi_printf("%s() ran out of variables for %%d format code.", name); vpi_control(vpiFinish, 1); free(strval); return 0; @@ -622,7 +622,7 @@ static int scan_format_module_path(vpiHandle callh, vpiHandle argv, if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s() ran out of variables for %%m format code", name); + vpi_printf("%s() ran out of variables for %%m format code.", name); vpi_control(vpiFinish, 1); return 0; } @@ -701,7 +701,7 @@ static int scan_format_string(vpiHandle callh, vpiHandle argv, if (! arg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s() ran out of variables for %%s format code", name); + vpi_printf("%s() ran out of variables for %%s format code.", name); vpi_control(vpiFinish, 1); free(strval); return 0; @@ -717,6 +717,284 @@ static int scan_format_string(vpiHandle callh, vpiHandle argv, return 1; } +/* + * Routine to return a two state value (implements %u). + * + * Note: Since this is a binary routine it also does not check for leading + * space characters or use space as a boundary character. + * + * Return: 1 for a match, 0 for no match/variable and -1 for a + * suppressed match. No variable is fatal. + */ +static int scan_format_two_state(vpiHandle callh, vpiHandle argv, + struct byte_source *src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name) +{ + vpiHandle arg; + p_vpi_vecval val_ptr; + s_vpi_value val; + unsigned words, word; + PLI_INT32 varlen; + + /* If we are being asked for no data then return a match fail. */ + if (width == 0) return 0; + + /* Since this is a binary format we do not have an ending sequence. + * Consequently we need to use the width to determine how many word + * pairs to remove from the input stream. */ + if (suppress_flag) { + /* If no width was given then just remove one word pair. */ + if (width == UINT_MAX) words = 1; + else words = (width+31)/32; + for (word = 0; word < words; word += 1) { + unsigned byte; + /* For a suppression we do not care about the endian order + * of the bytes. */ + for (byte = 0; byte < 4; byte += 1) { + int ch = byte_getc(src); + /* See the EOF comments below for more details. */ + if (ch == EOF) { + vpi_printf("WARNING: %s:%d: ", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() only found %u of %u bytes " + "needed by %%u format code.\n", name, + word*4U + byte, words*4U); + return 0; + } + } + } + return -1; + } + + /* We must have a variable to put the bits into. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() ran out of variables for %%u format code.", name); + vpi_control(vpiFinish, 1); + return 0; + } + + /* Extract either the given number of word pairs or enough to fill + * the variable. */ + varlen = (vpi_get(vpiSize, arg)+31)/32; + assert(varlen > 0); + val_ptr = (p_vpi_vecval) malloc(varlen*sizeof(s_vpi_vecval)); + if (width == UINT_MAX) words = (unsigned)varlen; + else words = (width+31)/32; + for (word = 0; word < words; word += 1) { + int byte; + PLI_INT32 bits = 0; +#ifdef WORDS_BIGENDIAN + for (byte = 3; byte >= 0; byte -= 1) { +#else + for (byte = 0; byte <= 3; byte += 1) { +#endif + int ch = byte_getc(src); + /* If there is an EOF while reading the bytes then treat + * that as a non-match. It could be argued that the bytes + * should be put back, but that is not practical and since + * a binary read should be treated as an atomic operation + * it's not helpful either. An EOF while reading is an + * error in the data stream so print a message to help the + * user debug what is going wrong. The calling routine has + * already verified that there is at least one byte + * available so this message is not printed when an EOF + * occurs at a format code boundary. Which may not be an + * error in the data stream. */ + if (ch == EOF) { + vpi_printf("WARNING: %s:%d: ", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() only found %d of %u bytes needed by " + "%%u format code.\n", name, word*4 + +#ifdef WORDS_BIGENDIAN + (3-byte), +#else + byte, +#endif + words*4U); + free(val_ptr); + return 0; + } + bits |= (ch & 0xff) << byte*8; + } + /* Only save the words that are in range. */ + if (word < (unsigned)varlen) { + val_ptr[word].aval = bits; + val_ptr[word].bval = 0; + } + } + + /* Mask the upper bits to match the specified width when required. */ + if (width != UINT_MAX) { + PLI_INT32 mask = UINT32_MAX >> (32U - ((width - 1U) % 32U + 1U)); + val_ptr[words-1].aval &= mask; + } + + /* Not enough words were read to fill the variable so zero fill the + * upper words. */ + if (words < (unsigned)varlen) { + for (word = words; word < varlen ; word += 1) { + val_ptr[word].aval = 0; + val_ptr[word].bval = 0; + } + } + + /* Put the two-state value into the variable. */ + val.format = vpiVectorVal; + val.value.vector = val_ptr; + vpi_put_value(arg, &val, 0, vpiNoDelay); + free(val_ptr); + + /* One variable was consumed. */ + return 1; +} + + +/* + * Routine to return a four state value (implements %z). + * + * Note: Since this is a binary routine it also does not check for leading + * space characters or use space as a boundary character. + * + * Return: 1 for a match, 0 for no match/variable and -1 for a + * suppressed match. No variable is fatal. + */ +static int scan_format_four_state(vpiHandle callh, vpiHandle argv, + struct byte_source *src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name) +{ + vpiHandle arg; + p_vpi_vecval val_ptr; + s_vpi_value val; + unsigned words, word; + PLI_INT32 varlen; + + /* If we are being asked for no data then return a match fail. */ + if (width == 0) return 0; + + /* Since this is a binary format we do not have an ending sequence. + * Consequently we need to use the width to determine how many word + * pairs to remove from the input stream. */ + if (suppress_flag) { + /* If no width was given then just remove one word pair. */ + if (width == UINT_MAX) words = 1; + else words = (width+31)/32; + for (word = 0; word < words; word += 1) { + unsigned byte; + /* For a suppression we do not care about the endian order + * of the bytes. */ + for (byte = 0; byte < 8; byte += 1) { + int ch = byte_getc(src); + /* See the EOF comments below for more details. */ + if (ch == EOF) { + vpi_printf("WARNING: %s:%d: ", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() only found %u of %u bytes " + "needed by %%z format code.\n", name, + word*8U + byte, words*8U); + return 0; + } + } + } + return -1; + } + + /* We must have a variable to put the bits into. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() ran out of variables for %%z format code.", name); + vpi_control(vpiFinish, 1); + return 0; + } + + /* Extract either the given number of word pairs or enough to fill + * the variable. */ + varlen = (vpi_get(vpiSize, arg)+31)/32; + assert(varlen > 0); + val_ptr = (p_vpi_vecval) malloc(varlen*sizeof(s_vpi_vecval)); + if (width == UINT_MAX) words = (unsigned)varlen; + else words = (width+31)/32; + for (word = 0; word < words; word += 1) { + unsigned elem; + for (elem = 0; elem < 2; elem += 1) { + int byte; + PLI_INT32 bits = 0; +#ifdef WORDS_BIGENDIAN + for (byte = 3; byte >= 0; byte -= 1) { +#else + for (byte = 0; byte <= 3; byte += 1) { +#endif + int ch = byte_getc(src); + /* If there is an EOF while reading the bytes then + * treat that as a non-match. It could be argued that + * the bytes should be put back, but that is not + * practical and since a binary read should be + * treated as an atomic operation it's not helpful + * either. An EOF while reading is an error in the + * data stream so print a message to help the user + * debug what is going wrong. The calling routine has + * already verified that there is at least one byte + * available so this message is not printed when an + * EOF occurs at a format code boundary. Which may + * not be an error in the data stream. */ + if (ch == EOF) { + vpi_printf("WARNING: %s:%d: ", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() only found %d of %u bytes " + "needed by %%z format code.\n", name, + word*8 + elem*4 + +#ifdef WORDS_BIGENDIAN + (3-byte), +#else + byte, +#endif + words*8U); + free(val_ptr); + return 0; + } + bits |= (ch & 0xff) << byte*8; + } + /* Only save the words that are in range. */ + if (word < (unsigned)varlen) { + *(&val_ptr[word].aval+elem) = bits; + } + } + } + + /* Mask the upper bits to match the specified width when required. */ + if (width != UINT_MAX) { + PLI_INT32 mask = UINT32_MAX >> (32U - ((width - 1U) % 32U + 1U)); + val_ptr[words-1].aval &= mask; + val_ptr[words-1].bval &= mask; + } + + /* Not enough words were read to fill the variable so zero fill the + * upper words. */ + if (words < (unsigned)varlen) { + for (word = words; word < varlen ; word += 1) { + val_ptr[word].aval = 0; + val_ptr[word].bval = 0; + } + } + + /* Put the four-state value into the variable. */ + val.format = vpiVectorVal; + val.value.vector = val_ptr; + vpi_put_value(arg, &val, 0, vpiNoDelay); + free(val_ptr); + + /* One variable was consumed. */ + return 1; +} + /* * The $fscanf and $sscanf functions are the same except for the first * argument, which is the source. The wrapper functions below peel off @@ -743,8 +1021,6 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv, * found just return EOF. */ len = vpi_get(vpiSize, item); words = ((len + 31) / 32) - 1; - /* The mask is defined to be 32 bits. */ - mask = 0xffffffff >> (32 - ((len - 1) % 32 + 1)); val.format = vpiVectorVal; vpi_get_value(item, &val); /* Check the full words for an undefined bit. */ @@ -755,6 +1031,8 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv, break; } } + /* The mask is defined to be 32 bits. */ + mask = UINT32_MAX >> (32U - ((len - 1U) % 32U + 1U)); /* Check the top word for an undefined bit. */ if (match && (val.value.vector[words].bval & mask)) { match = 0; @@ -906,8 +1184,16 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv, break; case 'u': + match = scan_format_two_state(callh, argv, src, + max_width, + suppress_flag, name); + /* If a binary match fails and it is the first item + * matched then treat that as an EOF. */ + if ((match == 0) && (rc == 0)) rc = EOF; + if (match == 1) rc += 1; + break; + case 'v': - case 'z': vpi_printf("SORRY: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -916,6 +1202,16 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv, vpi_control(vpiFinish, 1); break; + case 'z': + match = scan_format_four_state(callh, argv, src, + max_width, + suppress_flag, name); + /* If a binary match fails and it is the first item + * matched then treat that as an EOF. */ + if ((match == 0) && (rc == 0)) rc = EOF; + if (match == 1) rc += 1; + break; + default: vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 37465a913..506446912 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/sys_string.c b/vpi/sys_string.c new file mode 100644 index 000000000..88d2379ca --- /dev/null +++ b/vpi/sys_string.c @@ -0,0 +1,90 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "sys_priv.h" +# include + +static PLI_INT32 one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires a string argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + if (arg == 0) return 0; + + arg = vpi_scan(argv); + if (arg != 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s has too many arguments.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + return 0; +} + +static PLI_INT32 len_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + assert(argv); + arg = vpi_scan(argv); + assert(arg); + vpi_free_object(argv); + + int res = vpi_get(vpiSize, arg); + + s_vpi_value value; + value.format = vpiIntVal; + value.value.integer = res; + + vpi_put_value(callh, &value, 0, vpiNoDelay); + + return 0; +} + +void sys_string_register(void) +{ + s_vpi_systf_data tf_data; + vpiHandle res; + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.tfname = "$ivl_string_method$len"; + tf_data.calltf = len_calltf; + tf_data.compiletf = one_string_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$ivl_string_method$len"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); +} diff --git a/vpi/sys_table.c b/vpi/sys_table.c index 8a7dabffe..0eef9ddf2 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-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 @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vpi_config.h" @@ -24,6 +24,8 @@ # include extern void sys_convert_register(); +extern void sys_countdrivers_register(); +extern void sys_darray_register(); extern void sys_fileio_register(); extern void sys_finish_register(); extern void sys_deposit_register(); @@ -33,6 +35,7 @@ extern void sys_queue_register(); extern void sys_random_register(); extern void sys_random_mti_register(); extern void sys_readmem_register(); +extern void sys_string_register(); extern void sys_scanf_register(); extern void sys_sdf_register(); extern void sys_time_register(); @@ -195,6 +198,8 @@ static void sys_lxt_or_vcd_register() void (*vlog_startup_routines[])() = { sys_convert_register, + sys_countdrivers_register, + sys_darray_register, sys_fileio_register, sys_finish_register, sys_deposit_register, @@ -205,6 +210,7 @@ void (*vlog_startup_routines[])() = { sys_random_mti_register, sys_readmem_register, sys_scanf_register, + sys_string_register, sys_time_register, sys_lxt_or_vcd_register, sys_sdf_register, diff --git a/vpi/sys_time.c b/vpi/sys_time.c index 07e5560f8..e904d2718 100644 --- a/vpi/sys_time.c +++ b/vpi/sys_time.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sys_priv.h" diff --git a/vpi/sys_vcd.c b/vpi/sys_vcd.c index 22ba24621..85b6739d4 100644 --- a/vpi/sys_vcd.c +++ b/vpi/sys_vcd.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/sys_vcdoff.c b/vpi/sys_vcdoff.c index 96d41321f..1ce71f709 100644 --- a/vpi/sys_vcdoff.c +++ b/vpi/sys_vcdoff.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" diff --git a/vpi/system.sft b/vpi/system.sft index 0b43b1c65..2e65eade3 100644 --- a/vpi/system.sft +++ b/vpi/system.sft @@ -21,3 +21,5 @@ $abstime vpiSysFuncReal $simparam vpiSysFuncReal $simparam$str vpiSysFuncSized 1024 unsigned $table_model vpiSysFuncReal + +$ivl_string_method$len vpiSysFuncInt diff --git a/vpi/table_mod_parse.y b/vpi/table_mod_parse.y index 8e309b110..fb1ff4f18 100644 --- a/vpi/table_mod_parse.y +++ b/vpi/table_mod_parse.y @@ -121,6 +121,7 @@ static void process_point() */ table : point | table point + ; /* * An individual point is just a bunch of columns followed by one or more @@ -156,6 +157,7 @@ point : columns END_LINE } } } + ; /* * Each column is a real value. We only save the columns we care about. @@ -179,6 +181,7 @@ columns : REAL } else if (cur_columns == dep_column) values[indep_values] = $2; cur_columns += 1; } + ; %% diff --git a/vpi/v2009_enum.c b/vpi/v2009_enum.c index bd43cc09c..3c8645c4b 100644 --- a/vpi/v2009_enum.c +++ b/vpi/v2009_enum.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vpi_config.h" diff --git a/vpi/v2009_table.c b/vpi/v2009_table.c index be21785d3..551834e83 100644 --- a/vpi/v2009_table.c +++ b/vpi/v2009_table.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vpi_config.h" diff --git a/vpi/vcd_priv.c b/vpi/vcd_priv.c index e95a87309..da2a03a12 100644 --- a/vpi/vcd_priv.c +++ b/vpi/vcd_priv.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sys_priv.h" diff --git a/vpi/vcd_priv.h b/vpi/vcd_priv.h index 2772dadfb..ea96642b3 100644 --- a/vpi/vcd_priv.h +++ b/vpi/vcd_priv.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "vpi_user.h" diff --git a/vpi/vcd_priv2.cc b/vpi/vcd_priv2.cc index ac4a99364..fb01ce5a8 100644 --- a/vpi/vcd_priv2.cc +++ b/vpi/vcd_priv2.cc @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vcd_priv.h" diff --git a/vpi/vhdl_table.c b/vpi/vhdl_table.c index 694522119..4e80e1444 100644 --- a/vpi/vhdl_table.c +++ b/vpi/vhdl_table.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "vpi_config.h" diff --git a/vpi/vpi_config.h.in b/vpi/vpi_config.h.in index e4dd2eb47..1f29e3fbe 100644 --- a/vpi/vpi_config.h.in +++ b/vpi/vpi_config.h.in @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # undef HAVE_LIBIBERTY_H diff --git a/vpi/vpi_debug.c b/vpi/vpi_debug.c index 96f334201..c1a2d415b 100644 --- a/vpi/vpi_debug.c +++ b/vpi/vpi_debug.c @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* diff --git a/vpi_user.h b/vpi_user.h index 3d5811835..b767c9efd 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -43,6 +43,7 @@ EXTERN_C_START # include # include +# include # include "_pli_types.h" #define ICARUS_VPI_CONST @@ -286,6 +287,7 @@ typedef struct t_vpi_delay { #define vpiParameter 41 #define vpiPartSelect 42 #define vpiPathTerm 43 +#define vpiPort 44 #define vpiRealVar 47 #define vpiReg 48 #define vpiSysFuncCall 56 @@ -308,6 +310,12 @@ typedef struct t_vpi_delay { #define vpiVariables 100 #define vpiExpr 102 +/********************** object types added with 1364-2001 *********************/ + +# define vpiRegArray 116 + +/********************** object types added with 1364-2005 *********************/ + #define vpiCallback 1000 /* PROPERTIES */ @@ -325,6 +333,14 @@ typedef struct t_vpi_delay { #define vpiTimePrecision 12 #define vpiDefFile 15 #define vpiDefLineNo 16 + +#define vpiDirection 20 /* direction of port: */ +# define vpiInput 1 +# define vpiOutput 2 +# define vpiInout 3 +# define vpiMixedIO 4 /* Not currently output */ +# define vpiNoDirection 5 + #define vpiNetType 22 # define vpiWire 1 # define vpiWand 2 @@ -338,6 +354,7 @@ typedef struct t_vpi_delay { # define vpiSupply1 10 # define vpiSupply0 11 #define vpiArray 28 +#define vpiPortIndex 29 #define vpiEdge 36 # define vpiNoEdge 0x00 /* No edge */ # define vpiEdge01 0x01 /* 0 --> 1 */ @@ -371,6 +388,7 @@ typedef struct t_vpi_delay { #define vpiAutomatic 50 #define vpiConstantSelect 53 #define vpiSigned 65 +#define vpiLocalParam 70 /* IVL private properties, also see vvp/vpi_priv.h for other properties */ #define _vpiNexusId 0x1000000 /* used in vvp/vpi_priv.h 0x1000001 */ @@ -604,6 +622,17 @@ extern void vpip_set_return_value(int value); extern s_vpi_vecval vpip_calc_clog2(vpiHandle arg); extern void vpip_make_systf_system_defined(vpiHandle ref); + /* Return driver information for a net bit. The information is returned + in the 'counts' array as follows: + counts[0] - number of drivers driving '0' onto the net + counts[1] - number of drivers driving '1' onto the net + counts[2] - number of drivers driving 'X' onto the net + counts[3] - set to 1 if the net is forced, 0 otherwise + The 'ref' argument should reference a net. The 'idx' argument selects + which bit of the net is examined. */ +extern void vpip_count_drivers(vpiHandle ref, unsigned idx, + unsigned counts[4]); + EXTERN_C_END #endif diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 4f3a59a80..b9e260adb 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -12,9 +12,8 @@ # # You should have received a copy of the GNU Library 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 +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. # SHELL = /bin/sh @@ -66,17 +65,19 @@ dllib=@DLLIB@ MDIR1 = -DMODULE_DIR1='"$(libdir)/ivl$(suffix)"' -V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \ - vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \ +V = vpi_modules.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \ + vpi_event.o vpi_iter.o vpi_mcd.o \ + vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_string.o vpi_tasks.o vpi_time.o \ vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \ vpip_to_dec.o vpip_format.o vvp_vpi.o O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \ - concat.o dff.o enum_type.o extend.o file_line.o npmos.o part.o \ + concat.o dff.o class_type.o enum_type.o extend.o file_line.o npmos.o part.o \ permaheap.o reduce.o resolv.o \ sfunc.o stop.o symbols.o ufunc.o codes.o vthread.o schedule.o \ statistics.o tables.o udp.o vvp_island.o vvp_net.o vvp_net_sig.o \ - event.o logic.o delay.o words.o island_tran.o $V + vvp_object.o vvp_cobject.o vvp_darray.o event.o logic.o delay.o \ + words.o island_tran.o $V all: dep vvp@EXEEXT@ libvpi.a vvp.man @@ -104,8 +105,8 @@ distclean: clean rm -f stamp-config-h config.h cppcheck: $(O:.o=.cc) libvpi.c draw_tt.c - cppcheck --enable=all -f --suppressions $(srcdir)/cppcheck.sup \ - $(INCLUDE_PATH) $^ + cppcheck --enable=all -f --suppressions-list=$(srcdir)/cppcheck.sup \ + --relative-paths=$(srcdir) $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in cd ..; ./config.status --file=vvp/$@ diff --git a/vvp/README.txt b/vvp/README.txt index a45854ded..0905425e2 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -284,6 +284,7 @@ general syntax of a variable is: