diff --git a/AStatement.h b/AStatement.h index ebff58e8d..209dab455 100644 --- a/AStatement.h +++ b/AStatement.h @@ -1,7 +1,7 @@ -#ifndef __AStatement_H -#define __AStatement_H +#ifndef IVL_AStatement_H +#define IVL_AStatement_H /* - * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2014 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 @@ -82,4 +82,4 @@ class AProcess : public LineInfo { AProcess& operator= (const AProcess&); }; -#endif +#endif /* IVL_AStatement_H */ diff --git a/Attrib.h b/Attrib.h index 55548ec7b..34dd3ac48 100644 --- a/Attrib.h +++ b/Attrib.h @@ -1,7 +1,7 @@ -#ifndef __Attrib_H -#define __Attrib_H +#ifndef IVL_Attrib_H +#define IVL_Attrib_H /* - * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -57,4 +57,4 @@ class Attrib { Attrib& operator= (const Attrib&); }; -#endif +#endif /* IVL_Attrib_H */ diff --git a/HName.cc b/HName.cc index 709528489..c783d57bb 100644 --- a/HName.cc +++ b/HName.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -22,22 +22,26 @@ # include # include # include -# include +using namespace std; hname_t::hname_t() { - number_ = INT_MIN; } hname_t::hname_t(perm_string text) : name_(text) { - number_ = INT_MIN; } hname_t::hname_t(perm_string text, int num) -: name_(text), number_(num) +: name_(text), number_(1) +{ + number_[0] = num; +} + +hname_t::hname_t(perm_string text, vector&nums) +: name_(text), number_(nums) { } @@ -53,24 +57,50 @@ hname_t& hname_t::operator = (const hname_t&that) return *this; } -bool operator < (const hname_t&l, const hname_t&r) +bool hname_t::operator < (const hname_t&r) const { - int cmp = strcmp(l.peek_name(), r.peek_name()); + int cmp = strcmp(name_, r.name_); if (cmp < 0) return true; if (cmp > 0) return false; - if (l.has_number() && r.has_number()) - return l.peek_number() < r.peek_number(); - else - return false; + + // The text parts are equal, so compare then number + // parts. Finish as soon as we find one to be less or more + // than the other. + size_t idx = 0; + while (number_.size() > idx || r.number_.size() > idx) { + + // Ran out of l numbers, so less. + if (number_.size() <= idx) + return true; + + // Ran out of r numbers, so greater. + if (r.number_.size() <= idx) + return false; + + if (number_[idx] < r.number_[idx]) + return true; + + if (number_[idx] > r.number_[idx]) + return false; + + idx += 1; + } + + // Fall-through means that we are equal, including all the + // number parts, so not less. + return false; } -bool operator == (const hname_t&l, const hname_t&r) +bool hname_t::operator == (const hname_t&r) const { - if (l.peek_name() == r.peek_name()) { - if (l.has_number() && r.has_number()) - return l.peek_number() == r.peek_number(); - else - return true; + if (name_ == r.name_) { + if (number_.size() != r.number_.size()) + return false; + + for (size_t idx = 0 ; idx < number_.size() ; idx += 1) + if (number_[idx] != r.number_[idx]) return false; + + return true; } return false; @@ -84,8 +114,8 @@ ostream& operator<< (ostream&out, const hname_t&that) } out << that.peek_name(); - if (that.has_number()) - out << "[" << that.peek_number() << "]"; + for (size_t idx = 0 ; idx < that.number_.size() ; idx += 1) + out << "[" << that.number_[idx] << "]"; return out; } diff --git a/HName.h b/HName.h index ce561f8f0..90f0d7942 100644 --- a/HName.h +++ b/HName.h @@ -1,7 +1,7 @@ -#ifndef __HName_H -#define __HName_H +#ifndef IVL_HName_H +#define IVL_HName_H /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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,13 +21,10 @@ # include # include +# include # include "StringHeap.h" -# include -#ifdef __GNUC__ -#if __GNUC__ > 2 -using namespace std; -#endif -#endif + +# include /* * This class represents a component of a Verilog hierarchical name. A @@ -39,27 +36,33 @@ using namespace std; class hname_t { + friend ostream& operator<< (ostream&out, const hname_t&that); + public: hname_t (); explicit hname_t (perm_string text); explicit hname_t (perm_string text, int num); + explicit hname_t (perm_string text, std::vector&nums); hname_t (const hname_t&that); ~hname_t(); hname_t& operator= (const hname_t&); + bool operator == (const hname_t&that) const; + bool operator < (const hname_t&that) const; + // Return the string part of the hname_t. perm_string peek_name(void) const; - bool has_number() const; - int peek_number() const; + size_t has_numbers() const; + int peek_number(size_t idx) const; private: perm_string name_; // If the number is anything other than INT_MIN, then this is // the numeric part of the name. Otherwise, it is not part of // the name at all. - int number_; + std::vector number_; private: // not implemented }; @@ -73,18 +76,17 @@ inline perm_string hname_t::peek_name(void) const return name_; } -inline int hname_t::peek_number() const +inline int hname_t::peek_number(size_t idx) const { - return number_; + assert(number_.size() > idx); + return number_[idx]; } -inline bool hname_t::has_number() const +inline size_t hname_t::has_numbers() const { - return number_ != INT_MIN; + return number_.size(); } -extern bool operator < (const hname_t&, const hname_t&); -extern bool operator == (const hname_t&, const hname_t&); extern ostream& operator<< (ostream&, const hname_t&); inline bool operator != (const hname_t&l, const hname_t&r) @@ -102,4 +104,4 @@ inline ostream& operator<< (ostream&out, const list&ll) return out; } -#endif +#endif /* IVL_HName_H */ diff --git a/Makefile.in b/Makefile.in index c31e2d735..acef67ec7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -68,7 +68,7 @@ dllib=@DLLIB@ # For a cross compile these defines will need to be set accordingly. HOSTCC = @CC@ -HOSTCFLAGS = @WARNING_FLAGS@ @CFLAGS@ +HOSTCFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ CC = @CC@ CXX = @CXX@ @@ -90,7 +90,7 @@ INCLUDE_PATH = -I. -I$(srcdir) -I$(srcdir)/libmisc endif CPPFLAGS = @DEFS@ $(INCLUDE_PATH) @CPPFLAGS@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ PICFLAGS = @PICFLAG@ LDFLAGS = @rdynamic@ @LDFLAGS@ @@ -109,7 +109,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.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 netscalar.o netstruct.o netvector.o \ + netenum.o netparray.o netqueue.o netscalar.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 \ @@ -175,6 +175,8 @@ endif cppcheck: $(O:.o=.cc) $(srcdir)/dosify.c $(srcdir)/version.c cppcheck --enable=all -f --suppressions-list=$(srcdir)/cppcheck.sup \ + -UYYPARSE_PARAM -UYYPRINT -Ushort -Usize_t -Uyyoverflow \ + -UYYTYPE_INT8 -UYYTYPE_INT16 -UYYTYPE_UINT8 -UYYTYPE_UINT16 \ --relative-paths=$(srcdir) $(INCLUDE_PATH) $^ cppcheck-all: diff --git a/Module.h b/Module.h index 2a53f3690..3facf3a7f 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ -#ifndef __Module_H -#define __Module_H +#ifndef IVL_Module_H +#define IVL_Module_H /* - * Copyright (c) 1998-2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -160,4 +160,4 @@ class Module : public PScopeExtra, public LineInfo { Module& operator= (const Module&); }; -#endif +#endif /* IVL_Module_H */ diff --git a/PClass.h b/PClass.h index 9282c094d..e5dc1d8a2 100644 --- a/PClass.h +++ b/PClass.h @@ -1,7 +1,7 @@ -#ifndef __PClass_H -#define __PClass_H +#ifndef IVL_PClass_H +#define IVL_PClass_H /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 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 @@ -44,4 +44,4 @@ class PClass : public PScopeExtra, public LineInfo { class_type_t*type; }; -#endif +#endif /* IVL_PClass_H */ diff --git a/PDelays.h b/PDelays.h index 7ecefd984..353501f66 100644 --- a/PDelays.h +++ b/PDelays.h @@ -1,7 +1,7 @@ -#ifndef __PDelays_H -#define __PDelays_H +#ifndef IVL_PDelays_H +#define IVL_PDelays_H /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -72,4 +72,4 @@ class PDelays { ostream& operator << (ostream&o, const PDelays&); -#endif +#endif /* IVL_PDelays_H */ diff --git a/PEvent.h b/PEvent.h index b51e87d13..11836d295 100644 --- a/PEvent.h +++ b/PEvent.h @@ -1,7 +1,7 @@ -#ifndef __PEvent_H -#define __PEvent_H +#ifndef IVL_PEvent_H +#define IVL_PEvent_H /* - * Copyright (c) 2000-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -51,4 +51,4 @@ class PEvent : public LineInfo { PEvent& operator= (const PEvent&); }; -#endif +#endif /* IVL_PEvent_H */ diff --git a/PExpr.h b/PExpr.h index 5b014de8a..44c4008a5 100644 --- a/PExpr.h +++ b/PExpr.h @@ -1,7 +1,7 @@ -#ifndef __PExpr_H -#define __PExpr_H +#ifndef IVL_PExpr_H +#define IVL_PExpr_H /* - * Copyright (c) 1998-2013 Stephen Williams + * Copyright (c) 1998-2014 Stephen Williams * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -245,6 +245,10 @@ class PEConcat : public PExpr { virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const; virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) 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; @@ -366,6 +370,11 @@ class PEIdent : public PExpr { // only applies to Ident expressions. NetNet* elaborate_subport(Design*des, NetScope*sc) const; + // Elaborate the identifier allowing for unpacked arrays. This + // method only applies to Ident expressions because only Ident + // expressions can can be unpacked arrays. + NetNet* elaborate_unpacked_net(Design*des, NetScope*sc) const; + verinum* eval_const(Design*des, NetScope*sc) const; virtual bool is_collapsible_net(Design*des, NetScope*scope) const; @@ -500,12 +509,23 @@ class PEIdent : public PExpr { NetESignal*net, NetScope*found, bool need_const) const; + NetExpr*elaborate_expr_net_bit_last_(Design*des, + NetScope*scope, + NetESignal*net, + NetScope*found, + bool need_const) const; NetExpr*elaborate_expr_class_member_(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const; + unsigned test_width_method_(Design*des, NetScope*scope, width_mode_t&mode); + NetExpr*elaborate_expr_method_(Design*des, + NetScope*scope, + unsigned expr_wid, + unsigned flags) const; + private: NetNet* elaborate_lnet_common_(Design*des, NetScope*scope, bool bidirectional_flag) const; @@ -916,7 +936,8 @@ class PECallFunction : public PExpr { NetExpr*elaborate_expr_pkg_(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags)const; NetExpr*elaborate_expr_method_(Design*des, NetScope*scope, - unsigned expr_wid) const; + unsigned expr_wid, + bool add_this_flag = false) const; #if 0 NetExpr*elaborate_expr_string_method_(Design*des, NetScope*scope) const; NetExpr*elaborate_expr_enum_method_(Design*des, NetScope*scope, @@ -980,4 +1001,4 @@ class PEVoid : public PExpr { unsigned flags) const; }; -#endif +#endif /* IVL_PExpr_H */ diff --git a/PGate.h b/PGate.h index 85ea1194b..5d9bde9f2 100644 --- a/PGate.h +++ b/PGate.h @@ -1,7 +1,7 @@ -#ifndef __PGate_H -#define __PGate_H +#ifndef IVL_PGate_H +#define IVL_PGate_H /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -124,6 +124,7 @@ class PGAssign : public PGate { virtual bool elaborate_sig(Design*des, NetScope*scope) const; private: + void elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const; }; @@ -259,4 +260,4 @@ class PGModule : public PGate { NetNet::PortType dir, bool as_signed) const; }; -#endif +#endif /* IVL_PGate_H */ diff --git a/PGenerate.h b/PGenerate.h index ff5fbbbff..45a37e13d 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -1,7 +1,7 @@ -#ifndef __PGenerate_H -#define __PGenerate_H +#ifndef IVL_PGenerate_H +#define IVL_PGenerate_H /* - * Copyright (c) 2006-2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2006-2014 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 @@ -139,4 +139,4 @@ class PGenerate : public LineInfo, public LexicalScope { extern std::ostream& operator << (std::ostream&, PGenerate::scheme_t); -#endif +#endif /* IVL_PGenerate_H */ diff --git a/PPackage.h b/PPackage.h index 6bd01c9c8..c352296d6 100644 --- a/PPackage.h +++ b/PPackage.h @@ -1,7 +1,7 @@ -#ifndef __PPackage_H -#define __PPackage_H +#ifndef IVL_PPackage_H +#define IVL_PPackage_H /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -44,4 +44,4 @@ class PPackage : public PScopeExtra, public LineInfo { void pform_dump(std::ostream&out) const; }; -#endif +#endif /* IVL_PPackage_H */ diff --git a/PScope.cc b/PScope.cc index 9fb4cef55..377142bf9 100644 --- a/PScope.cc +++ b/PScope.cc @@ -31,6 +31,9 @@ PScope::PScope(perm_string n) PScope::~PScope() { + for(map::iterator it = typedefs.begin(); + it != typedefs.end(); ++it) + delete it->second; } PWire* LexicalScope::wires_find(perm_string name) diff --git a/PScope.h b/PScope.h index 279ca6e6c..30e1fea7e 100644 --- a/PScope.h +++ b/PScope.h @@ -1,7 +1,7 @@ -#ifndef __PScope_H -#define __PScope_H +#ifndef IVL_PScope_H +#define IVL_PScope_H /* - * Copyright (c) 2008,2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -187,4 +187,4 @@ class PScopeExtra : public PScope { void dump_funcs_(ostream&out, unsigned indent) const; }; -#endif +#endif /* IVL_PScope_H */ diff --git a/PSpec.h b/PSpec.h index 29df33791..7c34f5bf6 100644 --- a/PSpec.h +++ b/PSpec.h @@ -1,7 +1,7 @@ -#ifndef __PSpec_H -#define __PSpec_H +#ifndef IVL_PSpec_H +#define IVL_PSpec_H /* - * Copyright (c) 2006-2011 Stephen Williams + * Copyright (c) 2006-2014 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -84,4 +84,4 @@ class PSpecPath : public LineInfo { std::vectordelays; }; -#endif +#endif /* IVL_PSpec_H */ diff --git a/PTask.h b/PTask.h index 9e417615f..1b636d05a 100644 --- a/PTask.h +++ b/PTask.h @@ -1,7 +1,7 @@ -#ifndef __PTask_H -#define __PTask_H +#ifndef IVL_PTask_H +#define IVL_PTask_H /* - * Copyright (c) 1999-2008,2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -49,6 +49,12 @@ class PTaskFunc : public PScope, public LineInfo { // to the class type. inline class_type_t* method_of() const { return this_type_; } + + virtual void elaborate_sig(Design*des, NetScope*scope) const =0; + virtual void elaborate(Design*des, NetScope*scope) const =0; + + virtual void dump(std::ostream&, unsigned) const =0; + protected: // Elaborate the ports list. Write into the ports vector the // NetNet pointers for the ports, and write into the pdefs the @@ -146,4 +152,4 @@ class PFunction : public PTaskFunc { bool is_auto_; }; -#endif +#endif /* IVL_PTask_H */ diff --git a/PUdp.h b/PUdp.h index 100e64572..9bc087c4d 100644 --- a/PUdp.h +++ b/PUdp.h @@ -1,7 +1,7 @@ -#ifndef __PUdp_H -#define __PUdp_H +#ifndef IVL_PUdp_H +#define IVL_PUdp_H /* - * Copyright (c) 1998-2011 Stephen Williams (steve@picturel.com) + * Copyright (c) 1998-2014 Stephen Williams (steve@picturel.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 @@ -76,4 +76,4 @@ class PUdp : public LineInfo { PUdp& operator= (const PUdp&); }; -#endif +#endif /* IVL_PUdp_H */ diff --git a/PWire.h b/PWire.h index 464d4d6c6..d003d445b 100644 --- a/PWire.h +++ b/PWire.h @@ -1,7 +1,7 @@ -#ifndef __PWire_H -#define __PWire_H +#ifndef IVL_PWire_H +#define IVL_PWire_H /* - * Copyright (c) 1998-2009,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -129,4 +129,4 @@ class PWire : public LineInfo { PWire& operator= (const PWire&); }; -#endif +#endif /* IVL_PWire_H */ diff --git a/Statement.cc b/Statement.cc index f30b6f931..e0ed46d24 100644 --- a/Statement.cc +++ b/Statement.cc @@ -336,6 +336,20 @@ PForce::~PForce() delete expr_; } +PForeach::PForeach(perm_string av, const list&ix, Statement*s) +: array_var_(av), index_vars_(ix.size()), statement_(s) +{ + size_t idx = 0; + for (list::const_iterator cur = ix.begin() + ; cur != ix.end() ; ++cur) + index_vars_[idx++] = *cur; +} + +PForeach::~PForeach() +{ + delete statement_; +} + PForever::PForever(Statement*s) : statement_(s) { diff --git a/Statement.h b/Statement.h index 60ab166f6..b650a03f9 100644 --- a/Statement.h +++ b/Statement.h @@ -1,7 +1,7 @@ -#ifndef __Statement_H -#define __Statement_H +#ifndef IVL_Statement_H +#define IVL_Statement_H /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -224,12 +224,16 @@ 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; + NetProc*elaborate_method_(Design*des, NetScope*scope, + bool add_this_flag = false) const; NetProc*elaborate_function_(Design*des, NetScope*scope) const; NetProc*elaborate_build_call_(Design*des, NetScope*scope, NetScope*task, NetExpr*use_this) const; - + NetProc*elaborate_sys_task_method_(Design*des, NetScope*scope, + NetNet*net, + perm_string method_name, + const char*sys_task_name) const; bool test_task_calls_ok_(Design*des, NetScope*scope) const; PPackage*package_; @@ -440,6 +444,26 @@ class PForce : public Statement { PExpr*expr_; }; +class PForeach : public Statement { + public: + explicit PForeach(perm_string var, const std::list&ix, Statement*stmt); + ~PForeach(); + + virtual NetProc* elaborate(Design*des, NetScope*scope) const; + virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; + virtual void dump(ostream&out, unsigned ind) const; + + private: + NetProc* elaborate_static_array_(Design*des, NetScope*scope, + const std::vector&dims) const; + + private: + perm_string array_var_; + std::vector index_vars_; + Statement*statement_; +}; + class PForever : public Statement { public: explicit PForever(Statement*s); @@ -558,4 +582,4 @@ class PWhile : public Statement { Statement*statement_; }; -#endif +#endif /* IVL_Statement_H */ diff --git a/_pli_types.h.in b/_pli_types.h.in index d3057eb04..694cbbdb9 100644 --- a/_pli_types.h.in +++ b/_pli_types.h.in @@ -1,7 +1,7 @@ -#ifndef PLI_TYPES -#define PLI_TYPES +#ifndef PLI_TYPES_H +#define PLI_TYPES_H /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -85,4 +85,4 @@ typedef char PLI_BYTE8; typedef unsigned char PLI_UBYTE8; #endif -#endif +#endif /* PLI_TYPES_H */ diff --git a/acc_user.h b/acc_user.h index 48eac2e69..3fae82700 100644 --- a/acc_user.h +++ b/acc_user.h @@ -1,7 +1,7 @@ -#ifndef __acc_user_H -#define __acc_user_H +#ifndef ACC_USER_H +#define ACC_USER_H /* - * Copyright (c) 2002 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2014 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 @@ -228,6 +228,7 @@ extern PLI_INT32 acc_fetch_size(handle obj); extern PLI_INT32 acc_fetch_type(handle obj); extern PLI_INT32 acc_fetch_fulltype(handle obj); +extern PLI_INT32 acc_fetch_paramtype(handle obj); extern PLI_INT32 acc_fetch_range(handle object, int *msb, int *lsb); extern const char* acc_fetch_type_str(PLI_INT32 type); @@ -270,4 +271,4 @@ extern char* acc_version(void); EXTERN_C_END -#endif +#endif /* ACC_USER_H */ diff --git a/aclocal.m4 b/aclocal.m4 index 0b0d9c29c..99bfe9516 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -218,17 +218,6 @@ AC_SUBST(strip_dynamic) # AC_MSG_RESULT($strip_dynamic) ])# AX_LD_RDYNAMIC -# AX_CPP_PRECOMP -# -------------- -AC_DEFUN([AX_CPP_PRECOMP], -[# Darwin requires -no-cpp-precomp -case "${host}" in - *-*-darwin*) - CPPFLAGS="-no-cpp-precomp $CPPFLAGS" - CFLAGS="-no-cpp-precomp $CFLAGS" - ;; -esac -])# AX_CPP_PRECOMP # AX_C99_STRTOD # ------------- diff --git a/async.cc b/async.cc index fa5bbaee0..311b1af2c 100644 --- a/async.cc +++ b/async.cc @@ -50,8 +50,8 @@ bool NetEvWait::is_asynchronous() level sensitive, but the nex_async_ method takes care of that test. */ NexusSet*sense = new NexusSet; - for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) { - NexusSet*tmp = event(idx)->nex_async_(); + for (unsigned idx = 0 ; idx < events_.size() ; idx += 1) { + NexusSet*tmp = events_[idx]->nex_async_(); if (tmp == 0) { delete sense; return false; diff --git a/cadpli/Makefile.in b/cadpli/Makefile.in index e3a0eb559..ba347b72c 100644 --- a/cadpli/Makefile.in +++ b/cadpli/Makefile.in @@ -43,7 +43,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = cadpli.o diff --git a/cadpli/cadpli.c b/cadpli/cadpli.c index 9a75ab7dd..66b213e56 100644 --- a/cadpli/cadpli.c +++ b/cadpli/cadpli.c @@ -79,7 +79,7 @@ static void thunker_register(void) } } -void (*vlog_startup_routines[])() = { +void (*vlog_startup_routines[])(void) = { thunker_register, 0 }; diff --git a/cadpli/ivl_dlfcn.h b/cadpli/ivl_dlfcn.h index edd8418a1..c18247daa 100644 --- a/cadpli/ivl_dlfcn.h +++ b/cadpli/ivl_dlfcn.h @@ -1,7 +1,7 @@ -#ifndef __ivl_dlfcn_H -#define __ivl_dlfcn_H +#ifndef IVL_ivl_dlfcn_H +#define IVL_ivl_dlfcn_H /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -91,4 +91,4 @@ static __inline__ const char*dlerror(void) { return strerror( errno ); } #endif -#endif +#endif /* IVL_ivl_dlfcn_H */ diff --git a/compiler.h b/compiler.h index 63cc509b5..cbd0e969f 100644 --- a/compiler.h +++ b/compiler.h @@ -1,5 +1,5 @@ -#ifndef __compiler_H -#define __compiler_H +#ifndef IVL_compiler_H +#define IVL_compiler_H /* * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) * @@ -283,4 +283,4 @@ extern void cleanup_sys_func_table(); */ extern ivl_sfunc_as_task_t def_sfunc_as_task; -#endif +#endif /* IVL_compiler_H */ diff --git a/config.h.in b/config.h.in index fee775dda..30470a22b 100644 --- a/config.h.in +++ b/config.h.in @@ -1,7 +1,7 @@ -#ifndef __config_H /* -*- c++ -*- */ -#define __config_H +#ifndef IVL_config_H /* -*- c++ -*- */ +#define IVL_config_H /* - * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -62,4 +62,4 @@ */ # undef CHECK_WITH_VALGRIND -#endif /* __config_H */ +#endif /* IVL_config_H */ diff --git a/configure.in b/configure.in index c5a31bf33..b50cd72a5 100644 --- a/configure.in +++ b/configure.in @@ -14,10 +14,6 @@ AC_CANONICAL_HOST dnl Checks for programs. AC_PROG_CC # AC_PROG_CC_C99 is only available in autoconf version 2.60 and later. -# If you must use an older version then comment out the following two -# lines, but be warned that there could be issues with finding the -# nan(), etc. functions. It is really best to upgrade to a supported -# version of autoconf. AC_PREREQ([2.60]) AC_PROG_CC_C99 AC_PROG_CXX @@ -85,8 +81,9 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], CFLAGS="$iverilog_temp_cflags" AC_SUBST(DEPENDENCY_FLAG, [-MD]) -AC_SUBST(WARNING_FLAGS, ["-Wall -Wshadow"]) -AC_SUBST(WARNING_FLAGS_CXX, ["$iverilog_wextra_flag"]) +AC_SUBST(WARNING_FLAGS, ["-Wall $iverilog_wextra_flag -Wshadow"]) +AC_SUBST(WARNING_FLAGS_CC, [""]) +AC_SUBST(WARNING_FLAGS_CXX, [""]) fi AC_LANG(C++) @@ -217,9 +214,6 @@ AX_LD_EXTRALIBS # CFLAGS inherited by cadpli/Makefile? AX_C_PICFLAG -# may modify CPPFLAGS and CFLAGS -AX_CPP_PRECOMP - # may modify LDFLAGS AX_C99_STRTOD diff --git a/cppcheck.sup b/cppcheck.sup index 839dd525a..8bbd27e6e 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:4589 -thisSubtraction:netlist.h:4598 +thisSubtraction:netlist.h:4938 +thisSubtraction:netlist.h:4947 diff --git a/design_dump.cc b/design_dump.cc index e42347bcb..7673b1598 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -30,6 +30,7 @@ # include "discipline.h" # include "netclass.h" # include "netdarray.h" +# include "netqueue.h" # include "netvector.h" # include "ivl_assert.h" # include "PExpr.h" @@ -113,6 +114,9 @@ ostream& operator << (ostream&o, ivl_variable_type_t val) case IVL_VT_CLASS: o << "class"; break; + case IVL_VT_QUEUE: + o << "queue"; + break; } return o; } @@ -145,18 +149,87 @@ ostream& operator << (ostream&o, ivl_switch_type_t val) return o; } +ostream& operator << (ostream&fd, PortType::Enum val) +{ + switch (val) { + case PortType::NOT_A_PORT: + fd << "NOT_A_PORT"; + break; + case PortType::PIMPLICIT: + fd << "PIMPLICIT"; + break; + case PortType::PINPUT: + fd << "PINPUT"; + break; + case PortType::POUTPUT: + fd << "POUTPUT"; + break; + case PortType::PINOUT: + fd << "PINOUT"; + break; + case PortType::PREF: + fd << "PREF"; + break; + default: + fd << "PortType::Enum::?"; + break; + } + + return fd; +} + +ostream& operator << (ostream&fd, NetCaseCmp::kind_t that) +{ + switch (that) { + case NetCaseCmp::EEQ: + fd << "==="; + break; + case NetCaseCmp::NEQ: + fd << "!=="; + break; + case NetCaseCmp::XEQ: + fd << "==?"; + break; + case NetCaseCmp::ZEQ: + fd << "==z?"; + break; + } + return fd; +} + ostream& ivl_type_s::debug_dump(ostream&o) const { o << typeid(*this).name(); return o; } +ostream& netclass_t::debug_dump(ostream&fd) const +{ + fd << "class " << name_ << "{"; + for (size_t idx = 0 ; idx < property_table_.size() ; idx += 1) { + if (idx != 0) fd << "; "; + if (property_table_[idx].type) + property_table_[idx].type->debug_dump(fd); + else + fd << "NO_TYPE"; + fd << " " << property_table_[idx].name; + } + fd << "}"; + return fd; +} + ostream& netdarray_t::debug_dump(ostream&o) const { o << "dynamic array of " << *element_type(); return o; } +ostream& netqueue_t::debug_dump(ostream&fd) const +{ + fd << "queue of " << *element_type(); + return fd; +} + ostream& netvector_t::debug_dump(ostream&o) const { o << type_ << (signed_? " signed" : " unsigned") << packed_dims_; @@ -170,10 +243,7 @@ static inline void dump_scope_path(ostream&o, const NetScope*scope) dump_scope_path(o, parent); o << "."; } - const hname_t name = scope->fullname(); - o << name.peek_name(); - if (name.has_number()) - o << "[" << name.peek_number() << "]"; + o << scope->fullname(); } ostream& operator <<(ostream&o, struct __ScopePathManip marg) @@ -192,6 +262,68 @@ ostream& operator <<(ostream&o, struct __ObjectPathManip marg) return o; } +ostream& operator <<(ostream&fd, Link::DIR dir) +{ + switch (dir) { + case Link::PASSIVE: + fd << "PASSIVE"; + break; + case Link::INPUT: + fd << "INPUT"; + break; + case Link::OUTPUT: + fd << "OUTPUT"; + break; + default: + fd << "<" << (int)dir << ">"; + break; + } + return fd; +} + +void NetPins::show_type(ostream&fd) const +{ + fd << typeid(*this).name(); +} + +void NetObj::show_type(ostream&fd) const +{ + fd << typeid(*this).name() << "[" << scope_path(scope_) << "." << name_ << "]"; +} + +struct __ShowTypeManip { const NetPins*pins; }; +inline __ShowTypeManip show_type(const NetPins*pins) +{ __ShowTypeManip tmp; tmp.pins = pins; return tmp; } + +inline ostream& operator << (ostream&fd, __ShowTypeManip man) +{ + if (man.pins == 0) + fd << "NexusSet"; + else + man.pins->show_type(fd); + return fd; +} + + +void Link::dump_link(ostream&fd, unsigned ind) const +{ + const Link*cur; + const Nexus*nex = nexus(); + + if (nex == 0) { + fd << setw(ind) << "" << "" << endl; + return; + } + + for (cur = nex->first_nlink() ; cur; cur = cur->next_nlink()) { + const NetPins*obj = cur->get_obj(); + unsigned pin = cur->get_pin(); + fd << setw(ind) << "" << "Pin " << pin + << " of " << show_type(obj) + << ", dir=" << cur->dir_ << endl; + } +} + void NetBranch::dump(ostream&o, unsigned ind) const { static const char*pin_names[2] = { @@ -523,10 +655,7 @@ void NetBUFZ::dump_node(ostream&o, unsigned ind) const void NetCaseCmp::dump_node(ostream&o, unsigned ind) const { - if (eeq_) - o << setw(ind) << "" << "case compare === : " << name() << endl; - else - o << setw(ind) << "" << "case compare !== : " << name() << endl; + o << setw(ind) << "" << "case compare " << kind_ << ": " << name() << endl; dump_node_pins(o, ind+4); } @@ -674,6 +803,21 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } +void NetSubstitute::dump_node(ostream&fd, unsigned ind) const +{ + fd << setw(ind) << "" << "NetSubstitute: " + << name(); + if (rise_time()) + fd << " #(" << *rise_time() + << "," << *fall_time() + << "," << *decay_time() << ")"; + else + fd << " #(.,.,.)"; + fd << " width=" << wid_ << " base=" << off_ <dump(o, ind+2); } +void NetForLoop::dump(ostream&fd, unsigned ind) const +{ + fd << setw(ind) << "" << "FOR LOOP index=" << index_->name() << endl; + statement_->dump(fd, ind+4); + step_statement_->dump(fd, ind+4); +} + void NetFree::dump(ostream&o, unsigned ind) const { o << setw(ind) << "// free storage : " << scope_path(scope_) << endl; @@ -1568,6 +1719,11 @@ void NetEEvent::dump(ostream&o) const o << "name() << ">"; } +void NetELast::dump(ostream&fd) const +{ + fd << "name() << ">"; +} + void NetENetenum::dump(ostream&o) const { o << ""; @@ -1593,6 +1749,8 @@ void NetENull::dump(ostream&o) const void NetEProperty::dump(ostream&o) const { o << net_->name() << ".<" << pidx_ << ">"; + if (index_) + o << "[" << *index_ << "]"; } void NetEScope::dump(ostream&o) const @@ -1721,6 +1879,18 @@ void Design::dump(ostream&o) const cur->second->dump(o); } + o << "$ROOT CLASSESS:" << endl; + for (map::const_iterator cur = classes_.begin() + ; cur != classes_.end() ; ++cur) { + cur->second->dump_scope(o); + } + + o << "$ROOT TASKS/FUNCTIONS:" << endl; + for (map::const_iterator cur = root_tasks_.begin() + ; cur != root_tasks_.end() ; ++ cur) { + cur->first->dump(o); + } + o << "SCOPES:" << endl; for (list::const_iterator scope = root_scopes_.begin(); scope != root_scopes_.end(); ++ scope ) { diff --git a/discipline.h b/discipline.h index 7c407d52e..df902b499 100644 --- a/discipline.h +++ b/discipline.h @@ -1,7 +1,7 @@ -#ifndef __discipline_H -#define __discipline_H +#ifndef IVL_discipline_H +#define IVL_discipline_H /* - * Copyright (c) 2008-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -74,4 +74,4 @@ extern map disciplines; // Map access function name to the nature that it accesses. extern map access_function_nature; -#endif +#endif /* IVL_discipline_H */ diff --git a/driver-vpi/Makefile.in b/driver-vpi/Makefile.in index 731e155eb..d462cc2f2 100644 --- a/driver-vpi/Makefile.in +++ b/driver-vpi/Makefile.in @@ -48,7 +48,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = main.o res.o diff --git a/driver/Makefile.in b/driver/Makefile.in index a94001e30..b2ad7150c 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -49,7 +49,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = main.o substit.o cflexor.o cfparse.o @@ -67,7 +67,11 @@ distclean: clean rm -f Makefile config.log cppcheck: $(O:.o=.c) - cppcheck --enable=all -f $(INCLUDE_PATH) $^ + cppcheck --enable=all -f \ + -UYY_USER_INIT \ + -UYYPARSE_PARAM -UYYPRINT -Ushort -Uyyoverflow \ + -UYYTYPE_INT8 -UYYTYPE_INT16 -UYYTYPE_UINT8 -UYYTYPE_UINT16 \ + $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in ../config.status cd ..; ./config.status --file=driver/$@ diff --git a/driver/cflexor.lex b/driver/cflexor.lex index 9d50c4c4f..b0ba1a40b 100644 --- a/driver/cflexor.lex +++ b/driver/cflexor.lex @@ -247,7 +247,7 @@ void cfreset(FILE*fd, const char*path) /* * Modern version of flex (>=2.5.9) can clean up the scanner data. */ -void destroy_lexor() +void destroy_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 diff --git a/driver/cfparse.y b/driver/cfparse.y index 13fcb85c9..4653ba560 100644 --- a/driver/cfparse.y +++ b/driver/cfparse.y @@ -221,7 +221,7 @@ item } | error - { fprintf(stderr, "Error: unable to parse line %d in " + { fprintf(stderr, "Error: unable to parse line %u in " "%s.\n", cflloc.first_line, current_file); return 1; } @@ -270,5 +270,6 @@ skip_arg : TOK_PLUSARG int yyerror(const char*msg) { + (void)msg; /* Parameter is not used. */ return 0; } diff --git a/driver/cfparse_misc.h b/driver/cfparse_misc.h index c72886b36..3cb7ddd6e 100644 --- a/driver/cfparse_misc.h +++ b/driver/cfparse_misc.h @@ -1,7 +1,7 @@ -#ifndef __cfparse_misc_H -#define __cfparse_misc_H +#ifndef IVL_cfparse_misc_H +#define IVL_cfparse_misc_H /* - * Copyright (c) 2001-2009 Picture Elements, Inc. + * Copyright (c) 2001-2014 Picture Elements, Inc. * Stephen Williams (steve@picturel.com) * * This source code is free software; you can redistribute it @@ -38,7 +38,7 @@ int cflex(void); int cferror(const char *); int cfparse(void); void switch_to_command_file(const char *); -void destroy_lexor(); +void destroy_lexor(void); char *current_file; -#endif +#endif /* IVL_cfparse_misc_H */ diff --git a/driver/globals.h b/driver/globals.h index 23c72a380..b71106f73 100644 --- a/driver/globals.h +++ b/driver/globals.h @@ -1,5 +1,5 @@ -#ifndef __globals_H -#define __globals_H +#ifndef IVL_globals_H +#define IVL_globals_H /* * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * @@ -54,4 +54,4 @@ extern void process_parameter(const char*name); /* Set the default timescale for the simulator. */ extern void process_timescale(const char*ts_string); -#endif +#endif /* IVL_globals_H */ diff --git a/driver/main.c b/driver/main.c index d0b286c47..3ee4de008 100644 --- a/driver/main.c +++ b/driver/main.c @@ -71,7 +71,7 @@ const char HELP[] = #endif #include -#if HAVE_GETOPT_H +#ifdef HAVE_GETOPT_H #include #endif @@ -188,7 +188,7 @@ static const char** defparm_base = 0; static int defparm_size = 0; /* Function to add a command file name to the FIFO. */ -void add_cmd_file(const char* filename) +static void add_cmd_file(const char* filename) { p_command_file new; @@ -205,7 +205,7 @@ void add_cmd_file(const char* filename) } /* Function to return the top command file name from the FIFO. */ -char *get_cmd_file() +static char *get_cmd_file(void) { char *filename; @@ -402,7 +402,7 @@ static int t_preprocess_only(void) * needed to run the command from the configuration file (which is * already parsed for us) so we can handle must of the generic cases. */ -static int t_compile() +static int t_compile(void) { unsigned rc; @@ -625,7 +625,7 @@ void process_file_name(const char*name, int lib_flag) } } -int process_generation(const char*name) +static int process_generation(const char*name) { if (strcmp(name,"1995") == 0) generation = "1995"; @@ -750,7 +750,7 @@ int process_generation(const char*name) return 0; } -int process_depfile(const char*name) +static int process_depfile(const char*name) { const char*cp = strchr(name, '='); if (cp) { @@ -784,7 +784,7 @@ int process_depfile(const char*name) /* * If it exists add the SFT file for the given module. */ -void add_sft_file(const char *module) +static void add_sft_file(const char *module) { char *file; @@ -799,7 +799,7 @@ int main(int argc, char **argv) { int e_flag = 0; int version_flag = 0; - int opt, idx; + int opt; #ifdef __MINGW32__ /* Calculate the ivl_root from the path to the command. This @@ -907,7 +907,7 @@ int main(int argc, char **argv) } } - while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hI:M:m:N::o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) { + while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hI:M:m:N:o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) { switch (opt) { case 'B': @@ -1142,7 +1142,7 @@ int main(int argc, char **argv) vhdlpp_work = "ivl_vhdl_work"; fprintf(defines_file, "vhdlpp:%s%cvhdlpp\n", vhdlpp_dir, sep); fprintf(defines_file, "vhdlpp-work:%s\n", vhdlpp_work); - for (idx = 0 ; idx < vhdlpp_libdir_cnt ; idx += 1) + for (unsigned idx = 0 ; idx < vhdlpp_libdir_cnt ; idx += 1) fprintf(defines_file, "vhdlpp-libdir:%s\n", vhdlpp_libdir[idx]); /* Process parameter definition from command line. The last @@ -1156,7 +1156,7 @@ int main(int argc, char **argv) /* Finally, process all the remaining words on the command line as file names. */ - for (idx = optind ; idx < argc ; idx += 1) + for (int idx = optind ; idx < argc ; idx += 1) process_file_name(argv[idx], 0); /* If the use of a default include directory is not diff --git a/driver/substit.c b/driver/substit.c index c71ea9f2a..5a7b9a239 100644 --- a/driver/substit.c +++ b/driver/substit.c @@ -21,6 +21,7 @@ # include # include # include "ivl_alloc.h" +# include "globals.h" char* substitutions(const char*str) diff --git a/dup_expr.cc b/dup_expr.cc index 93c509270..c1ec0ce0d 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -182,6 +182,14 @@ NetEEvent* NetEEvent::dup_expr() const return 0; } +NetELast* NetELast::dup_expr() const +{ + NetELast*tmp = new NetELast(sig_); + ivl_assert(*this, tmp); + tmp->set_line(*this); + return tmp; +} + NetENetenum* NetENetenum::dup_expr() const { ivl_assert(*this, 0); @@ -249,6 +257,7 @@ NetESignal* NetESignal::dup_expr() const NetESignal*tmp = new NetESignal(net_, word_); ivl_assert(*this, tmp); tmp->expr_width(expr_width()); + tmp->cast_signed(has_sign()); tmp->set_line(*this); return tmp; } diff --git a/elab_expr.cc b/elab_expr.cc index 854d6e1fb..39c05b9b6 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -30,6 +30,7 @@ # include "netlist.h" # include "netclass.h" # include "netenum.h" +# include "netparray.h" # include "netvector.h" # include "discipline.h" # include "netmisc.h" @@ -106,6 +107,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, int context_wid = -1; switch (lv_type) { case IVL_VT_DARRAY: + case IVL_VT_QUEUE: // For these types, use a different elab_and_eval that // uses the lv_net_type. We should eventually transition // all the types to this new form. @@ -309,7 +311,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode) case '%': case '/': - min_width_ = max(min_width_, expr_width_); + min_width_ = UINT_MAX; // disable width pruning break; case 'l': // << Should be handled by PEBShift @@ -530,7 +532,7 @@ NetExpr* PEBinary::elaborate_expr_base_mult_(Design*, if (NetEConst*rp_const = dynamic_cast (rp)) { verinum rp_val = rp_const->value(); - if (! rp_val.is_defined()) { + if (!rp_val.is_defined() && (lp->expr_type() == IVL_VT_LOGIC)) { NetEConst*tmp = make_const_x(expr_wid); tmp->cast_signed(signed_flag_); tmp->set_line(*this); @@ -538,7 +540,7 @@ NetExpr* PEBinary::elaborate_expr_base_mult_(Design*, return tmp; } - if (rp_val.is_zero() && (lp->expr_type() != IVL_VT_LOGIC)) { + if (rp_val.is_zero() && (lp->expr_type() == IVL_VT_BOOL)) { NetEConst*tmp = make_const_0(expr_wid); tmp->cast_signed(signed_flag_); tmp->set_line(*this); @@ -815,7 +817,7 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode) if (op_ == 'l') min_width_ = left_->min_width(); else - min_width_ = expr_width_; + min_width_ = UINT_MAX; // disable width pruning return fix_width_(mode); } @@ -1296,10 +1298,27 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope, return expr_width_; } + if (use_darray && (method_name == "pop_back" || method_name=="pop_front")) { + if (debug_elaborate) { + cerr << get_fileline() << ": PECallFunction::test_width_method_: " + << "Detected " << method_name << " method" + << " of dynamic arrays." << endl; + } + + expr_type_ = use_darray->element_base_type(); + expr_width_ = use_darray->element_width(); + min_width_ = expr_width_; + signed_flag_= false; + + return expr_width_; + } + if (const netclass_t*class_type = net->class_type()) { - cerr << get_fileline() << ": PECallFunction::test_width_method_: " - << "Try to find method " << method_name - << " of class " << class_type->get_name() << endl; + if (debug_elaborate) { + cerr << get_fileline() << ": PECallFunction::test_width_method_: " + << "Try to find method " << method_name + << " of class " << class_type->get_name() << endl; + } NetScope*func = class_type->method_from_name(method_name); if (func == 0) { @@ -1768,6 +1787,14 @@ static const netstruct_t::member_t*get_struct_member(const LineInfo*li, bool calculate_part(const LineInfo*li, Design*des, NetScope*scope, const index_component_t&index, long&off, unsigned long&wid) { + if (index.sel == index_component_t::SEL_BIT_LAST) { + cerr << li->get_fileline() << ": sorry: " + << "Last element select expression " + << "not supported." << endl; + des->errors += 1; + return false; + } + // Evaluate the last index expression into a constant long. NetExpr*texpr = elab_and_eval(des, scope, index.msb, -1, true); long msb; @@ -1809,6 +1836,11 @@ bool calculate_part(const LineInfo*li, Design*des, NetScope*scope, } return true; + case index_component_t::SEL_IDX_UP: + wid = lsb; + off = msb; + break; + default: ivl_assert(*li, 0); break; @@ -2051,11 +2083,24 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, des->errors += 1; return 0; } - ivl_assert(*this, def); + ivl_assert(*this, def); NetScope*dscope = def->scope(); ivl_assert(*this, dscope); + /* In SystemVerilog a method calling another method in the + * current class needs to be elaborated as a method with an + * implicit this added. */ + if (gn_system_verilog() && (path_.size() == 1)) { + const NetScope *c_scope = scope->get_class_scope(); + if (c_scope && (c_scope == dscope->get_class_scope())) { + NetExpr*tmp = elaborate_expr_method_(des, scope, expr_wid, + true); + assert(tmp); + return tmp; + } + } + bool need_const = NEED_CONST & flags; // It is possible to get here before the called function has been @@ -2249,17 +2294,22 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope, } NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, - unsigned expr_wid) const + unsigned expr_wid, + bool add_this_flag) const { pform_name_t use_path = path_; perm_string method_name = peek_tail_name(use_path); use_path.pop_back(); + /* Add the implicit this reference when requested. */ + if (add_this_flag) { + assert(use_path.empty()); + use_path.push_front(name_component_t(perm_string::literal("@"))); + } + // If there is no object to the left of the method name, then // give up on the idea of looking for an object method. - if (use_path.empty()) { - return 0; - } + if (use_path.empty()) return 0; NetNet *net = 0; const NetExpr *par; @@ -2323,12 +2373,31 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, if (net->darray_type()) { if (method_name == "size") { - NetESFunc*sys_expr = new NetESFunc("$ivl_darray_method$size", + NetESFunc*sys_expr = new NetESFunc("$size", IVL_VT_BOOL, 32, 1); sys_expr->parm(0, new NetESignal(net)); sys_expr->set_line(*this); return sys_expr; } + + if (method_name == "pop_back") { + NetESFunc*sys_expr = new NetESFunc("$ivl_darray_method$pop_back", + expr_type_, + expr_width_, 1); + sys_expr->parm(0, new NetESignal(net)); + sys_expr->set_line(*this); + return sys_expr; + } + + if (method_name == "pop_front") { + NetESFunc*sys_expr = new NetESFunc("$ivl_darray_method$pop_front", + expr_type_, + expr_width_, 1); + sys_expr->parm(0, new NetESignal(net)); + sys_expr->set_line(*this); + return sys_expr; + } + } if (const netclass_t*class_type = net->class_type()) { @@ -2466,6 +2535,24 @@ unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&) // Keep track of the concatenation/repeat depth. static int concat_depth = 0; +NetExpr* PEConcat::elaborate_expr(Design*, NetScope*, + ivl_type_t type, unsigned /*flags*/) const +{ + switch (type->base_type()) { + case IVL_VT_QUEUE: + if (parms_.size() == 0) { + NetENull*tmp = new NetENull; + tmp->set_line(*this); + return tmp; + } + default: + cerr << get_fileline() << ": internal error: " + << "I don't know how to elaborate(ivl_type_t)" + << " this expression: " << *this << endl; + return 0; + } +} + NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { @@ -2604,6 +2691,7 @@ bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net, { list index; index = path_.back().index; + ivl_assert(*this, index.size() >= net->unpacked_dimensions()); for (size_t idx = 0 ; idx < net->unpacked_dimensions() ; idx += 1) index.pop_front(); @@ -2787,6 +2875,48 @@ bool PEIdent::calculate_param_range_(Design*, NetScope*, return true; } +unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&) +{ + if (!gn_system_verilog()) + return 0; + if (path_.size() < 2) + return 0; + + pform_name_t use_path = path_; + perm_string member_name = peek_tail_name(path_); + use_path.pop_back(); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::test_width_method_: " + << "Try to find method=" << member_name + << " of signal " << use_path << endl; + } + + NetNet*net = 0; + const NetExpr*par = 0; + NetEvent*eve = 0; + const NetExpr*ex1 = 0, *ex2 = 0; + symbol_search(this, des, scope, use_path, net, par, eve, ex1, ex2); + if (net == 0) { + if (debug_elaborate) + cerr << get_fileline() << ": PEIdent::test_width_method_: " + << "Only nets can have methods, so give up here." << endl; + return 0; + } + + if (/*const netdarray_t*dtype =*/ net->darray_type()) { + if (member_name == "size") { + expr_type_ = IVL_VT_BOOL; + expr_width_ = 32; + min_width_ = 32; + signed_flag_= true; + return 32; + } + } + + return 0; +} + unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) { NetNet* net = 0; @@ -2801,6 +2931,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) ivl_assert(*this, use_scope); } + if (unsigned tmp = test_width_method_(des, scope, mode)) { + return tmp; + } + NetScope*found_in = symbol_search(this, des, use_scope, path_, net, par, eve, ex1, ex2); @@ -2845,23 +2979,38 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) const index_component_t&index_tail = name_tail.index.back(); ivl_assert(*this, index_tail.msb); } - use_width = 1; + // If we have a net in hand, then we can predict what the + // slice width will be. If not, then assume it will be a + // simple bit select. If the net only has a single dimension + // then this is still a simple bit select. + if ((net == 0) || (net->packed_dimensions() <= 1)) + use_width = 1; break; + case index_component_t::SEL_BIT_LAST: + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::test_width: " + << "Queue/Darray last index ($)" << endl; + } + break; default: ivl_assert(*this, 0); } if (const netdarray_t*darray = net? net->darray_type() : 0) { - if (use_sel == index_component_t::SEL_BIT) { + switch (use_sel) { + case index_component_t::SEL_BIT: + case index_component_t::SEL_BIT_LAST: expr_type_ = darray->element_base_type(); expr_width_ = darray->element_width(); min_width_ = expr_width_; signed_flag_ = net->get_signed(); - } else { + break; + default: expr_type_ = net->data_type(); expr_width_ = net->vector_width(); min_width_ = expr_width_; signed_flag_ = net->get_signed(); + break; } return expr_width_; } @@ -2877,15 +3026,35 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) // The width of a signal expression is the width of the signal. if (net != 0) { + size_t use_depth = name_tail.index.size(); + // Account for unpacked dimensions by assuming that the + // unpacked dimensions are consumed first, so subtract + // the unpacked dimensions from the dimension depth + // useable for making the slice. + if (use_depth >= net->unpacked_dimensions()) { + use_depth -= net->unpacked_dimensions(); + + } else { + // In this case, we have a slice of an unpacked + // array. This likely handled as an array instead + // of a slice. Hmm... + use_depth = 0; + } + expr_type_ = net->data_type(); - expr_width_ = net->vector_width(); + expr_width_ = net->slice_width(use_depth); min_width_ = expr_width_; 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; + << ", width=" << expr_width_ + << ", signed_=" << (signed_flag_?"true":"false") + << ", use_depth=" << use_depth + << ", packed_dimensions=" << net->packed_dimensions() + << ", unpacked_dimensions=" << net->unpacked_dimensions() + << endl; } return expr_width_; } @@ -3000,8 +3169,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, - ivl_type_t ntype, unsigned) const + ivl_type_t ntype, unsigned flags) const { + bool need_const = NEED_CONST & flags; + NetNet* net = 0; const NetExpr*par = 0; NetEvent* eve = 0; @@ -3013,6 +3184,10 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, ivl_assert(*this, use_scope); } + if (NetExpr* tmp = elaborate_expr_class_member_(des, scope, 0, flags)) { + return tmp; + } + /* NetScope*found_in = */ symbol_search(this, des, use_scope, path_, net, par, eve, ex1, ex2); @@ -3072,7 +3247,69 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, } ivl_assert(*this, ntype->type_compatible(net->net_type())); - NetESignal*tmp = new NetESignal(net); + const name_component_t&use_comp = path_.back(); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr: " + << "Typed ident " << net->name() + << " with " << use_comp.index.size() << " indices" + << " and " << net->unpacked_dimensions() << " expected." + << endl; + } + + if (net->unpacked_dimensions() != use_comp.index.size()) { + cerr << get_fileline() << ": sorry: " + << "Net " << net->name() + << " expects " << net->unpacked_dimensions() + << ", but got " << use_comp.index.size() << "." + << endl; + des->errors += 1; + + NetESignal*tmp = new NetESignal(net); + tmp->set_line(*this); + return tmp; + } + + if (net->unpacked_dimensions() == 0) { + NetESignal*tmp = new NetESignal(net); + tmp->set_line(*this); + return tmp; + } + + // Convert a set of index expressions to a single expression + // that addresses the canonical element. + listunpacked_indices; + list unpacked_indices_const; + indices_flags idx_flags; + indices_to_expressions(des, scope, this, + use_comp.index, net->unpacked_dimensions(), + need_const, net->unpacked_count(), + idx_flags, + unpacked_indices, + unpacked_indices_const); + + NetExpr*canon_index = 0; + + if (idx_flags.invalid) { + // Nothing to do + + } else if (idx_flags.undefined) { + cerr << get_fileline() << ": warning: " + << "returning 'bx for undefined array access " + << net->name() << as_indices(unpacked_indices) + << "." << endl; + + } else if (idx_flags.variable) { + ivl_assert(*this, unpacked_indices.size() == net->unpacked_dimensions()); + canon_index = normalize_variable_unpacked(net, unpacked_indices); + + } else { + ivl_assert(*this, unpacked_indices_const.size() == net->unpacked_dimensions()); + canon_index = normalize_variable_unpacked(net, unpacked_indices_const); + } + + ivl_assert(*this, canon_index); + NetESignal*tmp = new NetESignal(net, canon_index); tmp->set_line(*this); return tmp; @@ -3094,19 +3331,24 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, if (path_.size() != 1) return 0; - const netclass_t*class_type = scope->parent()->class_def(); + const netclass_t*class_type = find_class_containing_scope(*this, scope); if (class_type == 0) return 0; - perm_string member_name = peek_tail_name(path_); + const name_component_t&name_comp = path_.back(); + + perm_string member_name = name_comp.name; int pidx = class_type->property_idx_from_name(member_name); if (pidx < 0) return 0; - NetNet*this_net = scope->find_signal(perm_string::literal("@")); + NetScope*scope_method = find_method_containing_scope(*this, scope); + ivl_assert(*this, scope_method); + + NetNet*this_net = scope_method->find_signal(perm_string::literal("@")); if (this_net == 0) { cerr << get_fileline() << ": internal error: " - << "Unable to find 'this' port of " << scope_path(scope) + << "Unable to find 'this' port of " << scope_path(scope_method) << "." << endl; return 0; } @@ -3116,7 +3358,8 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, << "Found member " << member_name << " is a member of class " << class_type->get_name() << ", context scope=" << scope_path(scope) - << ", so synthesizing a NetEProperty." << endl; + << ", type=" << *class_type->get_prop_type(pidx) + << ", so making a NetEProperty." << endl; } property_qualifier_t qual = class_type->get_prop_qual(pidx); @@ -3132,11 +3375,98 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, return class_static_property_expression(this, class_type, member_name); } - NetEProperty*tmp = new NetEProperty(this_net, member_name); + NetExpr*canon_index = 0; + ivl_type_t tmp_type = class_type->get_prop_type(pidx); + if (const netuarray_t*tmp_ua = dynamic_cast(tmp_type)) { + + const std::vector&dims = tmp_ua->static_dimensions(); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member_: " + << "Property " << class_type->get_prop_name(pidx) + << " has " << dims.size() << " dimensions, " + << " got " << name_comp.index.size() << " indices." << endl; + } + + if (dims.size() != name_comp.index.size()) { + cerr << get_fileline() << ": error: " + << "Got " << name_comp.index.size() << " indices, " + << "expecting " << dims.size() + << " to index the property " << class_type->get_prop_name(pidx) << "." << endl; + des->errors += 1; + + } else { + + canon_index = make_canonical_index(des, scope, this, + name_comp.index, tmp_ua, false); + } + } + + if (debug_elaborate && canon_index) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member_: " + << "Property " << class_type->get_prop_name(pidx) + << " canonical index: " << *canon_index << endl; + } + + NetEProperty*tmp = new NetEProperty(this_net, member_name, canon_index); tmp->set_line(*this); return tmp; } +NetExpr* PEIdent::elaborate_expr_method_(Design*des, NetScope*scope, + unsigned, unsigned) const +{ + if (!gn_system_verilog()) + return 0; + if (path_.size() < 2) + return 0; + + pform_name_t use_path = path_; + perm_string member_name = peek_tail_name(path_); + use_path.pop_back(); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: " + << "Try to find method=" << member_name + << " of signal " << use_path << endl; + } + + NetNet*net = 0; + const NetExpr*par = 0; + NetEvent*eve = 0; + const NetExpr*ex1 = 0, *ex2 = 0; + symbol_search(this, des, scope, use_path, net, par, eve, ex1, ex2); + if (net == 0) { + if (debug_elaborate) + cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: " + << "Only nets can have methods, so give up here." << endl; + return 0; + } + + if (net->darray_type()) { + if (member_name == "size") { + NetESFunc*fun = new NetESFunc("$size", IVL_VT_BOOL, 32, 1); + fun->set_line(*this); + + NetESignal*arg = new NetESignal(net); + arg->set_line(*net); + + fun->parm(0, arg); + return fun; + } + + return 0; + } + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_method_: " + << "Give up trying to find method " << member_name + << " of " << path_ << "." << endl; + } + + return 0; +} + /* * 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 @@ -3197,6 +3527,14 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, ivl_assert(*this, use_scope); } + // Special case: Detect the special situation that the name is + // a method of an object (including built-in methods) that has + // no arguments. For example, "foo.size" is the call to the + // size() method if foo is an array type. + if (NetExpr*tmp = elaborate_expr_method_(des, scope, expr_wid, flags)) { + return tmp; + } + NetScope*found_in = symbol_search(this, des, use_scope, path_, net, par, eve, ex1, ex2); @@ -3241,6 +3579,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, if (!tmp) return 0; + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr: " + << "Expression as net. expr_wid=" << expr_wid + << ", tmp->expr_width()=" << tmp->expr_width() + << ", tmp=" << *tmp << endl; + } + tmp = pad_to_width(tmp, expr_wid, *this); tmp->cast_signed(signed_flag_); @@ -3898,6 +4243,8 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, return 0; } + ivl_assert(*this, use_sel != index_component_t::SEL_BIT_LAST); + if (use_sel == index_component_t::SEL_BIT) return elaborate_expr_param_bit_(des, scope, par, found_in, par_msb, par_lsb, need_const); @@ -3988,7 +4335,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, if (name_tail.index.empty()) { cerr << get_fileline() << ": error: Array " << path() - << " Needs an array index here." << endl; + << " needs an array index here." << endl; des->errors += 1; return 0; } @@ -4458,6 +4805,15 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, // making a mux part in the netlist. if (NetEConst*msc = dynamic_cast (mux)) { + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_net_bit_: " + << "mux is constant=" << *msc + << ", packed_dims()=" << net->sig()->packed_dims() + << ", packed_dims().size()=" << net->sig()->packed_dims().size() + << ", prefix_indices.size()=" << prefix_indices.size() + << endl; + } + // Special case: The bit select expression is constant // x/z. The result of the expression is 1'bx. if (! msc->value().is_defined()) { @@ -4475,6 +4831,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, << endl; } + // FIXME: Should I be using slice_width() here? NetEConst*tmp = make_const_x(1); tmp->set_line(*this); delete mux; @@ -4566,6 +4923,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, if (net->vector_width() == 1) return net; + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr_net_bit_: " + << "Make bit select idx=" << idx + << endl; + } + // Make an expression out of the index NetEConst*idx_c = new NetEConst(verinum(idx)); idx_c->set_line(*net); @@ -4610,6 +4973,29 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return ss; } +NetExpr* PEIdent::elaborate_expr_net_bit_last_(Design*, NetScope*, + NetESignal*net, + NetScope* /* found_in */, + bool need_const) const +{ + if (need_const) { + cerr << get_fileline() << ": error: " + << "Expression with \"[$]\" is not constant." << endl; + return 0; + } + + unsigned use_width = 1; + if (const netdarray_t*darray = net->sig()->darray_type()) { + use_width = darray->element_width(); + } + + NetELast*mux = new NetELast(net->sig()); + mux->set_line(*this); + NetESelect*ss = new NetESelect(net, mux, use_width); + ss->set_line(*this); + return ss; +} + NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, NetNet*net, NetScope*found_in, unsigned expr_wid, @@ -4662,6 +5048,10 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, return elaborate_expr_net_bit_(des, scope, node, found_in, need_const); + if (use_sel == index_component_t::SEL_BIT_LAST) + return elaborate_expr_net_bit_last_(des, scope, node, found_in, + need_const); + // It's not anything else, so this must be a simple identifier // expression with no part or bit select. Return the signal // itself as the expression. @@ -4740,6 +5130,8 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope, const netclass_t*ctype, NetExpr*obj, unsigned /*flags*/) const { + ivl_assert(*this, ctype); + // If there is an initializer function, then pass the object // through that function first. Note that the initializer // function has no arguments other than the object itself. @@ -4777,6 +5169,12 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope, NetFuncDef*def = new_scope->func_def(); + if (def == 0) { + cerr << get_fileline() << ": internal error: " + << "Scope " << scope_path(new_scope) + << " is missing constructor definition." << endl; + des->errors += 1; + } ivl_assert(*this, def); // Are there too many arguments passed to the function. If so, diff --git a/elab_lval.cc b/elab_lval.cc index b7d3bc4c2..b62c201b2 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -27,6 +27,7 @@ # include "netstruct.h" # include "netclass.h" # include "netdarray.h" +# include "netparray.h" # include "netvector.h" # include "compiler.h" # include @@ -397,23 +398,49 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, if (path_.size() != 1) return 0; - const netclass_t*class_type = scope->parent()->class_def(); + const netclass_t*class_type = find_class_containing_scope(*this, scope); if (class_type == 0) return 0; - perm_string member_name = peek_tail_name(path_); + const name_component_t&name_comp = path_.back(); + + perm_string member_name = name_comp.name; int pidx = class_type->property_idx_from_name(member_name); if (pidx < 0) return 0; - NetNet*this_net = scope->find_signal(perm_string::literal("@")); + NetScope*scope_method = find_method_containing_scope(*this, scope); + ivl_assert(*this, scope_method); + + NetNet*this_net = scope_method->find_signal(perm_string::literal("@")); if (this_net == 0) { cerr << get_fileline() << ": internal error: " - << "Unable to find 'this' port of " << scope_path(scope) + << "Unable to find 'this' port of " << scope_path(scope_method) << "." << endl; return 0; } + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: " + << "Ident " << member_name + << " is a property of class " << class_type->get_name() << endl; + } + + NetExpr*canon_index = 0; + if (! name_comp.index.empty()) { + ivl_type_t property_type = class_type->get_prop_type(pidx); + + if (const netsarray_t* stype = dynamic_cast (property_type)) { + canon_index = make_canonical_index(des, scope, this, + name_comp.index, stype, false); + + } else { + cerr << get_fileline() << ": error: " + << "Index expressions don't apply to this type of property." << endl; + des->errors += 1; + } + } + // Detect assignment to constant properties. Note that the // initializer constructor MAY assign to constant properties, // as this is how the property gets its value. @@ -448,8 +475,34 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, } } + ivl_type_t tmp_type = class_type->get_prop_type(pidx); + if (const netuarray_t*tmp_ua = dynamic_cast(tmp_type)) { + + const std::vector&dims = tmp_ua->static_dimensions(); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: " + << "Property " << class_type->get_prop_name(pidx) + << " has " << dims.size() << " dimensions, " + << " got " << name_comp.index.size() << " indices." << endl; + if (canon_index) { + cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: " + << "Canonical index is:" << *canon_index << endl; + }; + } + + if (dims.size() != name_comp.index.size()) { + cerr << get_fileline() << ": error: " + << "Got " << name_comp.index.size() << " indices, " + << "expecting " << dims.size() + << " to index the property " << class_type->get_prop_name(pidx) << "." << endl; + des->errors += 1; + } + } + NetAssign_*this_lval = new NetAssign_(this_net); this_lval->set_property(member_name); + if (canon_index) this_lval->set_word(canon_index); return this_lval; } diff --git a/elab_net.cc b/elab_net.cc index 769815809..64711d97d 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -501,6 +501,10 @@ 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; + // Set this to true if we calculate the word index. This is + // used to distinguish between unpacked array assignment and + // array word assignment. + bool widx_flag = false; list unpacked_indices_const; @@ -555,8 +559,9 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, packed_base = collapse_array_indices(des, scope, sig, tmp_index); if (debug_elaborate) { - cerr << get_fileline() << ": debug: " - << "packed_base expression = " << *packed_base << endl; + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " + << "packed_base=" << *packed_base + << ", member_off=" << member_off << endl; } } @@ -590,13 +595,31 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, midx = lidx + tmp_wid - 1; } + } else if (gn_system_verilog() && sig->unpacked_dimensions() > 0 && path_tail.index.empty()) { + + // In this case, we are doing a continuous assignment to + // an unpacked array. The NetNet representation is a + // NetNet with a pin for each array element, so there is + // nothing more needed here. + // + // This can come up from code like this: + // logic [...] data [0:3]; + // assign data = ...; + // In this case, "sig" is "data", and sig->pin_count() + // is 4 to account for the unpacked size. + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " + << "Net assign to unpacked array \"" << sig->name() + << "\" with " << sig->pin_count() << " elements." << endl; + } + } 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; + << " but got only " << path_tail.index.size() << ". (net)" << endl; des->errors += 1; return 0; } @@ -627,6 +650,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, << sig->name() << as_indices(unpacked_indices) << "." << endl; widx = -1; + widx_flag = true; } else { NetExpr*canon_index = 0; @@ -639,12 +663,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, << sig->name() << as_indices(unpacked_indices_const) << "." << endl; widx = -1; + widx_flag = true; } else { NetEConst*canon_const = dynamic_cast(canon_index); ivl_assert(*this, canon_const); widx = canon_const->value().as_long(); + widx_flag = true; delete canon_index; } } @@ -682,6 +708,16 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, } } else if (!path_tail.index.empty()) { + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: " + << "path_tail.index.size()=" << path_tail.index.size() + << endl; + } + + // There are index expressions on the name, so this is a + // bit/slice select of the name. Calculate a canonical + // part select. + if (sig->get_scalar()) { cerr << get_fileline() << ": error: " << "can not select part of "; @@ -710,14 +746,21 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, unsigned subnet_wid = midx-lidx+1; /* Check if the l-value bits are double-driven. */ - if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx)) { + if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx, widx_flag? widx : 0)) { cerr << get_fileline() << ": error: Unresolved net/uwire " << sig->name() << " cannot have multiple drivers." << endl; + if (debug_elaborate) { + cerr << get_fileline() << ": : Overlap in " + << "[" << midx << ":" << lidx << "] (canonical)" + << ", widx=" << (widx_flag? widx : 0) + << ", vector width=" << sig->vector_width() + << endl; + } des->errors += 1; return 0; } - if (sig->pin_count() > 1) { + if (sig->pin_count() > 1 && widx_flag) { if (widx < 0 || widx >= (long) sig->pin_count()) return 0; @@ -729,6 +772,13 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, tmp->local_flag(true); connect(sig->pin(widx), tmp->pin(0)); sig = tmp; + + } else if (sig->pin_count() > 1) { + + // If this turns out to be an l-value unpacked array, + // then let the caller handle it. It will probably be + // converted into an array of assignments. + return sig; } /* If the desired l-value vector is narrower than the @@ -851,6 +901,33 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const long midx; long lidx; + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_subport: " + << "path_ = \"" << path_ + << "\", unpacked_dimensions=" << sig->unpacked_dimensions() + << ", port_type()=" << sig->port_type() << endl; + } + + if (sig->unpacked_dimensions() && !gn_system_verilog()) { + cerr << get_fileline() << ": error: " + << "Ports cannot be unpacked arrays. Try enabling SystemVerilog support." << endl; + des->errors += 1; + return 0; + } + + // There cannot be parts to an unpacked array, so process this + // simply as an unpacked array. + if (sig->unpacked_dimensions()) { + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_subport: " + << "path_=\"" << path_ + << "\" is an unpacked array with " << sig->pin_count() + << " elements." << endl; + } + scope->add_module_port_net(sig); + return sig; + } + /* Evaluate the part/bit select expressions, to get the part select of the signal that attaches to the port. Also handle range and direction checking here. */ @@ -912,6 +989,20 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const return sig; } +NetNet*PEIdent::elaborate_unpacked_net(Design*des, NetScope*scope) const +{ + NetNet* sig = 0; + const NetExpr*par = 0; + NetEvent* eve = 0; + perm_string method_name; + + symbol_search(this, des, scope, path_, sig, par, eve); + + ivl_assert(*this, sig); + + return sig; +} + bool PEIdent::is_collapsible_net(Design*des, NetScope*scope) const { assert(scope); diff --git a/elab_scope.cc b/elab_scope.cc index 0701a09d8..3c4c43e69 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -425,6 +425,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) netclass_t*use_base_class = 0; if (base_class) { + ivl_assert(*pclass, scope); use_base_class = scope->find_class(base_class->name); if (use_base_class == 0) { cerr << pclass->get_fileline() << ": error: " @@ -436,6 +437,9 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) netclass_t*use_class = new netclass_t(use_type->name, use_base_class); + ivl_assert(*pclass, use_type->save_elaborated_type == 0); + use_type->save_elaborated_type = use_class; + // Class scopes have no parent scope, because references are // not allowed to escape a class method. NetScope*class_scope = new NetScope(0, hname_t(pclass->pscope_name()), @@ -443,18 +447,22 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) class_scope->set_line(pclass); class_scope->set_class_def(use_class); use_class->set_class_scope(class_scope); + use_class->set_definition_scope(scope); // Collect the properties, elaborate them, and add them to the // elaborated class definition. for (map::iterator cur = use_type->properties.begin() ; cur != use_type->properties.end() ; ++ cur) { - if (debug_scopes) { - cerr << pclass->get_fileline() << ": elaborate_scope_class: " - << " Property " << cur->first << endl; - } + ivl_type_s*tmp = cur->second.type->elaborate_type(des, scope); ivl_assert(*pclass, tmp); + if (debug_scopes) { + cerr << pclass->get_fileline() << ": elaborate_scope_class: " + << " Property " << cur->first + << " type=" << *tmp << endl; + } use_class->set_property(cur->first, cur->second.qual, tmp); + } for (map::iterator cur = pclass->tasks.begin() @@ -493,7 +501,12 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) cur->second->elaborate_scope(des, method_scope); } - scope->add_class(use_class); + if (scope) { + scope->add_class(use_class); + + } else { + des->add_class(use_class, pclass); + } } static void elaborate_scope_classes(Design*des, NetScope*scope, @@ -505,6 +518,18 @@ static void elaborate_scope_classes(Design*des, NetScope*scope, } } +void elaborate_rootscope_classes(Design*des) +{ + if (pform_classes.empty()) + return; + + for (map::iterator cur = pform_classes.begin() + ; cur != pform_classes.end() ; ++ cur) { + blend_class_constructors(cur->second); + elaborate_scope_class(des, 0, cur->second); + } +} + static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc, const Module::replace_t&replacements) { @@ -546,6 +571,25 @@ static void elaborate_scope_events_(Design*des, NetScope*scope, } } +static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task) +{ + hname_t use_name( task->pscope_name() ); + + NetScope*task_scope = new NetScope(scope, use_name, NetScope::TASK); + task_scope->is_auto(task->is_auto()); + task_scope->set_line(task); + + if (scope==0) + des->add_root_task(task_scope, task); + + if (debug_scopes) { + cerr << task->get_fileline() << ": elaborate_scope_task: " + << "Elaborate task scope " << scope_path(task_scope) << endl; + } + + task->elaborate_scope(des, task_scope); +} + static void elaborate_scope_tasks(Design*des, NetScope*scope, const map&tasks) { @@ -587,19 +631,30 @@ static void elaborate_scope_tasks(Design*des, NetScope*scope, des->errors += 1; } - NetScope*task_scope = new NetScope(scope, use_name, - NetScope::TASK); - task_scope->is_auto((*cur).second->is_auto()); - task_scope->set_line((*cur).second); - - if (debug_scopes) - cerr << cur->second->get_fileline() << ": debug: " - << "Elaborate task scope " << scope_path(task_scope) << endl; - (*cur).second->elaborate_scope(des, task_scope); + elaborate_scope_task(des, scope, cur->second); } } +static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task) +{ + hname_t use_name( task->pscope_name() ); + + NetScope*task_scope = new NetScope(scope, use_name, NetScope::FUNC); + task_scope->is_auto(task->is_auto()); + task_scope->set_line(task); + + if (scope==0) + des->add_root_task(task_scope, task); + + if (debug_scopes) { + cerr << task->get_fileline() << ": elaborate_scope_func: " + << "Elaborate task scope " << scope_path(task_scope) << endl; + } + + task->elaborate_scope(des, task_scope); +} + static void elaborate_scope_funcs(Design*des, NetScope*scope, const map&funcs) { @@ -642,19 +697,33 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope, des->errors += 1; } - NetScope*func_scope = new NetScope(scope, use_name, - NetScope::FUNC); - func_scope->is_auto((*cur).second->is_auto()); - func_scope->set_line((*cur).second); - - if (debug_scopes) - cerr << cur->second->get_fileline() << ": debug: " - << "Elaborate function scope " << scope_path(func_scope) << endl; - (*cur).second->elaborate_scope(des, func_scope); + elaborate_scope_func(des, scope, cur->second); } } +void elaborate_rootscope_tasks(Design*des) +{ + for (map::iterator cur = pform_tasks.begin() + ; cur != pform_tasks.end() ; ++ cur) { + + if (PTask*task = dynamic_cast (cur->second)) { + elaborate_scope_task(des, 0, task); + continue; + } + + if (PFunction*func = dynamic_cast(cur->second)) { + elaborate_scope_func(des, 0, func); + continue; + } + + cerr << cur->second->get_fileline() << ": internal error: " + << "elabortae_rootscope_tasks does not understand " + << "this object," << endl; + des->errors += 1; + } +} + class generate_schemes_work_item_t : public elaborator_work_item_t { public: generate_schemes_work_item_t(Design*des__, NetScope*scope, Module*mod) @@ -690,12 +759,14 @@ class generate_schemes_work_item_t : public elaborator_work_item_t { bool PPackage::elaborate_scope(Design*des, NetScope*scope) { if (debug_scopes) { - cerr << get_fileline() << ": debug: Elaborate package scope " - << scope_path(scope) << "." << endl; + cerr << get_fileline() << ": PPackage::elaborate_scope: " + << "Elaborate package " << scope_path(scope) << "." << endl; } collect_scope_parameters_(des, scope, parameters); collect_scope_localparams_(des, scope, localparams); + elaborate_scope_enumerations(des, scope, enum_sets); + elaborate_scope_classes(des, scope, classes_lexical); elaborate_scope_funcs(des, scope, funcs); elaborate_scope_tasks(des, scope, tasks); return true; @@ -705,8 +776,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, const replace_t&replacements) { if (debug_scopes) { - cerr << get_fileline() << ": debug: Elaborate scope " - << scope_path(scope) << "." << endl; + cerr << get_fileline() << ": Module::elaborate_scope: " + << "Elaborate " << scope_path(scope) << "." << endl; } // Add the genvars to the scope. @@ -892,8 +963,10 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) // Check the generate block name. - // A generate "loop" can not have the same name as another scope object. - const NetScope *child = container->child(hname_t(scope_name)); + // A generate "loop" can not have the same name as another + // scope object. Find any scope with this name, not just an + // exact match scope. + const NetScope *child = container->child_byname(scope_name); if (child) { cerr << get_fileline() << ": error: generate \"loop\" and "; child->print_type(cerr); @@ -1897,6 +1970,18 @@ void PEventStatement::elaborate_scope(Design*des, NetScope*scope) const statement_ -> elaborate_scope(des, scope); } +/* + * The standard says that we create an implicit scope for foreach + * loops, but that is just to hold the index variables, and we'll + * handle them by creating unique names. So just jump into the + * contained statement for scope elaboration. + */ +void PForeach::elaborate_scope(Design*des, NetScope*scope) const +{ + if (statement_) + statement_ -> elaborate_scope(des, scope); +} + /* * Statements that contain a further statement but do not * intrinsically add a scope need to elaborate_scope the contained diff --git a/elab_sig.cc b/elab_sig.cc index 4b8b0ec36..87c5c9b80 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -41,6 +41,7 @@ # include "netvector.h" # include "netdarray.h" # include "netparray.h" +# include "netqueue.h" # include "util.h" # include "ivl_assert.h" @@ -206,6 +207,11 @@ bool PPackage::elaborate_sig(Design*des, NetScope*scope) const { bool flag = true; + if (debug_elaborate) { + cerr << get_fileline() << ": PPackage::elaborate_sig: " + << "Start package scope=" << scope_path(scope) << endl; + } + flag = elaborate_sig_wires_(des, scope) && flag; // After all the wires are elaborated, we are free to @@ -214,6 +220,13 @@ bool PPackage::elaborate_sig(Design*des, NetScope*scope) const elaborate_sig_funcs(des, scope, funcs); elaborate_sig_tasks(des, scope, tasks); + elaborate_sig_classes(des, scope, classes); + + if (debug_elaborate) { + cerr << get_fileline() << ": PPackage::elaborate_sig: " + << "Done package scope=" << scope_path(scope) + << ", flag=" << flag << endl; + } return flag; } @@ -563,7 +576,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const // Special case: this is a constructor, so the return // signal is also the first argument. For example, the // source code for the definition may be: - // function new(...); + // function new(...); // endfunction // In this case, the "@" port is the synthetic "this" // argument and we also use it as a return value at the @@ -594,6 +607,11 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const } if (ret_type) { + if (debug_elaborate) { + cerr << get_fileline() << ": PFunction::elaborate_sig: " + << "return type: " << *ret_type << endl; + return_type_->pform_dump(cerr, 8); + } list ret_unpacked; ret_sig = new NetNet(scope, fname, NetNet::REG, ret_unpacked, ret_type); @@ -615,9 +633,10 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const NetFuncDef*def = new NetFuncDef(scope, ret_sig, ports, pdef); if (debug_elaborate) - cerr << get_fileline() << ": debug: " - << "Attach function definition to scope " - << scope_path(scope) << "." << endl; + cerr << get_fileline() << ": PFunction::elaborate_sig: " + << "Attach function definition " << scope_path(scope) + << " with ret_sig width=" << (ret_sig? ret_sig->vector_width() : 0) + << "." << endl; scope->set_func_def(def); @@ -799,6 +818,12 @@ void PEventStatement::elaborate_sig(Design*des, NetScope*scope) const statement_->elaborate_sig(des, scope); } +void PForeach::elaborate_sig(Design*des, NetScope*scope) const +{ + if (statement_) + statement_->elaborate_sig(des, scope); +} + void PForever::elaborate_sig(Design*des, NetScope*scope) const { if (statement_) @@ -823,55 +848,6 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const statement_->elaborate_sig(des, scope); } -static bool evaluate_ranges(Design*des, NetScope*scope, - vector&llist, - const list&rlist) -{ - bool bad_msb = false, bad_lsb = false; - - for (list::const_iterator cur = rlist.begin() - ; cur != rlist.end() ; ++cur) { - long use_msb, use_lsb; - - NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); - if (! eval_as_long(use_msb, texpr)) { - cerr << cur->first->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << cur->first->get_fileline() << " : " - "This MSB expression violates the rule: " - << *cur->first << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, cur->second, -1, true); - if (! eval_as_long(use_lsb, texpr)) { - cerr << cur->second->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << cur->second->get_fileline() << " : " - "This LSB expression violates the rule: " - << *cur->second << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; - - llist.push_back(netrange_t(use_msb, use_lsb)); - } - - return bad_msb | bad_lsb; -} - -static netclass_t* locate_class_type(Design*, NetScope*scope, - class_type_t*class_type) -{ - netclass_t*use_class = scope->find_class(class_type->name); - return use_class; -} - static ivl_type_s*elaborate_type(Design*des, NetScope*scope, data_type_t*pform_type) { @@ -949,7 +925,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const des->errors += error_cnt_; // A signal can not have the same name as a scope object. - const NetScope *child = scope->child(hname_t(name_)); + const NetScope *child = scope->child_byname(name_); if (child) { cerr << get_fileline() << ": error: signal and "; child->print_type(cerr); @@ -1078,7 +1054,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const listunpacked_dimensions; - netdarray_t*netarray = 0; + netdarray_t*netdarray = 0; for (list::const_iterator cur = unpacked_.begin() ; cur != unpacked_.end() ; ++cur) { @@ -1091,13 +1067,23 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const 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); + ivl_assert(*this, netdarray==0); + netdarray = new netdarray_t(vec); + continue; + } + + // Special case: Detect the mark for a QUEUE + // declaration, which is the dimensions [null:]. + if (use_ridx==0 && dynamic_cast(use_lidx)) { + netvector_t*vec = new netvector_t(packed_dimensions, data_type_); + packed_dimensions.clear(); + ivl_assert(*this, netdarray==0); + netdarray = new netqueue_t(vec); continue; } // Cannot handle dynamic arrays of arrays yet. - ivl_assert(*this, netarray==0); + ivl_assert(*this, netdarray==0); ivl_assert(*this, use_lidx && use_ridx); NetExpr*lexp = elab_and_eval(des, scope, use_lidx, -1, true); @@ -1190,22 +1176,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const // 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); - if (use_type == 0) { - cerr << get_fileline() << ": internal error: " - << "Class " << class_type->name - << " isn't elaborated in scope=" << scope_path(scope) << endl; - des->errors += 1; - } - ivl_assert(*this, use_type); - if (debug_elaborate) { - cerr << get_fileline() << ": debug: " - << "Create class instance signal " << wtype - << " " << name_ << endl; - } - // (No arrays of classes) - list use_unpacked; - sig = new NetNet(scope, name_, wtype, use_unpacked, use_type); + + ivl_assert(*this, class_type->save_elaborated_type); + netclass_t*use_type = class_type->save_elaborated_type; + + sig = new NetNet(scope, name_, wtype, unpacked_dimensions, 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 @@ -1226,7 +1201,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } else if (enum_type_t*enum_type = dynamic_cast(set_data_type_)) { list::const_iterator sample_name = enum_type->names->begin(); - const netenum_t*use_enum = scope->enumeration_for_name(sample_name->name); + const netenum_t*use_enum = scope->find_enumeration_for_name(sample_name->name); if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype @@ -1240,7 +1215,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig = new NetNet(scope, name_, wtype, unpacked_dimensions, use_enum); - } else if (netarray) { + } else if (netdarray) { if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype @@ -1250,7 +1225,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const ivl_assert(*this, packed_dimensions.empty()); ivl_assert(*this, unpacked_dimensions.empty()); - sig = new NetNet(scope, name_, wtype, netarray); + sig = new NetNet(scope, name_, wtype, netdarray); } else if (parray_type_t*parray_type = dynamic_cast(set_data_type_)) { // The pform gives us a parray_type_t for packed arrays @@ -1266,7 +1241,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype - << " parray=" << use_type->packed_dimensions() + << " parray=" << use_type->static_dimensions() << " " << name_ << unpacked_dimensions << " in scope " << scope_path(scope) << endl; } @@ -1321,3 +1296,27 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const return sig; } + + +void Design::root_elaborate_sig(void) +{ + for (map::const_iterator cur = classes_.begin() + ; cur != classes_.end() ; ++ cur) { + + netclass_t*cur_class = cur->second; + PClass*cur_pclass = class_to_pclass_[cur_class]; + + cur_class->elaborate_sig(this, cur_pclass); + } + + for (map::iterator cur = root_tasks_.begin() + ; cur != root_tasks_.end() ; ++ cur) { + + if (debug_elaborate) { + cerr << cur->second->get_fileline() << ": root_elaborate_sig: " + << "Elaborate_sig for root task/func " << scope_path(cur->first) << endl; + } + + cur->second->elaborate_sig(this, cur->first); + } +} diff --git a/elab_type.cc b/elab_type.cc index c4c97eaa7..09e0c86da 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -22,6 +22,7 @@ # include "netclass.h" # include "netdarray.h" # include "netenum.h" +# include "netparray.h" # include "netscalar.h" # include "netstruct.h" # include "netvector.h" @@ -31,6 +32,25 @@ using namespace std; +/* + * Elaborations of types may vary depending on the scope that it is + * done in, so keep a per-scope cache of the results. + */ +ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*scope) +{ + Definitions*use_definitions = scope; + if (use_definitions == 0) + use_definitions = des; + + map::iterator pos = cache_type_elaborate_.lower_bound(use_definitions); + if (pos->first == use_definitions) + return pos->second; + + ivl_type_s*tmp = elaborate_type_raw(des, scope); + cache_type_elaborate_.insert(pos, pair(scope, tmp)); + return tmp; +} + ivl_type_s* data_type_t::elaborate_type_raw(Design*des, NetScope*) const { cerr << get_fileline() << ": internal error: " @@ -75,9 +95,10 @@ ivl_type_s* atom2_type_t::elaborate_type_raw(Design*des, NetScope*) const } } -ivl_type_s* class_type_t::elaborate_type_raw(Design*, NetScope*scope) const +ivl_type_s* class_type_t::elaborate_type_raw(Design*, NetScope*) const { - return scope->find_class(name); + ivl_assert(*this, save_elaborated_type); + return save_elaborated_type; } /* @@ -188,9 +209,27 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const ivl_type_t btype = base_type->elaborate_type(des, scope); - assert(dims->size() == 1); + assert(dims->size() >= 1); list::const_iterator cur = dims->begin(); - assert(cur->first == 0 && cur->second==0); - ivl_type_s*res = new netdarray_t(btype); + + // Special case: if the dimension is nil:nil, this is a + // dynamic array. Note that we only know how to handle dynamic + // arrays with 1 dimension at a time. + if (cur->first==0 && cur->second==0) { + assert(dims->size()==1); + ivl_type_s*res = new netdarray_t(btype); + return res; + } + + vector dimensions; + bool bad_range = evaluate_ranges(des, scope, dimensions, *dims); + + if (bad_range) { + cerr << get_fileline() << " : warning: " + << "Bad dimensions for type here." << endl; + } + + ivl_assert(*this, btype); + ivl_type_s*res = new netuarray_t(dimensions, btype); return res; } diff --git a/elaborate.cc b/elaborate.cc index 66f346853..3095394b6 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -40,6 +40,7 @@ # include "netlist.h" # include "netvector.h" # include "netdarray.h" +# include "netparray.h" # include "netclass.h" # include "netmisc.h" # include "util.h" @@ -77,11 +78,19 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const return; } + // If this turns out to be an assignment to an unpacked array, + // then handle that special case elsewhere. + if (lval->pin_count() > 1) { + elaborate_unpacked_array_(des, scope, lval); + return; + } + ivl_assert(*this, lval->pin_count() == 1); if (debug_elaborate) { - cerr << get_fileline() << ": debug: PGAssign: elaborated l-value" - << " width=" << lval->vector_width() << endl; + cerr << get_fileline() << ": PGAssign::elaborate: elaborated l-value" + << " width=" << lval->vector_width() + << ", pin_count=" << lval->pin_count() << endl; } NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->net_type(), @@ -211,6 +220,18 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const } +void PGAssign::elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const +{ + PEIdent*rval_pident = dynamic_cast (pin(1)); + ivl_assert(*this, rval_pident); + + NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope); + + ivl_assert(*this, rval_net->pin_count() == lval->pin_count()); + + assign_unpacked_with_bufz(des, scope, this, lval, rval_net); +} + unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope, long&high, long&low) const { @@ -1287,6 +1308,10 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const perm_string pname = peek_tail_name(mport[0]->path()); NetNet*tmp = instance[0]->find_signal(pname); + + // Handle the error case where there is no internal + // signal connected to the port. + if (!tmp) continue; assert(tmp); if (tmp->port_type() == NetNet::PINPUT) { @@ -1350,18 +1375,22 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const unsigned int prt_vector_width = 0; PortType::Enum ptype = PortType::PIMPLICIT; // Scan the module sub-ports for this instance... + // (Sub-ports are concatenated ports that form the + // single port for the instance. This is not a + // commonly used feature.) for (unsigned ldx = 0 ; ldx < mport.size() ; ldx += 1) { unsigned lbase = inst * mport.size(); PEIdent*pport = mport[ldx]; - assert(pport); + ivl_assert(*this, pport); NetNet *netnet = pport->elaborate_subport(des, inst_scope); prts[lbase + ldx] = netnet; if (netnet == 0) continue; - assert(netnet); - prts_vector_width += netnet->vector_width(); - prt_vector_width += netnet->vector_width(); + ivl_assert(*this, netnet); + unsigned port_width = netnet->vector_width() * netnet->pin_count(); + prts_vector_width += port_width; + prt_vector_width += port_width; ptype = PortType::merged(netnet->port_type(), ptype); } inst_scope->add_module_port_info(idx, rmod->get_port_name(idx), ptype, prt_vector_width ); @@ -1392,9 +1421,25 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // module[s] port. sig is the thing outside the module // that connects to the port. - NetNet*sig; + NetNet*sig = 0; if (prts.empty() || (prts[0]->port_type() == NetNet::PINPUT)) { + // Special case: If the input port is an unpacked + // array, then there should be no sub-ports and + // the r-value expression is processed + // differently. + if (prts.size() >= 1 && prts[0]->pin_count()>1) { + ivl_assert(*this, prts.size()==1); + + PEIdent*rval_pident = dynamic_cast (pins[idx]); + ivl_assert(*this, rval_pident); + + NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope); + ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count()); + assign_unpacked_with_bufz(des, scope, this, prts[0], rval_net); + continue; + } + /* Input to module. elaborate the expression to the desired width. If this in an instance array, then let the net determine its own @@ -1471,6 +1516,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } else if (prts[0]->port_type() == NetNet::PINOUT) { + // For now, do not support unpacked array outputs. + ivl_assert(*this, prts[0]->unpacked_dimensions()==0); + /* Inout to/from module. This is a more complicated case, where the expression must be an lnet, but also an r-value net. @@ -1530,6 +1578,28 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const /* Port type must be OUTPUT here. */ ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT); + // Special case: If the output port is an unpacked + // array, then there should be no sub-ports and + // the passed pexxpression is processed + // differently. Note that we are calling it the + // "r-value" expression, but since this is an + // output port, we assign to it from the internal object. + if (prts[0]->pin_count() > 1) { + ivl_assert(*this, prts.size()==1); + + PEIdent*rval_pident = dynamic_cast(pins[idx]); + ivl_assert(*this, rval_pident); + + NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope); + ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count()); + + assign_unpacked_with_bufz(des, scope, this, rval_net, prts[0]); + continue; + } + + // At this point, arrays are handled. + ivl_assert(*this, prts[0]->unpacked_dimensions()==0); + /* Output from module. Elaborate the port expression as the l-value of a continuous assignment, as the port will continuous assign @@ -2221,6 +2291,14 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const NetAssign_*lv = new NetAssign_(tmp); return lv; } + + if (debug_elaborate) { + cerr << get_fileline() << ": PAssign_::elaborate_lval: " + << "lval_ = " << *lval_ << endl; + cerr << get_fileline() << ": PAssign_::elaborate_lval: " + << "lval_ expr type = " << typeid(*lval_).name() << endl; + } + return lval_->elaborate_lval(des, scope, false, false); } @@ -2451,6 +2529,23 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const rv = elaborate_rval_(des, scope, use_lv_type); + } else if (const netuarray_t*utype = dynamic_cast(lv_net_type)) { + ivl_assert(*this, lv->more==0); + if (debug_elaborate) { + if (lv->word()) + cerr << get_fileline() << ": PAssign::elaborate: " + << "lv->word() = " << *lv->word() << endl; + else + cerr << get_fileline() << ": PAssign::elaborate: " + << "lv->word() = " << endl; + } + ivl_type_t use_lv_type = lv_net_type; + ivl_assert(*this, lv->word()); + use_lv_type = utype->element_type(); + + ivl_assert(*this, use_lv_type); + rv = elaborate_rval_(des, scope, use_lv_type); + } else { /* Elaborate the r-value expression, then try to evaluate it. */ rv = elaborate_rval_(des, scope, lv_net_type, lv->expr_type(), count_lval_width(lv)); @@ -3118,7 +3213,6 @@ NetProc* PChainConstructor::elaborate(Design*des, NetScope*scope) const NetBlock*tmp = new NetBlock(NetBlock::SEQU, 0); tmp->set_line(*this); return tmp; - return 0; } NetProc* PCondit::elaborate(Design*des, NetScope*scope) const @@ -3345,6 +3439,17 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const } assert(def); + /* In SystemVerilog a method calling another method in the + * current class needs to be elaborated as a method with an + * implicit this added. */ + if (gn_system_verilog() && (path_.size() == 1)) { + const NetScope *c_scope = scope->get_class_scope(); + if (c_scope && (c_scope == task->get_class_scope())) { + NetProc *tmp = elaborate_method_(des, scope, true); + assert(tmp); + return tmp; + } + } unsigned parm_count = def->port_count(); @@ -3359,7 +3464,45 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const return elaborate_build_call_(des, scope, task, 0); } -NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const +/* + * This private method is called to elaborate built-in methods. The + * method_name is the detected name of the built-in method, and the + * sys_task_name is the internal system-task name to use. + */ +NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope, + NetNet*net, + perm_string method_name, + const char*sys_task_name) const +{ + NetESignal*sig = new NetESignal(net); + sig->set_line(*this); + + /* If there is a single NULL argument then ignore it since it is + * left over from the parser and is not needed by the method. */ + unsigned nparms = parms_.size(); + if ((nparms == 1) && (parms_[0] == 0)) nparms = 0; + + vectorargv (1 + nparms); + argv[0] = sig; + + for (unsigned idx = 0 ; idx < nparms ; idx += 1) { + PExpr*ex = parms_[idx]; + if (ex != 0) { + argv[idx+1] = elab_sys_task_arg(des, scope, + method_name, + idx, ex); + } else { + argv[idx+1] = 0; + } + } + + NetSTask*sys = new NetSTask(sys_task_name, IVL_SFUNC_AS_TASK_IGNORE, argv); + sys->set_line(*this); + return sys; +} + +NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, + bool add_this_flag) const { pform_name_t use_path = path_; perm_string method_name = peek_tail_name(use_path); @@ -3370,6 +3513,12 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const NetEvent *eve; const NetExpr *ex1, *ex2; + /* Add the implicit this reference when requested. */ + if (add_this_flag) { + assert(use_path.empty()); + use_path.push_front(name_component_t(perm_string::literal("@"))); + } + // There is no signal to search for so this cannot be a method. if (use_path.empty()) return 0; @@ -3385,15 +3534,20 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const // Is this a delete method for dynamic arrays? if (net->darray_type() && method_name=="delete") { - NetESignal*sig = new NetESignal(net); + return elaborate_sys_task_method_(des, scope, net, + method_name, + "$ivl_darray_method$delete"); + } - 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; + if (net->queue_type()) { + if (method_name=="push_back") + return elaborate_sys_task_method_(des, scope, net, + method_name, + "$ivl_queue_method$push_back"); + if (method_name=="push_front") + return elaborate_sys_task_method_(des, scope, net, + method_name, + "$ivl_queue_method$push_front"); } if (const netclass_t*class_type = net->class_type()) { @@ -4470,6 +4624,222 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const return dev; } +static void find_property_in_class(const LineInfo&loc, const NetScope*scope, perm_string name, const netclass_t*&found_in, int&property) +{ + found_in = find_class_containing_scope(loc, scope); + property = -1; + + if (found_in==0) return; + + property = found_in->property_idx_from_name(name); + if (property < 0) { + found_in = 0; + return; + } +} + +/* + * The foreach statement can be written as a for statement like so: + * + * for ( = $low() ; <= $high() ; += 1) + * + * + * The variable is already known to be in the containing named + * block scope, which was created by the parser. + */ +NetProc* PForeach::elaborate(Design*des, NetScope*scope) const +{ + // Locate the signal for the array variable + pform_name_t array_name; + array_name.push_back(name_component_t(array_var_)); + NetNet*array_sig = des->find_signal(scope, array_name); + + // And if necessary, look for the class property that is + // referenced. + const netclass_t*class_scope = 0; + int class_property = -1; + if (array_sig == 0) + find_property_in_class(*this, scope, array_var_, class_scope, class_property); + + if (debug_elaborate && array_sig) { + cerr << get_fileline() << ": PForeach::elaborate: " + << "Found array_sig in " << scope_path(array_sig->scope()) << "." << endl; + } + + if (debug_elaborate && class_scope) { + cerr << get_fileline() << ": PForeach::elaborate: " + << "Found array_sig property (" << class_property + << ") in class " << class_scope->get_name() + << " as " << *class_scope->get_prop_type(class_property) << "." << endl; + } + + if (class_scope!=0 && class_property >= 0) { + ivl_type_t ptype = class_scope->get_prop_type(class_property); + const netsarray_t*atype = dynamic_cast (ptype); + if (atype == 0) { + cerr << get_fileline() << ": error: " + << "I can't handle the type of " << array_var_ + << " as a foreach loop." << endl; + des->errors += 1; + return 0; + } + + const std::vector&dims = atype->static_dimensions(); + if (dims.size() < index_vars_.size()) { + cerr << get_fileline() << ": error: " + << "class " << class_scope->get_name() + << " property " << array_var_ + << " has too few dimensions for foreach dimension list." << endl; + des->errors += 1; + return 0; + } + + return elaborate_static_array_(des, scope, dims); + } + + if (array_sig == 0) { + cerr << get_fileline() << ": error:" + << " Unable to find foreach array " << array_name + << " in scope " << scope_path(scope) + << "." << endl; + des->errors += 1; + return 0; + } + + ivl_assert(*this, array_sig); + + if (debug_elaborate) { + cerr << get_fileline() << ": PForeach::elaborate: " + << "Scan array " << array_sig->name() + << " of " << array_sig->data_type() + << " with " << array_sig->unpacked_dimensions() << " unpacked" + << " and " << array_sig->packed_dimensions() + << " packed dimensions." << endl; + } + + // Classic arrays are processed this way. + if (array_sig->data_type()==IVL_VT_BOOL) + return elaborate_static_array_(des, scope, array_sig->unpacked_dims()); + if (array_sig->data_type()==IVL_VT_LOGIC) + return elaborate_static_array_(des, scope, array_sig->unpacked_dims()); + if (array_sig->unpacked_dimensions() >= index_vars_.size()) + return elaborate_static_array_(des, scope, array_sig->unpacked_dims()); + + + // At this point, we know that the array is dynamic so we + // handle that slightly differently, using run-time tests. + + if (index_vars_.size() != 1) { + cerr << get_fileline() << ": sorry: " + << "Multi-index foreach loops not supported." << endl; + des->errors += 1; + } + + // Get the signal for the index variable. + pform_name_t index_name; + index_name.push_back(name_component_t(index_vars_[0])); + NetNet*idx_sig = des->find_signal(scope, index_name); + ivl_assert(*this, idx_sig); + + NetESignal*array_exp = new NetESignal(array_sig); + array_exp->set_line(*this); + + NetESignal*idx_exp = new NetESignal(idx_sig); + idx_exp->set_line(*this); + + // Make an initialization expression for the index. + NetESFunc*init_expr = new NetESFunc("$low", IVL_VT_BOOL, 32, 1); + init_expr->set_line(*this); + init_expr->parm(0, array_exp); + + // Make a condition expression: idx <= $high(array) + NetESFunc*high_exp = new NetESFunc("$high", IVL_VT_BOOL, 32, 1); + high_exp->set_line(*this); + high_exp->parm(0, array_exp); + + NetEBComp*cond_expr = new NetEBComp('L', idx_exp, high_exp); + cond_expr->set_line(*this); + + /* Elaborate the statement that is contained in the foreach + loop. */ + NetProc*sub = statement_->elaborate(des, scope); + + /* Make a step statement: idx += 1 */ + NetAssign_*idx_lv = new NetAssign_(idx_sig); + NetEConst*step_val = make_const_val(1); + NetAssign*step = new NetAssign(idx_lv, '+', step_val); + step->set_line(*this); + + NetForLoop*stmt = new NetForLoop(idx_sig, init_expr, cond_expr, sub, step); + stmt->set_line(*this); + stmt->wrap_up(); + + return stmt; +} + +/* + * This is a variant of the PForeach::elaborate() method that handles + * the case that the array has static dimensions. We can use constants + * and possibly do some optimizations. + */ +NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, + const vector&dims) const +{ + if (debug_elaborate) { + cerr << get_fileline() << ": PForeach::elaborate_static_array_: " + << "Handle as array with static dimensions." << endl; + } + + ivl_assert(*this, index_vars_.size() > 0); + ivl_assert(*this, dims.size() == index_vars_.size()); + + NetProc*sub = statement_->elaborate(des, scope); + NetForLoop*stmt = 0; + + for (int idx_idx = index_vars_.size()-1 ; idx_idx >= 0 ; idx_idx -= 1) { + const netrange_t&idx_range = dims[idx_idx]; + + // Get the $high and $low constant values for this slice + // of the array. + NetEConst*hig_expr = make_const_val_s(idx_range.get_msb()); + NetEConst*low_expr = make_const_val_s(idx_range.get_lsb()); + if (idx_range.get_msb() < idx_range.get_lsb()) { + NetEConst*tmp = hig_expr; + hig_expr = low_expr; + low_expr = tmp; + } + + hig_expr->set_line(*this); + low_expr->set_line(*this); + + pform_name_t idx_name; + idx_name.push_back(name_component_t(index_vars_[idx_idx])); + NetNet*idx_sig = des->find_signal(scope, idx_name); + ivl_assert(*this, idx_sig); + + // Make the condition expression <= $high(slice) + NetESignal*idx_expr = new NetESignal(idx_sig); + idx_expr->set_line(*this); + + NetEBComp*cond_expr = new NetEBComp('L', idx_expr, hig_expr); + cond_expr->set_line(*this); + + // Make the step statement: += 1 + NetAssign_*idx_lv = new NetAssign_(idx_sig); + NetEConst*step_val = make_const_val_s(1); + NetAssign*step = new NetAssign(idx_lv, '+', step_val); + step->set_line(*this); + + stmt = new NetForLoop(idx_sig, low_expr, cond_expr, sub, step); + stmt->set_line(*this); + stmt->wrap_up(); + + sub = stmt; + } + + return stmt? stmt : sub; +} + /* * elaborate the for loop as the equivalent while loop. This eases the * task for the target code generator. The structure is: @@ -4484,15 +4854,12 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const */ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const { - NetExpr*etmp; + NetExpr*initial_expr; assert(scope); const PEIdent*id1 = dynamic_cast(name1_); assert(id1); - NetBlock*top = new NetBlock(NetBlock::SEQU, 0); - top->set_line(*this); - /* make the expression, and later the initial assignment to the condition variable. The statement in the for loop is very specifically an assignment. */ @@ -4504,34 +4871,23 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const return 0; } assert(sig); - NetAssign_*lv = new NetAssign_(sig); /* Make the r-value of the initial assignment, and size it properly. Then use it to build the assignment statement. */ - etmp = elaborate_rval_expr(des, scope, sig->net_type(), - lv->expr_type(), lv->lwidth(), - expr1_); + initial_expr = elaborate_rval_expr(des, scope, sig->net_type(), + sig->data_type(), sig->vector_width(), + expr1_); if (debug_elaborate) { cerr << get_fileline() << ": debug: FOR initial assign: " - << sig->name() << " = " << *etmp << endl; + << sig->name() << " = " << *initial_expr << endl; } - NetAssign*init = new NetAssign(lv, etmp); - init->set_line(*this); - - top->append(init); - - NetBlock*body = new NetBlock(NetBlock::SEQU, 0); - body->set_line(*this); - /* Elaborate the statement that is contained in the for loop. If there is an error, this will return 0 and I should skip the append. No need to worry, the error has been reported so it's OK that the netlist is bogus. */ - NetProc*tmp = statement_->elaborate(des, scope); - if (tmp) - body->append(tmp); + NetProc*sub = statement_->elaborate(des, scope); /* Now elaborate the for_step statement. I really should do @@ -4539,20 +4895,19 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const really does step the variable. */ if (debug_elaborate) { cerr << get_fileline() << ": debug: Elaborate for_step statement " - << sig->name() << " = " << *etmp << endl; + << sig->name() << " = " << *initial_expr << endl; } NetProc*step = step_->elaborate(des, scope); - body->append(step); - /* Elaborate the condition expression. Try to evaluate it too, in case it is a constant. This is an interesting case worthy of a warning. */ NetExpr*ce = elab_and_eval(des, scope, cond_, -1); if (ce == 0) { - delete top; + delete sub; + delete step; return 0; } @@ -4564,10 +4919,10 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const /* All done, build up the loop. */ - NetWhile*loop = new NetWhile(ce, body); + NetForLoop*loop = new NetForLoop(sig, initial_expr, ce, sub, step); loop->set_line(*this); - top->append(loop); - return top; + loop->wrap_up(); + return loop; } /* @@ -5199,6 +5554,9 @@ bool PPackage::elaborate(Design*des, NetScope*scope) const // Elaborate task methods. elaborate_tasks(des, scope, tasks); + // Elaborate class definitions. + elaborate_classes(des, scope, classes); + return result_flag; } @@ -5626,6 +5984,28 @@ bool Design::check_proc_delay() const return result_flag; } +void Design::root_elaborate(void) +{ + for (map::const_iterator cur = classes_.begin() + ; cur != classes_.end() ; ++ cur) { + netclass_t*cur_class = cur->second; + PClass*cur_pclass = class_to_pclass_[cur_class]; + cur_class->elaborate(this, cur_pclass); + } + + for (map::iterator cur = root_tasks_.begin() + ; cur != root_tasks_.end() ; ++ cur) { + + if (debug_elaborate) { + cerr << cur->second->get_fileline() << ": Design::root_elaborate: " + << "Elaborate for root task/func " << scope_path(cur->first) << endl; + } + + cur->second->elaborate(this, cur->first); + } + +} + /* * This function is the root of all elaboration. The input is the list * of root module names. The function locates the Module definitions @@ -5657,12 +6037,19 @@ Design* elaborate(listroots) // Elaborate enum sets in $root scope. elaborate_rootscope_enumerations(des); + // Elaborate tasks and functions in $root scope. + elaborate_rootscope_tasks(des); + + // Elaborate classes in $root scope. + elaborate_rootscope_classes(des); + // Elaborate the packages. Package elaboration is simpler // because there are fewer sub-scopes involved. i = 0; for (map::iterator pac = pform_packages.begin() ; pac != pform_packages.end() ; ++ pac) { + ivl_assert(*pac->second, pac->first == pac->second->pscope_name()); NetScope*scope = des->make_package_scope(pac->first); scope->set_line(pac->second); @@ -5754,6 +6141,11 @@ Design* elaborate(listroots) } } + if (debug_elaborate) { + cerr << ": elaborate: " + << "elaboration work list done. Start processing residual defparams." << endl; + } + // Look for residual defparams (that point to a non-existent // scope) and clean them out. des->residual_defparams(); @@ -5763,6 +6155,11 @@ Design* elaborate(listroots) if (des->errors > 0) return des; + if (debug_elaborate) { + cerr << ": elaborate: " + << "Start calling Package elaborate_sig methods." << endl; + } + // With the parameters evaluated down to constants, we have // what we need to elaborate signals and memories. This pass // creates all the NetNet and NetMemory objects for declared @@ -5781,6 +6178,18 @@ Design* elaborate(listroots) } } + if (debug_elaborate) { + cerr << ": elaborate: " + << "Start calling $root elaborate_sig methods." << endl; + } + + des->root_elaborate_sig(); + + if (debug_elaborate) { + cerr << ": elaborate: " + << "Start calling root module elaborate_sig methods." << endl; + } + for (i = 0; i < root_elems.size(); i++) { Module *rmod = root_elems[i].mod; NetScope *scope = root_elems[i].scope; @@ -5812,7 +6221,9 @@ Design* elaborate(listroots) // stuff to the design that should be cleaned later. NetNet *netnet = mport[pin]->elaborate_subport(des, scope); if (netnet != 0) { - // Elaboration may actually fail with erroneous input source + // Elaboration may actually fail with + // erroneous input source + ivl_assert(*mport[pin], netnet->pin_count()==1); prt_vector_width += netnet->vector_width(); ptype = PortType::merged(netnet->port_type(), ptype); } @@ -5835,6 +6246,8 @@ Design* elaborate(listroots) rc &= pkg->elaborate(des, scope); } + des->root_elaborate(); + for (i = 0; i < root_elems.size(); i++) { Module *rmod = root_elems[i].mod; NetScope *scope = root_elems[i].scope; diff --git a/emit.cc b/emit.cc index 4da13d0d3..bd46fc5c4 100644 --- a/emit.cc +++ b/emit.cc @@ -167,6 +167,11 @@ bool NetSignExtend::emit_node(struct target_t*tgt) const return tgt->sign_extend(this); } +bool NetSubstitute::emit_node(struct target_t*tgt) const +{ + return tgt->substitute(this); +} + bool NetUReduce::emit_node(struct target_t*tgt) const { return tgt->ureduce(this); @@ -283,6 +288,11 @@ bool NetForever::emit_proc(struct target_t*tgt) const return true; } +bool NetForLoop::emit_proc(struct target_t*tgt) const +{ + return tgt->proc_block(as_block_); +} + bool NetFree::emit_proc(struct target_t*tgt) const { tgt->proc_free(this); @@ -399,14 +409,13 @@ void NetRepeat::emit_recurse(struct target_t*tgt) const void netclass_t::emit_scope(struct target_t*tgt) const { class_scope_->emit_scope(tgt); - class_scope_->emit_defs(tgt); } void NetScope::emit_scope(struct target_t*tgt) const { if (debug_emit) { cerr << "NetScope::emit_scope: " - << "Emit scope basename=" << basename() << endl; + << "Emit scope " << scope_path(this) << endl; } tgt->scope(this); @@ -451,12 +460,20 @@ bool NetScope::emit_defs(struct target_t*tgt) const { bool flag = true; + if (debug_emit) { + cerr << "NetScope::emit_defs: " + << "Emit definitions for " << scope_path(this) << endl; + } + switch (type_) { case PACKAGE: case MODULE: for (map::const_iterator cur = children_.begin() ; cur != children_.end() ; ++ cur ) flag &= cur->second->emit_defs(tgt); + for (map::const_iterator cur = classes_.begin() + ; cur != classes_.end() ; ++ cur) + flag &= cur->second->emit_defs(tgt); break; case FUNC: @@ -475,6 +492,11 @@ bool NetScope::emit_defs(struct target_t*tgt) const return flag; } +bool netclass_t::emit_defs(struct target_t*tgt) const +{ + return class_scope_->emit_defs(tgt); +} + int Design::emit(struct target_t*tgt) const { int rc = 0; @@ -482,12 +504,26 @@ int Design::emit(struct target_t*tgt) const if (tgt->start_design(this) == false) return -2; + for (map::const_iterator scope = root_tasks_.begin() + ; scope != root_tasks_.end() ; ++ scope) { + scope->first->emit_scope(tgt); + scope->first->emit_defs(tgt); + } + // enumerate package scopes for (map::const_iterator scope = packages_.begin() ; scope != packages_.end() ; ++ scope) { scope->second->emit_scope(tgt); } + for (map::const_iterator cur = classes_.begin() + ; cur != classes_.end() ; ++cur) { + const NetScope*use_scope = cur->second->class_scope(); + cur->second->emit_scope(tgt); + tgt->class_type(use_scope, cur->second); + cur->second->emit_defs(tgt); + } + // enumerate root scopes for (list::const_iterator scope = root_scopes_.begin() ; scope != root_scopes_.end(); ++ scope ) { @@ -600,6 +636,11 @@ void NetEEvent::expr_scan(struct expr_scan_t*tgt) const tgt->expr_event(this); } +void NetELast::expr_scan(struct expr_scan_t*tgt) const +{ + tgt->expr_last(this); +} + void NetENetenum::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_netenum(this); diff --git a/eval.cc b/eval.cc index 09b2aae89..475bf31b0 100644 --- a/eval.cc +++ b/eval.cc @@ -44,6 +44,14 @@ verinum* PEBinary::eval_const(Design*des, NetScope*scope) const verinum*res; switch (op_) { + case 'p': { + if (l->is_defined() && r->is_defined()) { + res = new verinum(pow(*l, *r)); + } else { + res = new verinum(verinum::Vx, l->len()); + } + break; + } case '+': { if (l->is_defined() && r->is_defined()) { res = new verinum(*l + *r); diff --git a/eval_tree.cc b/eval_tree.cc index ff224d909..15bbc96d4 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1384,6 +1384,7 @@ NetExpr*NetETernary::blended_arguments_(const NetExpr*te, const NetExpr*fe) cons if (tv == fv) val.set(idx, tv); else val.set(idx, verinum::Vx); } + val.has_sign(has_sign()); if (debug_eval_tree) { cerr << get_fileline() << ": debug: Evaluate ternary with " @@ -2015,6 +2016,7 @@ static bool get_array_info(const NetExpr*arg, long dim, /* A string or dynamic array must be handled by the run time. */ switch (sig->data_type()) { case IVL_VT_DARRAY: + case IVL_VT_QUEUE: case IVL_VT_STRING: defer = true; return true; diff --git a/expr_synth.cc b/expr_synth.cc index 89242ec9b..28f3c783e 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -274,7 +274,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, NetExpr*root) if (op_ == 'E' || op_ == 'N') { NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(), - width, op_=='E'?true:false); + width, op_=='E'?NetCaseCmp::EEQ:NetCaseCmp::NEQ); gate->set_line(*this); connect(gate->pin(0), osig->pin(0)); connect(gate->pin(1), lsig->pin(0)); @@ -1271,6 +1271,22 @@ NetNet* NetETernary::synthesize(Design *des, NetScope*scope, NetExpr*root) */ NetNet* NetESignal::synthesize(Design*des, NetScope*scope, NetExpr*root) { + // If this is a synthesis with a specific value for the + // signal, then replace it (here) with a constant value. + if (net_->scope()==scope && net_->name()==scope->genvar_tmp) { + 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, tmp_vec); + verinum tmp_val ((uint64_t)scope->genvar_tmp_val, net_->vector_width()); + NetConst*tmp_const = new NetConst(scope, scope->local_symbol(), tmp_val); + tmp_const->set_line(*this); + des->add_node(tmp_const); + + connect(tmp->pin(0), tmp_const->pin(0)); + return tmp; + } + if (word_ == 0) return net_; @@ -1440,6 +1456,12 @@ NetNet* NetEUFunc::synthesize(Design*des, NetScope*scope, NetExpr*root) osig->local_flag(true); connect(net->pin(0), osig->pin(0)); + if (debug_synth2) { + cerr << get_fileline() << ": NetEUFunc::synthesize: " + << "result_sig_->vector_width()=" << result_sig_->vector_width() + << ", osig->vector_width()=" << osig->vector_width() << endl; + } + /* Connect the pins to the arguments. */ NetFuncDef*def = func_->func_def(); for (unsigned idx = 0; idx < eparms.size(); idx += 1) { diff --git a/functor.h b/functor.h index ea0431c0d..b72e8efd3 100644 --- a/functor.h +++ b/functor.h @@ -1,7 +1,7 @@ -#ifndef __functor_H -#define __functor_H +#ifndef IVL_functor_H +#define IVL_functor_H /* - * Copyright (c) 1999-2008,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -105,4 +105,4 @@ struct proc_match_t { virtual int block(class NetBlock*); }; -#endif +#endif /* IVL_functor_H */ diff --git a/ivl_alloc.h b/ivl_alloc.h index 577e8fd28..76f3d09ca 100644 --- a/ivl_alloc.h +++ b/ivl_alloc.h @@ -1,7 +1,7 @@ -#ifndef __ivl_alloc_H -#define __ivl_alloc_H +#ifndef IVL_ivl_alloc_H +#define IVL_ivl_alloc_H /* - * Copyright (C) 2010 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2014 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 @@ -83,4 +83,4 @@ __ivl_rtn; \ }) -#endif +#endif /* IVL_ivl_alloc_H */ diff --git a/ivl_assert.h b/ivl_assert.h index 6c4f9c0b9..72812c05f 100644 --- a/ivl_assert.h +++ b/ivl_assert.h @@ -1,5 +1,7 @@ +#ifndef IVL_ivl_assert_H +#define IVL_ivl_assert_H /* - * Copyright (c) 2007-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2014 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 @@ -17,9 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __ivl_assert_h -#define __ivl_assert_h - # include #define ivl_assert(tok, expression) \ @@ -32,4 +31,4 @@ } \ } while (0) -#endif +#endif /* IVL_ivl_assert_H */ diff --git a/ivl_target.h b/ivl_target.h index 70b5b9db2..0198eec09 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1,7 +1,7 @@ -#ifndef __ivl_target_H -#define __ivl_target_H +#ifndef IVL_ivl_target_H +#define IVL_ivl_target_H /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -300,6 +300,8 @@ typedef enum ivl_lpm_type_e { IVL_LPM_CONCAT = 16, IVL_LPM_CONCATZ = 36, /* Transparent concat */ IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */ + IVL_LPM_CMP_EQX= 37, /* Windcard EQ (==?) */ + IVL_LPM_CMP_EQZ= 38, /* casez EQ */ IVL_LPM_CMP_EQ = 10, IVL_LPM_CMP_GE = 1, IVL_LPM_CMP_GT = 2, @@ -326,6 +328,7 @@ typedef enum ivl_lpm_type_e { IVL_LPM_SHIFTR = 7, IVL_LPM_SIGN_EXT=27, IVL_LPM_SUB = 8, + IVL_LPM_SUBSTITUTE=39, /* IVL_LPM_RAM = 9, / obsolete */ IVL_LPM_UFUNC = 14 } ivl_lpm_type_t; @@ -437,6 +440,7 @@ typedef enum ivl_variable_type_e { IVL_VT_STRING = 5, IVL_VT_DARRAY = 6, /* Array (esp. dynamic array) */ IVL_VT_CLASS = 7, /* SystemVerilog class instances */ + IVL_VT_QUEUE = 8, /* SystemVerilog queue instances */ IVL_VT_VECTOR = IVL_VT_LOGIC /* For compatibility */ } ivl_variable_type_t; @@ -828,6 +832,10 @@ extern unsigned ivl_event_lineno(ivl_event_t net); * table. That number can be passed to ivl_type_prop_*() functions to * get details about the property. * + * If the property is an array, then the ivl_expr_oper1() function + * returns the canonical expression for accessing the element of the + * property. + * * - IVL_EX_NEW * This expression takes one or two operands. The first operand, * returned by ivl_expr_oper1() is the number of elements to create @@ -1265,7 +1273,7 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net); * width of the part. The ivl_lpm_q is the part end, and the * ivl_lpm_data(0) is the non-part end. * - * - Comparisons (IVL_LPM_CMP_GT/GE/EQ/NE/EEQ/NEE) + * - Comparisons (IVL_LPM_CMP_GT/GE/EQ/NE/EEQ/NEE/EQX/EQZ) * These devices have two inputs, available by the ivl_lpm_data() * function, and one output available by the ivl_lpm_q function. The * output width is always 1, but the ivl_lpm_width() returns the width @@ -1277,6 +1285,11 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net); * magnitude compare, the signedness does matter. In any case, the * result of the compare is always unsigned. * + * The EQX and EQZ nodes are windcard compares, where xz bits (EQX) or + * z bits (EQZ) in the data(1) operand are treated as windcards. no + * bits in the data(0) operand are wild. This matches the + * SystemVerilog convention for the ==? operator. + * * - Mux Device (IVL_LPM_MUX) * The MUX device has a q output, a select input, and a number of data * inputs. The ivl_lpm_q output and the ivl_lpm_data inputs all have @@ -1402,7 +1415,7 @@ extern ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net); extern ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net); /* IVL_LPM_ARRAY */ extern ivl_signal_t ivl_lpm_array(ivl_lpm_t net); - /* IVL_LPM_PART */ + /* IVL_LPM_PART IVL_LPM_SUBSTITUTE */ extern unsigned ivl_lpm_base(ivl_lpm_t net); /* IVL_LPM_FF */ extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net); @@ -1412,12 +1425,14 @@ extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net); /* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT IVL_LPM_MUX IVL_LPM_POW IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB - IVL_LPM_UFUNC */ + IVL_LPM_UFUNC IVL_LPM_SUBSTITUTE */ extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx); - /* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_POW IVL_LPM_SUB */ + /* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_POW IVL_LPM_SUB IVL_LPM_CMP_EQ + IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE */ extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_POW - IVL_LPM_SUB IVL_LPM_UFUNC */ + IVL_LPM_SUB IVL_LPM_UFUNC IVL_LPM_CMP_EEQ IVL_LPM_CMP_EQX + IVL_LPM_CMP_EQZ IVL_LPM_CMP_NEE IVL_LPM_SUBSTITUTE */ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net); extern ivl_drive_t ivl_lpm_drive0(ivl_lpm_t net); extern ivl_drive_t ivl_lpm_drive1(ivl_lpm_t net); @@ -1488,6 +1503,11 @@ extern const char*ivl_lpm_string(ivl_lpm_t net); * then the ivl_lval_idx expression must *not* be present. * * For array words, the ivl_lval_width is the width of the word. + * + * - Arrayed properties + * If the l-value is a class property, then the ivl_lval_idx function + * will return an expression if the property is in fact arrayed. The + * expression is the canonical index for elements in the property. */ extern unsigned ivl_lval_width(ivl_lval_t net); @@ -2322,4 +2342,4 @@ typedef const char* (*target_query_f) (const char*key); _END_DECL -#endif +#endif /* IVL_ivl_target_H */ diff --git a/ivl_target_priv.h b/ivl_target_priv.h index a5a10d01d..489d801eb 100644 --- a/ivl_target_priv.h +++ b/ivl_target_priv.h @@ -1,7 +1,7 @@ -#ifndef __ivl_target_priv_H -#define __ivl_target_priv_H +#ifndef IVL_ivl_target_priv_H +#define IVL_ivl_target_priv_H /* - * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2014 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 @@ -52,6 +52,7 @@ struct ivl_design_s { // Keep arrays of root scopes. std::map classes; + std::map root_tasks; std::vector packages; std::vector roots; @@ -90,4 +91,4 @@ struct ivl_island_s { extern std::ostream& operator << (std::ostream&o, ivl_drive_t str); -#endif +#endif /* IVL_ivl_target_priv_H */ diff --git a/ivlpp/Makefile.in b/ivlpp/Makefile.in index ffcafe6a9..07053c298 100644 --- a/ivlpp/Makefile.in +++ b/ivlpp/Makefile.in @@ -44,7 +44,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = main.o lexor.o diff --git a/ivlpp/globals.h b/ivlpp/globals.h index db7d660a5..90b4632b9 100644 --- a/ivlpp/globals.h +++ b/ivlpp/globals.h @@ -1,7 +1,7 @@ -#ifndef __globals_H -#define __globals_H +#ifndef IVL_globals_H +#define IVL_globals_H /* - * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -22,11 +22,11 @@ # include extern void reset_lexor(FILE*out, char*paths[]); -extern void destroy_lexor(); +extern void destroy_lexor(void); extern void load_precompiled_defines(FILE*src); extern void define_macro(const char*name, const char*value, int keyword, int argc); -extern void free_macros(); +extern void free_macros(void); extern void dump_precompiled_defines(FILE*out); /* These variables contain the include directories to be searched when @@ -54,6 +54,6 @@ extern char dep_mode; extern int verbose_flag; /* This is the entry to the lexer. */ -extern int yylex(); +extern int yylex(void); -#endif +#endif /* IVL_globals_H */ diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index fe4e235f2..0fa66e41f 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1,7 +1,7 @@ %option prefix="yy" %{ /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -30,29 +30,29 @@ # include "globals.h" # include "ivl_alloc.h" -static void output_init(); +static void output_init(void); #define YY_USER_INIT output_init() -static void def_start(); -static void def_add_arg(); -static void def_finish(); -static void def_undefine(); -static void do_define(); -static int def_is_done(); +static void def_start(void); +static void def_add_arg(void); +static void def_finish(void); +static void def_undefine(void); +static void do_define(void); +static int def_is_done(void); static int is_defined(const char*name); static int macro_needs_args(const char*name); -static void macro_start_args(); +static void macro_start_args(void); static void macro_add_to_arg(int is_whitespace); -static void macro_finish_arg(); +static void macro_finish_arg(void); static void do_expand(int use_args); static const char* do_magic(const char*name); -static const char* macro_name(); +static const char* macro_name(void); -static void include_filename(); -static void do_include(); +static void include_filename(void); +static void do_include(void); -static int load_next_input(); +static int load_next_input(void); struct include_stack_t { @@ -804,7 +804,7 @@ static /* inline */ char* def_argv(int arg) return def_buf + def_argo[arg]; } -static void check_for_max_args() +static void check_for_max_args(void) { if (def_argc == MAX_DEF_ARG) { @@ -825,14 +825,14 @@ static void def_buf_grow_to_fit(int length) } } -static void def_start() +static void def_start(void) { def_buf_free = def_buf_size; def_argc = 0; def_add_arg(); } -static void def_add_arg() +static void def_add_arg(void) { int length = yyleng; @@ -852,7 +852,7 @@ static void def_add_arg() char*arg = yytext; char*val; - int val_length; + int val_length = 0; /* Break into ARG = value. This happens if the source specifies a default value for the formal argument. In that case, the @@ -979,7 +979,7 @@ static void free_macro(struct define_t* def) free(def); } -void free_macros() +void free_macros(void) { free_macro(def_table); } @@ -1052,7 +1052,7 @@ static char *find_arg(char*ptr, char*head, char*arg) * continuation, then return 1 and this function may be called again * to collect another line of the definition. */ -static void do_define() +static void do_define(void) { char* cp; char* head; @@ -1202,7 +1202,7 @@ static void do_define() * Return true if the definition text is done. This is the opposite of * the define_continue_flag. */ -static int def_is_done() +static int def_is_done(void) { return !define_continue_flag; } @@ -1212,7 +1212,7 @@ static int def_is_done() * assigned value to the parsed name. If there is no value, then * assign the string "" (empty string.) */ -static void def_finish() +static void def_finish(void) { define_continue_flag = 0; @@ -1234,7 +1234,7 @@ static void def_finish() def_argc = 0; } -static void def_undefine() +static void def_undefine(void) { struct define_t* cur; struct define_t* tail; @@ -1360,7 +1360,7 @@ static int macro_needs_args(const char*text) } } -static const char* macro_name() +static const char* macro_name(void) { return cur_macro ? cur_macro->name : ""; } @@ -1402,7 +1402,7 @@ static void macro_add_to_arg(int is_white_space) def_buf_free -= length; } -static void macro_finish_arg() +static void macro_finish_arg(void) { char* tail = &def_buf[def_buf_size - def_buf_free]; @@ -1443,7 +1443,7 @@ static void exp_buf_grow_to_fit(int length) } } -static void expand_using_args() +static void expand_using_args(void) { char* head; char* tail; @@ -1634,7 +1634,8 @@ static const char* do_magic(const char*name) int actual_len = snprintf(magic_text, desired_cnt, "%u", get_line(istack)); - assert(actual_len < desired_cnt); + assert(actual_len >= 0); + assert((unsigned) actual_len < desired_cnt); return magic_text; } else if(!strcmp(name, "__FILE__")) @@ -1654,7 +1655,9 @@ static const char* do_magic(const char*name) int actual_len = snprintf(magic_text, desired_cnt, "\"%s\"", path); - assert(actual_len < desired_cnt); + + assert(actual_len >= 0); + assert((unsigned) actual_len < (unsigned)desired_cnt); return magic_text; } } @@ -1684,13 +1687,13 @@ static const char* do_magic(const char*name) * parsing resumes. */ -static void output_init() +static void output_init(void) { if (line_direct_flag) fprintf(yyout, "`line 1 \"%s\" 0\n", istack->path); } -static void include_filename() +static void include_filename(void) { if(standby) { emit_pathline(istack); @@ -1709,7 +1712,7 @@ static void include_filename() standby->comment = NULL; } -static void do_include() +static void do_include(void) { /* standby is defined by include_filename() */ if (standby->path[0] == '/') { @@ -1832,7 +1835,7 @@ static void emit_pathline(struct include_stack_t* isp) fprintf(stderr, "%s:%u: ", isp->path, isp->lineno+1); } -static void lexor_done() +static void lexor_done(void) { while (ifdef_stack) { @@ -1920,7 +1923,7 @@ static void open_input_file(struct include_stack_t*isp) * end of a base file, in which case the next base source file is * opened. */ -static int load_next_input() +static int load_next_input(void) { int line_mask_flag = 0; struct include_stack_t* isp = istack; @@ -2190,7 +2193,7 @@ void reset_lexor(FILE* out, char* paths[]) /* * Modern version of flex (>=2.5.9) can clean up the scanner data. */ -void destroy_lexor() +void destroy_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 diff --git a/lexor.lex b/lexor.lex index 68435444c..d14e38694 100644 --- a/lexor.lex +++ b/lexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -134,9 +134,17 @@ TU [munpf] \n { yylloc.first_line += 1; } /* C++ style comments start with / / and run to the end of the - current line. These are very easy to handle. */ + current line. These are very easy to handle. The meta-comments + format is a little more tricky to handle, but do what we can. */ -"//".* { comment_enter = YY_START; BEGIN(LCOMMENT); } + /* The lexor detects "// synthesis translate_on/off" meta-comments, + we handle them here by turning on/off a flag. The pform uses + that flag to attach implicit attributes to "initial" and + "always" statements. */ + +"//"{W}*"synthesis"{W}+"translate_on"{W}*\n { pform_mc_translate_on(true); } +"//"{W}*"synthesis"{W}+"translate_off"{W}*\n { pform_mc_translate_on(false); } +"//" { comment_enter = YY_START; BEGIN(LCOMMENT); } . { yymore(); } \n { yylloc.first_line += 1; BEGIN(comment_enter); } @@ -325,8 +333,8 @@ TU [munpf] if (in_package_scope) { if (rc == IDENTIFIER) { if (data_type_t*type = pform_test_type_identifier(in_package_scope, yylval.text)) { - delete[]yylval.text; - yylval.data_type = type; + yylval.type_identifier.text = yylval.text; + yylval.type_identifier.type = type; rc = TYPE_IDENTIFIER; } } @@ -361,8 +369,8 @@ TU [munpf] return this as a TYPE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { if (data_type_t*type = pform_test_type_identifier(yylval.text)) { - delete[]yylval.text; - yylval.data_type = type; + yylval.type_identifier.text = yylval.text; + yylval.type_identifier.type = type; rc = TYPE_IDENTIFIER; } } @@ -382,8 +390,8 @@ TU [munpf] } if (gn_system_verilog()) { if (data_type_t*type = pform_test_type_identifier(yylval.text)) { - delete[]yylval.text; - yylval.data_type = type; + yylval.type_identifier.text = yylval.text; + yylval.type_identifier.type = type; return TYPE_IDENTIFIER; } } @@ -649,14 +657,14 @@ TU [munpf] |GN_KEYWORDS_1364_2005 |GN_KEYWORDS_VAMS_2_3; } else { - fprintf(stderr, "%s:%u: Ignoring unknown keywords string: %s\n", + fprintf(stderr, "%s:%d: Ignoring unknown keywords string: %s\n", yylloc.text, yylloc.first_line, word); } BEGIN(0); } .* { - fprintf(stderr, "%s:%u: Malformed keywords specification: %s\n", + fprintf(stderr, "%s:%d: Malformed keywords specification: %s\n", yylloc.text, yylloc.first_line, yytext); BEGIN(0); } @@ -666,7 +674,7 @@ TU [munpf] lexor_keyword_mask = keyword_mask_stack.front(); keyword_mask_stack.pop_front(); } else { - fprintf(stderr, "%s:%u: Mismatched end_keywords directive\n", + fprintf(stderr, "%s:%d: Mismatched end_keywords directive\n", yylloc.text, yylloc.first_line); } } diff --git a/lexor_keyword.h b/lexor_keyword.h index dcd090188..f351dcf3a 100644 --- a/lexor_keyword.h +++ b/lexor_keyword.h @@ -1,7 +1,7 @@ -#ifndef __lexor_keyword_H -#define __lexor_keyword_H +#ifndef IVL_lexor_keyword_H +#define IVL_lexor_keyword_H /* - * Copyright (c) 2000 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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,4 +21,4 @@ extern int lexor_keyword_code (const char*str, unsigned len); -#endif +#endif /* IVL_lexor_keyword_H */ diff --git a/libmisc/LineInfo.h b/libmisc/LineInfo.h index 5f3dff9f5..b212bc959 100644 --- a/libmisc/LineInfo.h +++ b/libmisc/LineInfo.h @@ -1,7 +1,7 @@ -#ifndef __LineInfo_H -#define __LineInfo_H +#ifndef IVL_LineInfo_H +#define IVL_LineInfo_H /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -54,4 +54,4 @@ class LineInfo { unsigned lineno_; }; -#endif +#endif /* IVL_LineInfo_H */ diff --git a/libmisc/StringHeap.cc b/libmisc/StringHeap.cc index 6c30bafa7..f87c4fcf8 100644 --- a/libmisc/StringHeap.cc +++ b/libmisc/StringHeap.cc @@ -210,3 +210,5 @@ ostream& operator << (ostream&out, perm_string that) out << that.str(); return out; } + +const perm_string empty_perm_string = perm_string::literal(""); diff --git a/libmisc/StringHeap.h b/libmisc/StringHeap.h index f803e8a77..5c791e104 100644 --- a/libmisc/StringHeap.h +++ b/libmisc/StringHeap.h @@ -1,7 +1,7 @@ -#ifndef __StringHeap_H -#define __StringHeap_H +#ifndef IVL_StringHeap_H +#define IVL_StringHeap_H /* - * Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2014 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 @@ -52,6 +52,7 @@ class perm_string { const char*text_; }; +extern const perm_string empty_perm_string; extern bool operator == (perm_string a, perm_string b); extern bool operator == (perm_string a, const char* b); extern bool operator != (perm_string a, perm_string b); @@ -120,4 +121,4 @@ class StringHeapLex : private StringHeap { StringHeapLex& operator= (const StringHeapLex&); }; -#endif +#endif /* IVL_StringHeap_H */ diff --git a/libveriuser/Makefile.in b/libveriuser/Makefile.in index e6d843927..868f3e257 100644 --- a/libveriuser/Makefile.in +++ b/libveriuser/Makefile.in @@ -48,7 +48,7 @@ LDRELOCFLAGS = @LDRELOCFLAGS@ LDTARGETFLAGS = @LDTARGETFLAGS@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \ a_fetch_argv.o a_fetch_dir.o a_fetch_fullname.o a_fetch_location.o \ diff --git a/libveriuser/a_configure.c b/libveriuser/a_configure.c index c6d242e5d..cd79ca1e5 100644 --- a/libveriuser/a_configure.c +++ b/libveriuser/a_configure.c @@ -69,9 +69,13 @@ int acc_configure(PLI_INT32 config_param, const char*value) fprintf(pli_trace, "acc_configure(config=%d, %s)\n", (int)config_param, value); } - +#if 0 vpi_printf("XXXX acc_configure(%d, %s)\n", (int)config_param, value); +#else + /* Parameter is not necessarily a string. */ + vpi_printf("XXXX acc_configure(%d, ...)\n", (int)config_param); +#endif rc = 0; break; } diff --git a/libveriuser/a_fetch_argc.c b/libveriuser/a_fetch_argc.c index eadeef4bb..669807a6b 100644 --- a/libveriuser/a_fetch_argc.c +++ b/libveriuser/a_fetch_argc.c @@ -19,6 +19,7 @@ # include # include +# include /* * acc_fetch_argc implemented using VPI interface diff --git a/libveriuser/a_fetch_argv.c b/libveriuser/a_fetch_argv.c index 1f447a8a1..6d22a0404 100644 --- a/libveriuser/a_fetch_argv.c +++ b/libveriuser/a_fetch_argv.c @@ -19,6 +19,7 @@ # include # include +# include /* * acc_fetch_argv implemented using VPI interface diff --git a/libveriuser/a_fetch_dir.c b/libveriuser/a_fetch_dir.c index 52db2f704..3dc6081c7 100644 --- a/libveriuser/a_fetch_dir.c +++ b/libveriuser/a_fetch_dir.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Stephen Williams (steve@picturel.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@picturel.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,6 +25,7 @@ PLI_INT32 acc_fetch_direction(handle obj) { + (void)obj; /* Parameter is not used. */ if (pli_trace) { fprintf(pli_trace, "acc_fetch_direction: enter.\n"); fflush(pli_trace); diff --git a/libveriuser/a_fetch_location.c b/libveriuser/a_fetch_location.c index 1e078a6a3..28577c9d2 100644 --- a/libveriuser/a_fetch_location.c +++ b/libveriuser/a_fetch_location.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -22,6 +22,7 @@ int acc_fetch_location(p_location loc, handle obj) { + (void)obj; /* Parameter is not used. */ loc->line_no = 0; loc->filename = ""; return 1; diff --git a/libveriuser/a_fetch_type_str.c b/libveriuser/a_fetch_type_str.c index e8cefae4d..52b0c829a 100644 --- a/libveriuser/a_fetch_type_str.c +++ b/libveriuser/a_fetch_type_str.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -40,3 +40,12 @@ const char* acc_fetch_type_str(PLI_INT32 type) vpi_printf("acc_fetch_type_str: type %d is what accType?\n", (int)type); return "acc_fetch_type_str(unknown)"; } + +/* + * FIXME: What does this do? How should it be declared in acc_user.h? + */ +PLI_INT32 acc_fetch_paramtype(handle obj) +{ + (void)obj; /* Parameter is not used. */ + return 0; +} diff --git a/libveriuser/a_handle_hiconn.c b/libveriuser/a_handle_hiconn.c index 2b54647ea..e147b471e 100644 --- a/libveriuser/a_handle_hiconn.c +++ b/libveriuser/a_handle_hiconn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Stephen Williams (steve@picturel.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@picturel.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,6 +25,7 @@ handle acc_handle_hiconn(handle obj) { + (void)obj; /* Parameter is not used. */ if (pli_trace) { fprintf(pli_trace, "acc_handle_hiconn: enter.\n"); fflush(pli_trace); diff --git a/libveriuser/a_next_bit.c b/libveriuser/a_next_bit.c index cc9316c05..04ec7a759 100644 --- a/libveriuser/a_next_bit.c +++ b/libveriuser/a_next_bit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Stephen Williams (steve@picturel.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@picturel.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,6 +25,8 @@ handle acc_next_bit(handle ref, handle bit) { + (void)ref; /* Parameter is not used. */ + (void)bit; /* Parameter is not used. */ if (pli_trace) { fprintf(pli_trace, "acc_next_bit: enter.\n"); fflush(pli_trace); diff --git a/libveriuser/a_next_port.c b/libveriuser/a_next_port.c index e0950b3fa..f65565b80 100644 --- a/libveriuser/a_next_port.c +++ b/libveriuser/a_next_port.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,6 +25,8 @@ handle acc_next_port(handle ref, handle bit) { + (void)ref; /* Parameter is not used. */ + (void)bit; /* Parameter is not used. */ if (pli_trace) { fprintf(pli_trace, "acc_next_port: enter.\n"); fflush(pli_trace); diff --git a/libveriuser/a_vcl.c b/libveriuser/a_vcl.c index e4f4d7725..132ba6c2b 100644 --- a/libveriuser/a_vcl.c +++ b/libveriuser/a_vcl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 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 @@ -162,6 +162,7 @@ void acc_vcl_add(handle obj, PLI_INT32(*consumer)(p_vc_record), switch (vpi_get(vpiType, obj)) { case vpiNet: + case vpiReg: cur = malloc(sizeof (struct vcl_record)); cur->obj = obj; cur->consumer = consumer; @@ -195,5 +196,9 @@ void acc_vcl_add(handle obj, PLI_INT32(*consumer)(p_vc_record), void acc_vcl_delete(handle obj, PLI_INT32(*consumer)(p_vc_record), void*data, PLI_INT32 vcl_flag) { + (void)obj; /* Parameter is not used. */ + (void)consumer; /* Parameter is not used. */ + (void)data; /* Parameter is not used. */ + (void)vcl_flag; /* Parameter is not used. */ vpi_printf("XXXX acc_vcl_delete(...)\n"); } diff --git a/libveriuser/config.h.in b/libveriuser/config.h.in index 3496f7134..5328537b7 100644 --- a/libveriuser/config.h.in +++ b/libveriuser/config.h.in @@ -1,7 +1,7 @@ -#ifndef __config_H -#define __config_H +#ifndef IVL_config_H +#define IVL_config_H /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -37,4 +37,4 @@ typedef unsigned long ivl_u64_t; # endif #endif -#endif +#endif /* IVL_config_H */ diff --git a/libveriuser/delay.c b/libveriuser/delay.c index 2aa47b3ce..31c03b9d0 100644 --- a/libveriuser/delay.c +++ b/libveriuser/delay.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 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 @@ -24,6 +24,7 @@ static PLI_INT32 delay_callback(struct t_cb_data*cb) { + (void)cb; /* Parameter is not used. */ vpi_printf("XXXX delay_callback called.\n"); return 0; } diff --git a/libveriuser/exprinfo.c b/libveriuser/exprinfo.c index 314b3d5fb..219a884c5 100644 --- a/libveriuser/exprinfo.c +++ b/libveriuser/exprinfo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,6 +25,8 @@ struct t_tfexprinfo* tf_exprinfo(PLI_INT32 a, struct t_tfexprinfo*ip) { + (void)a; /* Parameter is not used. */ + (void)ip; /* Parameter is not used. */ if (pli_trace) { fprintf(pli_trace, "tf_exprinfo: enter.\n"); fflush(pli_trace); diff --git a/libveriuser/getsimtime.c b/libveriuser/getsimtime.c index 646cbf491..0a7ad914f 100644 --- a/libveriuser/getsimtime.c +++ b/libveriuser/getsimtime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2011 Michael Ruff (mruff at chiaro.com) + * Copyright (c) 2002-2014 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 @@ -39,14 +39,36 @@ static ivl_u64_t pow10u(PLI_INT32 val) } static ivl_u64_t -scale(int high, int low, void*obj) { - vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); +scale(int high, int low, void*obj) +{ ivl_u64_t scaled; + vpiHandle use_obj = obj; + if (use_obj == 0) { + /* If object is not passed in, then use current scope. */ + vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); + use_obj = hand; + } else { + /* If object IS passed in, make sure it is a scope. If + it is not, then get the scope of the object. We need + a scope handle to go on. */ + switch (vpi_get(vpiType,use_obj)) { + case vpiModule: + case vpiGenScope: + case vpiFunction: + case vpiTask: + case vpiNamedBegin: + case vpiNamedFork: + break; + default: + use_obj = vpi_handle(vpiScope, use_obj); + break; + } + } + scaled = high; scaled = (scaled << 32) | low; - scaled /= pow10u(vpi_get(vpiTimeUnit,obj ? (vpiHandle)obj : hand) - - vpi_get(vpiTimePrecision,0)); + scaled /= pow10u(vpi_get(vpiTimeUnit, use_obj) - vpi_get(vpiTimePrecision,0)); return scaled; } @@ -125,6 +147,8 @@ void tf_unscale_longdelay(void*obj, PLI_INT32 low, PLI_INT32 high, ivl_u64_t unscaled; vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); + (void)obj; /* Parameter is not used. */ + unscaled = high; unscaled = (unscaled << 32) | low; unscaled *= pow(10, vpi_get(vpiTimeUnit, hand) - @@ -138,6 +162,8 @@ void tf_scale_realdelay(void*obj, double real, double *areal) { vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); + (void)obj; /* Parameter is not used. */ + *areal = real / pow(10, vpi_get(vpiTimeUnit, hand) - vpi_get(vpiTimePrecision, 0)); } @@ -146,6 +172,8 @@ void tf_unscale_realdelay(void*obj, double real, double *areal) { vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); + (void)obj; /* Parameter is not used. */ + *areal = real * pow(10, vpi_get(vpiTimeUnit, hand) - vpi_get(vpiTimePrecision, 0)); } diff --git a/libveriuser/io_print.c b/libveriuser/io_print.c index f72cb6405..f23eb4ef7 100644 --- a/libveriuser/io_print.c +++ b/libveriuser/io_print.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Michael Ruff (mruff at chiaro.com) + * Copyright (c) 2002-2014 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 @@ -58,6 +58,8 @@ PLI_INT32 tf_message(PLI_INT32 level, char*facility, { va_list ap; + (void)level; /* Parameter is not used. */ + vpi_printf("%s[%s] ", facility, messno); va_start(ap, fmt); diff --git a/libveriuser/nodeinfo.c b/libveriuser/nodeinfo.c index d421c7ae5..4f7baf5f0 100644 --- a/libveriuser/nodeinfo.c +++ b/libveriuser/nodeinfo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -23,8 +23,11 @@ # include # include "priv.h" -struct t_tfnoeinfo* tf_nodeinfo(PLI_INT32 a, struct t_tfnodeinfo*ip) +/* XXX Not declared or used anywhere? */ +struct t_tfnodeinfo* tf_nodeinfo(PLI_INT32 a, struct t_tfnodeinfo*ip) { + (void)a; /* Parameter is not used. */ + (void)ip; /* Parameter is not used. */ if (pli_trace) { fprintf(pli_trace, "tf_nodeinfo: enter.\n"); fflush(pli_trace); diff --git a/libveriuser/nump.c b/libveriuser/nump.c index c1449cae2..38d574020 100644 --- a/libveriuser/nump.c +++ b/libveriuser/nump.c @@ -19,6 +19,7 @@ #include #include +#include "veriuser.h" /* * tf_nump implemented using VPI interface diff --git a/libveriuser/priv.h b/libveriuser/priv.h index 0fdabeb8b..8256e16d3 100644 --- a/libveriuser/priv.h +++ b/libveriuser/priv.h @@ -1,7 +1,7 @@ -#ifndef __priv_H -#define __priv_H +#ifndef IVL_priv_H +#define IVL_priv_H /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 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 @@ -33,4 +33,4 @@ extern char* __acc_newstring(const char*txt); */ FILE* pli_trace; -#endif +#endif /* IVL_priv_H */ diff --git a/libveriuser/veriusertfs.c b/libveriuser/veriusertfs.c index cf7b156a7..979b2b5d3 100644 --- a/libveriuser/veriusertfs.c +++ b/libveriuser/veriusertfs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2013 Michael Ruff (mruff at chiaro.com) + * Copyright (c) 2002-2014 Michael Ruff (mruff at chiaro.com) * Michael Runyan (mrunyan at chiaro.com) * * This source code is free software; you can redistribute it @@ -57,6 +57,8 @@ static PLI_INT32 sys_end_of_simulation(p_cb_data cb_data) { unsigned idx; + (void)cb_data; /* Parameter is not used. */ + for (idx = 0; idx < udata_count; idx += 1) { free(udata_store[idx]); } @@ -370,7 +372,7 @@ PLI_INT32 tf_irosynchronize(void*obj) vpiHandle sys = (vpiHandle)obj; p_pli_data pli = vpi_get_userdata(sys); s_cb_data cb; - s_vpi_time ti = {vpiSuppressTime, 0, 0}; + s_vpi_time ti = {vpiSuppressTime, 0, 0, 0.0}; cb.reason = cbReadOnlySynch; cb.cb_rtn = callback; @@ -397,7 +399,7 @@ PLI_INT32 tf_isetrealdelay(double dly, void*obj) vpiHandle sys = (vpiHandle)obj; p_pli_data pli = vpi_get_userdata(sys); s_cb_data cb; - s_vpi_time ti = {vpiSimTime}; + s_vpi_time ti = {vpiSimTime, 0, 0, 0.0}; /* Scale delay to SimTime */ ivl_u64_t delay = ((dly diff --git a/link_const.cc b/link_const.cc index 9b01c75b3..0e8c7e39d 100644 --- a/link_const.cc +++ b/link_const.cc @@ -232,3 +232,58 @@ verinum Nexus::driven_vector() const return val; } + +/* + * Calculate a vector that represent all the bits of the vector, with + * each driven bit set to true, otherwise false. + */ +vector Nexus::driven_mask(void) const +{ + vector mask (vector_width()); + + for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) { + + Link::DIR link_dir = cur->get_dir(); + if (link_dir==Link::PASSIVE) + continue; + if (link_dir==Link::INPUT) + continue; + + const NetPins*obj = cur->get_obj(); + + // If the link is to a variable (REG or INTEGER) then + // the variable is driving all the bits. We have our + // complete answer, mark all the bits as driven and + // finish. Otherwise, we are not going to get new + // information from this node, move on. + if (const NetNet*sig = dynamic_cast (obj)) { + NetNet::Type sig_type = sig->type(); + if (sig_type==NetNet::INTEGER || sig_type==NetNet::REG) { + for (size_t idx = 0 ; idx < mask.size() ; idx += 1) + mask[idx] = true; + return mask; + } + continue; + } + + const NetPartSelect*obj_ps = dynamic_cast(obj); + if (obj_ps && obj_ps->dir()==NetPartSelect::VP) + continue; + if (obj_ps && cur->get_pin()!=1) + continue; + if (obj_ps) { + for (unsigned idx = 0 ; idx < obj_ps->width() ; idx += 1) { + size_t bit = idx + obj_ps->base(); + ivl_assert(*obj, bit < mask.size()); + mask[bit] = true; + } + continue; + } + + for (size_t idx = 0 ; idx < mask.size() ; idx += 1) + mask[idx] = true; + return mask; + } + + return mask; +} diff --git a/main.cc b/main.cc index 5c7e040a1..21d7232b1 100644 --- a/main.cc +++ b/main.cc @@ -1019,6 +1019,16 @@ int main(int argc, char*argv[]) ; cur != disciplines.end() ; ++ cur ) { pform_dump(out, (*cur).second); } + out << "PFORM DUMP $ROOT TASKS/FUNCTIONS:" << endl; + for (map::iterator cur = pform_tasks.begin() + ; cur != pform_tasks.end() ; ++ cur) { + pform_dump(out, cur->second); + } + out << "PFORM DUMP $ROOT CLASSES:" << endl; + for (map::iterator cur = pform_classes.begin() + ; cur != pform_classes.end() ; ++ cur) { + pform_dump(out, cur->second); + } out << "PFORM DUMP PACKAGES:" << endl; for (map::iterator pac = pform_packages.begin() ; pac != pform_packages.end() ; ++ pac) { @@ -1142,6 +1152,12 @@ int main(int argc, char*argv[]) (*idx).second = 0; } + for(map::iterator it = pform_typedefs.begin() + ; it != pform_typedefs.end() ; ++it) { + delete (*it).second; + (*it).second = 0; + } + if (verbose_flag) { if (times_flag) { times(cycles+2); diff --git a/named.h b/named.h index c10367a9f..1086637c5 100644 --- a/named.h +++ b/named.h @@ -1,7 +1,7 @@ -#ifndef __named_H -#define __named_H +#ifndef IVL_named_H +#define IVL_named_H /* - * Copyright (c) 2000-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -31,4 +31,4 @@ template struct named { T parm; }; -#endif +#endif /* IVL_named_H */ diff --git a/net_design.cc b/net_design.cc index a523bf4a4..5dd021390 100644 --- a/net_design.cc +++ b/net_design.cc @@ -134,6 +134,21 @@ NetScope* Design::make_package_scope(perm_string name) return scope; } +void Design::add_class(netclass_t*cl, PClass*pclass) +{ + Definitions::add_class(cl); + class_to_pclass_[cl] = pclass; +} + +netclass_t* Design::find_class(perm_string name) const +{ + map::const_iterator cur = classes_.find(name); + if (cur != classes_.end()) + return cur->second; + + return 0; +} + NetScope* Design::find_package(perm_string name) const { map::const_iterator cur = packages_.find(name); @@ -154,6 +169,17 @@ list Design::find_package_scopes() const return res; } +list Design::find_roottask_scopes() const +{ + listres; + for (map::const_iterator cur = root_tasks_.begin() + ; cur != root_tasks_.end() ; ++ cur) { + res.push_back (cur->first); + } + + return res; +} + /* * This method locates a scope in the design, given its rooted * hierarchical name. Each component of the key is used to scan one @@ -182,7 +208,25 @@ NetScope* Design::find_scope(const std::list&path) const tmp.pop_front(); } + } + for (map::const_iterator root = root_tasks_.begin() + ; root != root_tasks_.end() ; ++ root) { + + NetScope*cur = root->first; + if (path.front() != cur->fullname()) + continue; + + std::list tmp = path; + tmp.pop_front(); + + while (cur) { + if (tmp.empty()) return cur; + + cur = cur->child( tmp.front() ); + + tmp.pop_front(); + } } return 0; @@ -821,6 +865,11 @@ NetScope* Design::find_task(NetScope*scope, const pform_name_t&name) return 0; } +void Design::add_root_task(NetScope*tscope, PTaskFunc*tf) +{ + root_tasks_[tscope] = tf; +} + void Design::add_node(NetNode*net) { assert(net->design_ == 0); diff --git a/net_event.cc b/net_event.cc index 5ad61063a..9b67b5b99 100644 --- a/net_event.cc +++ b/net_event.cc @@ -20,6 +20,7 @@ # include "config.h" # include "compiler.h" # include "netlist.h" +# include "ivl_assert.h" /* * NOTE: The name_ is perm-allocated by the caller. @@ -316,6 +317,10 @@ void NetEvProbe::find_similar_probes(list&plist) for (Link*lcur = nex->first_nlink(); lcur; lcur = lcur->next_nlink()) { NetPins*obj = lcur->get_obj(); + // Skip NexusSet objects + if (obj == 0) + continue; + if (obj->pin_count() != pin_count()) continue; @@ -340,14 +345,14 @@ void NetEvProbe::find_similar_probes(list&plist) } NetEvWait::NetEvWait(NetProc*pr) -: statement_(pr), nevents_(0), events_(0) +: statement_(pr) { } NetEvWait::~NetEvWait() { - if (events_) { - for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) { + if (! events_.empty()) { + for (unsigned idx = 0 ; idx < events_.size() ; idx += 1) { NetEvent*tgt = events_[idx]; tgt->waitref_ -= 1; @@ -365,7 +370,7 @@ NetEvWait::~NetEvWait() delete tmp; } } - delete[]events_; + events_.clear(); } delete statement_; } @@ -374,29 +379,12 @@ void NetEvWait::add_event(NetEvent*tgt) { /* A wait fork is an empty event. */ if (! tgt) { - assert(nevents_ == 0); - nevents_ = 1; - events_ = new NetEvent*[1]; - events_[0] = 0; + assert(events_.empty()); + events_.push_back(0); return; } - if (nevents_ == 0) { - events_ = new NetEvent*[1]; - - } else { - assert(events_[0]); - NetEvent**tmp = new NetEvent*[nevents_+1]; - for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) { - tmp[idx] = events_[idx]; - assert(tmp[idx] != tgt); - } - delete[]events_; - events_ = tmp; - } - - events_[nevents_] = tgt; - nevents_ += 1; + events_.push_back(tgt); // Remember to tell the NetEvent that there is someone // pointing to it. @@ -411,14 +399,14 @@ void NetEvWait::add_event(NetEvent*tgt) void NetEvWait::replace_event(NetEvent*src, NetEvent*repl) { unsigned idx; - for (idx = 0 ; idx < nevents_ ; idx += 1) { + for (idx = 0 ; idx < events_.size() ; idx += 1) { if (events_[idx] == src) break; } - assert(idx < nevents_); + assert(idx < events_.size()); - /* First, remove me from the list held by the src NetEvent. */ + // First, remove me from the list held by the src NetEvent. assert(src->waitref_ > 0); src->waitref_ -= 1; struct NetEvent::wcell_*tmp = src->wlist_; @@ -435,6 +423,7 @@ void NetEvWait::replace_event(NetEvent*src, NetEvent*repl) delete tmp; } + // Replace the src pointer with the repl pointer. events_[idx] = repl; // Remember to tell the replacement NetEvent that there is @@ -448,23 +437,6 @@ void NetEvWait::replace_event(NetEvent*src, NetEvent*repl) } -unsigned NetEvWait::nevents() const -{ - return nevents_; -} - -const NetEvent* NetEvWait::event(unsigned idx) const -{ - assert(idx < nevents_); - return events_[idx]; -} - -NetEvent* NetEvWait::event(unsigned idx) -{ - assert(idx < nevents_); - return events_[idx]; -} - NetProc* NetEvWait::statement() { return statement_; diff --git a/net_expr.cc b/net_expr.cc index c0e92ed4d..fa9e6fe2c 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -321,6 +321,20 @@ const NetScope* NetECRealParam::scope() const } +NetELast::NetELast(NetNet*s) +: sig_(s) +{ +} + +NetELast::~NetELast() +{ +} + +ivl_variable_type_t NetELast::expr_type() const +{ + return IVL_VT_BOOL; +} + NetENetenum::NetENetenum(const netenum_t*s) : netenum_(s) { @@ -362,8 +376,8 @@ NetENull::~NetENull() { } -NetEProperty::NetEProperty(NetNet*net, perm_string pnam) -: net_(net) +NetEProperty::NetEProperty(NetNet*net, perm_string pnam, NetExpr*idx) +: net_(net), index_(idx) { const netclass_t*use_type = dynamic_cast(net->net_type()); assert(use_type); diff --git a/net_func_eval.cc b/net_func_eval.cc index d130f3723..ecbe55780 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -416,8 +416,8 @@ bool NetCase::evaluate_function_vect_(const LineInfo&loc, NetProc*default_statement = 0; - for (unsigned cnt = 0 ; cnt < nitems_ ; cnt += 1) { - Item*item = &items_[cnt]; + for (unsigned cnt = 0 ; cnt < items_.size() ; cnt += 1) { + const Item*item = &items_[cnt]; if (item->guard == 0) { default_statement = item->statement; @@ -478,8 +478,8 @@ bool NetCase::evaluate_function_real_(const LineInfo&loc, NetProc*default_statement = 0; - for (unsigned cnt = 0 ; cnt < nitems_ ; cnt += 1) { - Item*item = &items_[cnt]; + for (unsigned cnt = 0 ; cnt < items_.size() ; cnt += 1) { + const Item*item = &items_[cnt]; if (item->guard == 0) { default_statement = item->statement; @@ -628,6 +628,16 @@ bool NetForever::evaluate_function(const LineInfo&loc, return flag; } +/* + * For now, resort to the block form of the statement until we learn + * to do this directly. + */ +bool NetForLoop::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + return as_block_->evaluate_function(loc, context_map); +} + bool NetRepeat::evaluate_function(const LineInfo&loc, map&context_map) const { diff --git a/net_link.cc b/net_link.cc index 7552a9693..15c67e046 100644 --- a/net_link.cc +++ b/net_link.cc @@ -90,13 +90,19 @@ void Nexus::connect(Link&r) void connect(Link&l, Link&r) { + Nexus*tmp; assert(&l != &r); - if (l.nexus_ != 0) { - connect(l.nexus_, r); - } else if (r.nexus_ != 0) { - connect(r.nexus_, l); + // If either the l or r link already are part of a Nexus, then + // re-use that nexus. Go through some effort so that we are + // not gratuitously creating Nexus object. + if (l.next_ && (tmp=l.find_nexus_())) { + connect(tmp, r); + } else if (r.next_ && (tmp=r.find_nexus_())) { + connect(tmp, l); } else { - Nexus*tmp = new Nexus(l); + // No existing Nexus (both links are so far unconnected) + // so start one. + tmp = new Nexus(l); tmp->connect(r); } } @@ -105,6 +111,8 @@ Link::Link() : dir_(PASSIVE), drive0_(IVL_DR_STRONG), drive1_(IVL_DR_STRONG), next_(0), nexus_(0) { + node_ = 0; + pin_zero_ = true; } Link::~Link() @@ -222,9 +230,11 @@ bool Link::is_linked() const bool Link::is_linked(const Link&that) const { - if (next_ == 0) + // If this or that link is linked to nothing, then they cannot + // be linked to each other. + if (! this->is_linked()) return false; - if (that.next_ == 0) + if (! that.is_linked()) return false; const Link*cur = next_; @@ -504,16 +514,24 @@ const char* Nexus::name() const << obj->name() << " pin " << pin << " type=" << typeid(*obj).name() << "?" << endl; - } - assert(sig); - ostringstream tmp; - tmp << scope_path(sig->scope()) << "." << sig->name(); - if (sig->pin_count() > 1) - tmp << "<" << pin << ">"; + ostringstream tmp; + tmp << "nex=" << this << ends; + const string tmps = tmp.str(); + name_ = new char[strlen(tmps.c_str()) + 1]; + strcpy(name_, tmps.c_str()); + } else { + assert(sig); + ostringstream tmp; + tmp << scope_path(sig->scope()) << "." << sig->name(); + if (sig->pin_count() > 1) + tmp << "<" << pin << ">"; + tmp << ends; + + const string tmps = tmp.str(); + name_ = new char[strlen(tmps.c_str()) + 1]; + strcpy(name_, tmps.c_str()); + } - const string tmps = tmp.str(); - name_ = new char[strlen(tmps.c_str()) + 1]; - strcpy(name_, tmps.c_str()); return name_; } diff --git a/net_nex_input.cc b/net_nex_input.cc index fa2d9ecfc..aff41f281 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -106,6 +106,11 @@ NexusSet* NetEEvent::nex_input(bool) return new NexusSet; } +NexusSet* NetELast::nex_input(bool) +{ + return new NexusSet; +} + NexusSet* NetENetenum::nex_input(bool) { return new NexusSet; @@ -340,7 +345,7 @@ NexusSet* NetCase::nex_input(bool rem_out) if (result == 0) return 0; - for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) { + for (size_t idx = 0 ; idx < items_.size() ; idx += 1) { /* Skip cases that have empty statements. */ if (items_[idx].statement == 0) @@ -406,6 +411,25 @@ NexusSet* NetForce::nex_input(bool) return new NexusSet; } +NexusSet* NetForLoop::nex_input(bool rem_out) +{ + NexusSet*result = init_expr_->nex_input(rem_out); + + NexusSet*tmp = condition_->nex_input(rem_out); + result->add(*tmp); + delete tmp; + + tmp = statement_->nex_input(rem_out); + result->add(*tmp); + delete tmp; + + tmp = step_statement_->nex_input(rem_out); + result->add(*tmp); + delete tmp; + + return result; +} + NexusSet* NetForever::nex_input(bool rem_out) { NexusSet*result = statement_->nex_input(rem_out); diff --git a/net_nex_output.cc b/net_nex_output.cc index 761937fb8..194947955 100644 --- a/net_nex_output.cc +++ b/net_nex_output.cc @@ -60,19 +60,18 @@ void NetAssign_::nex_output(NexusSet&out) } Nexus*nex = sig_->pin(use_word).nexus(); if (base_) { - long tmp = 0; - bool flag = eval_as_long(tmp, base_); - if (!flag) { - // Unable to evaluate the bit/part select of - // the l-value, so this is a mux. Pretty - // sure I don't know how to handle this yet - // in synthesis, so punt for now. - use_base = 0; - use_wid = nex->vector_width(); - } else { - use_base = tmp; - } + // Unable to evaluate the bit/part select of + // the l-value, so this is a mux. Pretty + // sure I don't know how to handle this yet + // in synthesis, so punt for now. + + // Even with constant bit/part select, we want to + // return the entire signal as an output. The + // context will need to sort out which bits are + // actually assigned. + use_base = 0; + use_wid = nex->vector_width(); } out.add(nex, use_base, use_wid); } @@ -102,7 +101,7 @@ void NetBlock::nex_output(NexusSet&out) void NetCase::nex_output(NexusSet&out) { - for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) { + for (size_t idx = 0 ; idx < items_.size() ; idx += 1) { // Empty statements clearly have no output. if (items_[idx].statement == 0) @@ -134,6 +133,11 @@ void NetEvWait::nex_output(NexusSet&out) statement_->nex_output(out); } +void NetForLoop::nex_output(NexusSet&out) +{ + if (statement_) statement_->nex_output(out); +} + void NetPDelay::nex_output(NexusSet&out) { if (statement_) statement_->nex_output(out); diff --git a/net_proc.cc b/net_proc.cc index d9412fa9d..93c746b6d 100644 --- a/net_proc.cc +++ b/net_proc.cc @@ -71,23 +71,18 @@ const NetProc* NetBlock::proc_next(const NetProc*cur) const } NetCase::NetCase(NetCase::TYPE c, NetExpr*ex, unsigned cnt) -: type_(c), expr_(ex), nitems_(cnt) +: type_(c), expr_(ex), items_(cnt) { assert(expr_); - items_ = new Item[nitems_]; - for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) { - items_[idx].statement = 0; - } } NetCase::~NetCase() { delete expr_; - for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) { + for (size_t idx = 0 ; idx < items_.size() ; idx += 1) { delete items_[idx].guard; if (items_[idx].statement) delete items_[idx].statement; } - delete[]items_; } NetCase::TYPE NetCase::type() const @@ -97,7 +92,7 @@ NetCase::TYPE NetCase::type() const void NetCase::set_case(unsigned idx, NetExpr*e, NetProc*p) { - assert(idx < nitems_); + assert(idx < items_.size()); items_[idx].guard = e; items_[idx].statement = p; } @@ -126,6 +121,43 @@ NetForever::~NetForever() delete statement_; } +NetForLoop::NetForLoop(NetNet*ind, NetExpr*iexpr, NetExpr*cond, NetProc*sub, NetProc*step) +: index_(ind), init_expr_(iexpr), condition_(cond), statement_(sub), step_statement_(step) +{ +} + +void NetForLoop::wrap_up() +{ + NetBlock*top = new NetBlock(NetBlock::SEQU, 0); + top->set_line(*this); + + NetAssign_*lv = new NetAssign_(index_); + NetAssign*set_stmt = new NetAssign(lv, init_expr_); + set_stmt->set_line(*init_expr_); + top->append(set_stmt); + + NetBlock*internal_block = new NetBlock(NetBlock::SEQU, 0); + internal_block->set_line(*this); + + if (statement_) internal_block->append(statement_); + internal_block->append(step_statement_); + + NetWhile*wloop = new NetWhile(condition_, internal_block); + wloop->set_line(*this); + + top->append(wloop); + + as_block_ = top; +} + +NetForLoop::~NetForLoop() +{ + delete init_expr_; + delete condition_; + delete statement_; + delete step_statement_; +} + NetPDelay::NetPDelay(uint64_t d, NetProc*st) : delay_(d), expr_(0), statement_(st) { diff --git a/net_scope.cc b/net_scope.cc index e72a31133..1d8653e79 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -96,6 +96,11 @@ const NetExpr* Definitions::enumeration_expr(perm_string key) } } +void Definitions::add_class(netclass_t*net_class) +{ + classes_[net_class->get_name()] = net_class; +} + /* * The NetScope class keeps a scope tree organized. Each node of the * scope tree points to its parent, its right sibling and its leftmost @@ -130,7 +135,6 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bo time_unit_ = 0; time_prec_ = 0; time_from_timescale_ = false; - assert(t==MODULE || t==PACKAGE || t==CLASS); } switch (t) { @@ -189,6 +193,22 @@ void NetScope::set_line(perm_string file, perm_string def_file, def_lineno_ = def_lineno; } +/* + * Look for the enumeration in the current scope and any parent scopes. + */ +const netenum_t*NetScope::find_enumeration_for_name(perm_string name) +{ + NetScope *cur_scope = this; + while (cur_scope) { + NetEConstEnum*tmp = cur_scope->enum_names_[name]; + if (tmp) break; + cur_scope = cur_scope->parent(); + } + + assert(cur_scope); + return cur_scope->enum_names_[name]->enumeration(); +} + void NetScope::set_parameter(perm_string key, bool is_annotatable, PExpr*val, ivl_variable_type_t type__, PExpr*msb, PExpr*lsb, bool signed_flag, @@ -616,14 +636,9 @@ NetNet* NetScope::find_signal(perm_string key) return 0; } -void NetScope::add_class(netclass_t*net_class) -{ - classes_[net_class->get_name()] = net_class; -} - netclass_t*NetScope::find_class(perm_string name) { - // Special class: The scope itself is the class that we are + // Special case: The scope itself is the class that we are // looking for. This may happen for example when elaborating // methods within the class. if (type_==CLASS && name_==hname_t(name)) @@ -638,6 +653,13 @@ netclass_t*NetScope::find_class(perm_string name) if (type_==MODULE) return 0; + if (up_==0 && type_==CLASS) { + assert(class_def_); + + NetScope*def_parent = class_def_->definition_scope(); + return def_parent->find_class(name); + } + // If there is no further to look, ... if (up_ == 0) return 0; @@ -668,6 +690,47 @@ const NetScope* NetScope::child(const hname_t&name) const return cur->second; } +/* Helper function to see if the given scope is defined in a class and if + * so return the class scope. */ +const NetScope* NetScope::get_class_scope() const +{ + const NetScope*scope = this; + while (scope) { + switch(scope->type()) { + case NetScope::CLASS: + return scope; + case NetScope::TASK: + case NetScope::FUNC: + case NetScope::BEGIN_END: + case NetScope::FORK_JOIN: + break; + case NetScope::MODULE: + case NetScope::GENBLOCK: + case NetScope::PACKAGE: + return 0; + default: + assert(0); + } + scope = scope->parent(); + } + return scope; +} + +const NetScope* NetScope::child_byname(perm_string name) const +{ + hname_t hname (name); + map::const_iterator cur = children_.lower_bound(hname); + + if (cur == children_.end()) + return 0; + + if (cur->first.peek_name() == name) + return cur->second; + + return 0; +} + + perm_string NetScope::local_symbol() { ostringstream res; diff --git a/netclass.cc b/netclass.cc index f302585d1..0ae3ba1dc 100644 --- a/netclass.cc +++ b/netclass.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 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 @@ -24,7 +24,7 @@ using namespace std; netclass_t::netclass_t(perm_string name, netclass_t*sup) -: name_(name), super_(sup), class_scope_(0) +: name_(name), super_(sup), class_scope_(0), definition_scope_(0) { } @@ -50,10 +50,16 @@ bool netclass_t::set_property(perm_string pname, property_qualifier_t qual, ivl_ return true; } -void netclass_t::set_class_scope(NetScope*class_scope) +void netclass_t::set_class_scope(NetScope*class_scope__) { assert(class_scope_ == 0); - class_scope_ = class_scope; + class_scope_ = class_scope__; +} + +void netclass_t::set_definition_scope(NetScope*use_definition_scope) +{ + assert(definition_scope_ == 0); + definition_scope_ = use_definition_scope; } ivl_variable_type_t netclass_t::base_type() const diff --git a/netclass.h b/netclass.h index bdde11058..b6d26e114 100644 --- a/netclass.h +++ b/netclass.h @@ -1,7 +1,7 @@ -#ifndef __netclass_H -#define __netclass_H +#ifndef IVL_netclass_H +#define IVL_netclass_H /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 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 @@ -43,9 +43,21 @@ class netclass_t : public ivl_type_s { bool set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype); // Set the scope for the class. The scope has no parents and - // is used for the elaboration of methods (tasks/functions). + // is used for the elaboration of methods + // (tasks/functions). In other words, this is the class itself. void set_class_scope(NetScope*cscope); + inline const NetScope* class_scope(void) const { return class_scope_; } + + // Set the scope for the class definition. This is the scope + // where the class definition was encountered, and may be used + // to locate symbols that the class definition may inherit + // from its context. This can be nil, or a package or module + // where a class is defined. + void set_definition_scope(NetScope*dscope); + + NetScope*definition_scope(void); + // As an ivl_type_s object, the netclass is always an // ivl_VT_CLASS object. ivl_variable_type_t base_type() const; @@ -74,7 +86,8 @@ class netclass_t : public ivl_type_s { bool test_for_missing_initializers(void) const; - // Map the name of a property to its index. + // Map the name of a property to its index. Return <0 if the + // name is not a property in the class. int property_idx_from_name(perm_string pname) const; // The task method scopes from the method name. @@ -94,7 +107,9 @@ class netclass_t : public ivl_type_s { void elaborate(Design*des, PClass*pclass); void emit_scope(struct target_t*tgt) const; + bool emit_defs(struct target_t*tgt) const; + std::ostream& debug_dump(std::ostream&fd) const; void dump_scope(ostream&fd) const; private: @@ -115,6 +130,14 @@ class netclass_t : public ivl_type_s { // This holds task/function definitions for methods. NetScope*class_scope_; + + // This holds the context for the class type definition. + NetScope*definition_scope_; }; -#endif +inline NetScope*netclass_t::definition_scope(void) +{ + return definition_scope_; +} + +#endif /* IVL_netclass_H */ diff --git a/netdarray.h b/netdarray.h index 509e32d73..e97465b5b 100644 --- a/netdarray.h +++ b/netdarray.h @@ -1,7 +1,7 @@ -#ifndef __netdarray_H -#define __netdarray_H +#ifndef IVL_netdarray_H +#define IVL_netdarray_H /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 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 @@ -48,4 +48,4 @@ class netdarray_t : public netarray_t { bool test_compatibility(ivl_type_t that) const; }; -#endif +#endif /* IVL_netdarray_H */ diff --git a/netenum.h b/netenum.h index a66fbc237..8b43086cf 100644 --- a/netenum.h +++ b/netenum.h @@ -1,7 +1,7 @@ -#ifndef __netenum_H -#define __netenum_H +#ifndef IVL_netenum_H +#define IVL_netenum_H /* - * Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -80,4 +80,4 @@ inline ivl_variable_type_t netenum_t::base_type() const inline size_t netenum_t::size() const { return names_.size(); } -#endif +#endif /* IVL_netenum_H */ diff --git a/netlist.cc b/netlist.cc index e66c9c7c9..44f142246 100644 --- a/netlist.cc +++ b/netlist.cc @@ -31,6 +31,7 @@ # include "netdarray.h" # include "netenum.h" # include "netparray.h" +# include "netqueue.h" # include "netstruct.h" # include "netvector.h" # include "ivl_assert.h" @@ -180,7 +181,11 @@ NetPins::NetPins(unsigned npins) NetPins::~NetPins() { - delete[] pins_; + if (pins_) { + assert(pins_[0].node_ == this); + assert(pins_[0].pin_zero_); + delete[] pins_; + } } Link& NetPins::pin(unsigned idx) @@ -194,7 +199,7 @@ Link& NetPins::pin(unsigned idx) } assert(idx < npins_); - assert(idx == 0? pins_[0].pin_zero_ : pins_[idx].pin_==idx); + assert(idx == 0? (pins_[0].pin_zero_ && pins_[0].node_==this) : pins_[idx].pin_==idx); return pins_[idx]; } @@ -208,7 +213,7 @@ const Link& NetPins::pin(unsigned idx) const } assert(pins_); assert(idx < npins_); - assert(idx == 0? pins_[0].pin_zero_ : pins_[idx].pin_==idx); + assert(idx == 0? (pins_[0].pin_zero_ && pins_[0].node_==this) : pins_[idx].pin_==idx); return pins_[idx]; } @@ -557,6 +562,8 @@ void NetNet::calculate_slice_widths_from_packed_dims_(void) } } +const list NetNet::not_an_array; + NetNet::NetNet(NetScope*s, perm_string n, Type t, const list&unpacked, ivl_type_t use_net_type) : NetObj(s, n, calculate_count(unpacked)), @@ -748,6 +755,11 @@ const netdarray_t* NetNet::darray_type(void) const return dynamic_cast (net_type_); } +const netqueue_t* NetNet::queue_type(void) const +{ + return dynamic_cast (net_type_); +} + const netclass_t* NetNet::class_type(void) const { return dynamic_cast (net_type_); @@ -762,6 +774,9 @@ const netclass_t* NetNet::class_type(void) const * 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. + * + * NOTE: The caller should already have accounted for unpacked + * dimensions. The "depth" is only for the packed dimensions. */ unsigned long NetNet::slice_width(size_t depth) const { @@ -868,17 +883,25 @@ unsigned NetNet::peek_eref() const * Test each of the bits in the range, and set them. If any bits are * already set then return true. */ -bool NetNet::test_and_set_part_driver(unsigned pmsb, unsigned plsb) +bool NetNet::test_and_set_part_driver(unsigned pmsb, unsigned plsb, int widx) { if (lref_mask_.empty()) - lref_mask_.resize(vector_width()); + lref_mask_.resize(vector_width() * pin_count()); + + // If indexing a word that doesn't exist, then pretend this is + // never driven. + if (widx < 0) + return false; + if (widx >= (int)pin_count()) + return false; bool rc = false; + unsigned word_base = vector_width() * widx; for (unsigned idx = plsb ; idx <= pmsb ; idx += 1) { - if (lref_mask_[idx]) + if (lref_mask_[idx+word_base]) rc = true; else - lref_mask_[idx] = true; + lref_mask_[idx+word_base] = true; } return rc; @@ -972,6 +995,20 @@ unsigned NetPartSelect::base() const return off_; } +NetSubstitute::NetSubstitute(NetNet*sig, NetNet*sub, unsigned wid, unsigned off) +: NetNode(sig->scope(), sig->scope()->local_symbol(), 3), wid_(wid), off_(off) +{ + pin(0).set_dir(Link::OUTPUT); + pin(1).set_dir(Link::INPUT); + pin(2).set_dir(Link::INPUT); + connect(pin(1), sig->pin(0)); + connect(pin(2), sub->pin(0)); +} + +NetSubstitute::~NetSubstitute() +{ +} + NetProc::NetProc() : next_(0) { @@ -1888,8 +1925,8 @@ unsigned NetBUFZ::width() const return width_; } -NetCaseCmp::NetCaseCmp(NetScope*s, perm_string n, unsigned wid, bool eeq__) -: NetNode(s, n, 3), width_(wid), eeq_(eeq__) +NetCaseCmp::NetCaseCmp(NetScope*s, perm_string n, unsigned wid, kind_t k) +: NetNode(s, n, 3), width_(wid), kind_(k) { pin(0).set_dir(Link::OUTPUT); pin(1).set_dir(Link::INPUT); @@ -1905,11 +1942,6 @@ unsigned NetCaseCmp::width() const return width_; } -bool NetCaseCmp::eeq() const -{ - return eeq_; -} - NetCondit::NetCondit(NetExpr*ex, NetProc*i, NetProc*e) : expr_(ex), if_(i), else_(e) { @@ -2745,6 +2777,11 @@ DelayType NetForever::delay_type() const return statement_->delay_type(); } +DelayType NetForLoop::delay_type() const +{ + return get_loop_delay_type(condition_, statement_); +} + DelayType NetPDelay::delay_type() const { if (expr_) { diff --git a/netlist.h b/netlist.h index 81b62b5d4..19cf46bc7 100644 --- a/netlist.h +++ b/netlist.h @@ -1,7 +1,7 @@ -#ifndef __netlist_H -#define __netlist_H +#ifndef IVL_netlist_H +#define IVL_netlist_H /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -74,12 +74,15 @@ class NetRamDq; class NetTaskDef; class NetEvTrig; class NetEvWait; +class PClass; class PExpr; class PFunction; +class PTaskFunc; struct enum_type_t; class netclass_t; class netdarray_t; class netparray_t; +class netqueue_t; class netenum_t; class netstruct_t; class netvector_t; @@ -153,11 +156,16 @@ class Link { bool is_equal(const Link&that) const; // Return information about the object that this link is - // a part of. + // a part of. Note that the get_obj() method can return NIL if + // this Link is part of a NexusSet. That should be OK, because + // they are collection variables, and not functional parts of + // a design. const NetPins*get_obj() const; NetPins*get_obj(); unsigned get_pin() const; + void dump_link(ostream&fd, unsigned ind) const; + private: // The NetNode manages these. They point back to the // NetNode so that following the links can get me here. @@ -205,6 +213,10 @@ class NetPins : public LineInfo { bool pins_are_virtual(void) const; void devirtualize_pins(void); + // This is for showing a brief description of the object to + // the stream. It is used for debug and diagnostics. + virtual void show_type(std::ostream&fd) const; + private: Link*pins_; const unsigned npins_; @@ -255,6 +267,8 @@ class NetObj : public NetPins, public Attrib { void dump_obj_attr(ostream&, unsigned) const; + virtual void show_type(std::ostream&fd) const; + private: NetScope*scope_; perm_string name_; @@ -383,6 +397,11 @@ class Nexus { verinum::V driven_value() const; verinum driven_vector() const; + /* Return a mask of the bits of this vector that are + driven. This is usually all false or all true, but in + special cases it may be a blend. */ + std::vector driven_mask(void)const; + /* The code generator sets an ivl_nexus_t to attach code generation details to the nexus. */ ivl_nexus_t t_cookie() const { return t_cookie_; } @@ -610,6 +629,7 @@ public: static Enum merged( Enum lhs, Enum rhs ); }; +extern std::ostream& operator << (std::ostream&, PortType::Enum); /* * Information on actual ports (rather than port-connected signals) of @@ -633,6 +653,8 @@ class NetNet : public NetObj, public PortType { typedef PortType::Enum PortType; + static const std::listnot_an_array; + public: // This form is the more generic form of the constructor. For // now, the unpacked type is not buried into an ivl_type_s object. @@ -676,6 +698,7 @@ class NetNet : public NetObj, public PortType { const netenum_t*enumeration(void) const; const netstruct_t*struct_type(void) const; const netdarray_t*darray_type(void) const; + const netqueue_t*queue_type(void) const; const netclass_t*class_type(void) const; /* Attach a discipline to the net. */ @@ -749,8 +772,10 @@ class NetNet : public NetObj, public PortType { // Treating this node as a uwire, this function tests whether // any bits in the canonical part are already driven. This is - // only useful for UNRESOLVED_WIRE objects. - bool test_and_set_part_driver(unsigned msb, unsigned lsb); + // only useful for UNRESOLVED_WIRE objects. The msb and lsb + // are the part select of the signal, and the widx is the word + // index if this is an unpacked array. + bool test_and_set_part_driver(unsigned msb, unsigned lsb, int widx =0); unsigned get_refs() const; @@ -865,6 +890,9 @@ class Definitions { // value. const NetExpr* enumeration_expr(perm_string key); + // Definitions scopes can also hold classes, by name. + void add_class(netclass_t*class_type); + protected: // Enumerations. The enum_sets_ is a list of all the // enumerations present in this scope. The enum_names_ is a @@ -873,6 +901,9 @@ class Definitions { std::map enum_sets_; std::map enum_names_; + // This is a map of all the classes (by name) in this scope. + std::map classes_; + }; /* @@ -896,6 +927,10 @@ class NetScope : public Definitions, public Attrib { if a unique name couldn't be generated. */ bool auto_name(const char* prefix, char pad, const char* suffix); + /* Routine to search for the enumeration given a name. It basically + * does what enumeration_for_name() does but searched the hierarchy. */ + const netenum_t*find_enumeration_for_name(perm_string name); + /* 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 @@ -953,7 +988,6 @@ class NetScope : public Definitions, public Attrib { void rem_signal(NetNet*); NetNet* find_signal(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 @@ -963,6 +997,15 @@ class NetScope : public Definitions, public Attrib { const NetScope* parent() const { return up_; } const NetScope* child(const hname_t&name) const; + /* A helper function to find the enclosing class scope. */ + const NetScope* get_class_scope() const; + + // Look for a child scope by name. This ignores the number + // part of the child scope name, so there may be multiple + // matches. Only return one. This function is only really + // useful for some elaboration error checking. + const NetScope* child_byname(perm_string name) const; + // Nested modules have slightly different scope search rules. inline bool nested_module() const { return nested_module_; } // Program blocks have elaboration constraints. @@ -1163,6 +1206,8 @@ class NetScope : public Definitions, public Attrib { perm_string genvar_tmp; long genvar_tmp_val; + std::map loop_index_tmp; + private: void evaluate_parameter_logic_(Design*des, param_ref_t cur); void evaluate_parameter_real_(Design*des, param_ref_t cur); @@ -1204,8 +1249,6 @@ class NetScope : public Definitions, public Attrib { const PFunction*func_pform_; unsigned elab_stage_; - std::map classes_; - NetScope*up_; map children_; @@ -2163,6 +2206,40 @@ class NetPartSelect : public NetNode { bool signed_flag_; }; +/* + * This device supports simple substitution of a part within a wider + * vector. For example, this: + * + * wire [7:0] foo = NetSubstitute(bar, bat, off); + * + * meaus that bar is a vector the same width as foo, bat is a narrower + * vector. The off is a constant offset into the bar vector. This + * looks something like this: + * + * foo = bar; + * foo[off +: ] = bat; + * + * There is no direct way in Verilog to express this (as a single + * device), it instead turns up in certain synthesis situation, + * i.e. the example above. + */ +class NetSubstitute : public NetNode { + + public: + NetSubstitute(NetNet*sig, NetNet*sub, unsigned wid, unsigned off); + ~NetSubstitute(); + + inline unsigned width() const { return wid_; } + inline unsigned base() const { return off_; } + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*tgt) const; + + private: + unsigned wid_; + unsigned off_; +}; + /* * The NetBUFZ is a magic device that represents the continuous * assign, with the output being the target register and the input @@ -2199,30 +2276,43 @@ class NetBUFZ : public NetNode { * input. The elaboration, btw, needs to make sure the input widths * match. * + * The case compare can be generated to handle ===/!==, or also + * to test guards in the case/casez/casex statements. + * * This pins are assigned as: * * 0 -- Output (always returns 0 or 1) * 1 -- Input - * 2 -- Input + * 2 -- Input (windcard input for EQX and EQZ variants) */ class NetCaseCmp : public NetNode { public: - explicit NetCaseCmp(NetScope*s, perm_string n, unsigned wid, bool eeq); + enum kind_t { + EEQ, // === + NEQ, // !== + XEQ, // casex guard tests + ZEQ // casez guard tests + }; + + public: + explicit NetCaseCmp(NetScope*s, perm_string n, unsigned wid, kind_t eeq); ~NetCaseCmp(); unsigned width() const; - // true if this is ===, false if this is !== - bool eeq() const; + // What kind of case compare? + inline kind_t kind() const { return kind_; } virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: unsigned width_; - bool eeq_; + const kind_t kind_; }; +extern ostream& operator << (ostream&fd, NetCaseCmp::kind_t that); + /* NOTE: This class should be replaced with the NetLiteral class * below, that is more general in that it supports different types of * values. @@ -2524,7 +2614,8 @@ class NetProc : public virtual LineInfo { // picked off by e.g. condit statements as set/reset inputs to // the flipflop being generated. virtual bool synth_sync(Design*des, NetScope*scope, - NetNet*ff_clock, NetNet*ff_ce, + NetNet*ff_clock, NetBus&ff_ce, + NetBus&ff_aclr, NetBus&ff_aset, NexusSet&nex_map, NetBus&nex_out, const std::vector&events); @@ -2533,6 +2624,11 @@ class NetProc : public virtual LineInfo { // Recursively checks to see if there is delay in this element. virtual DelayType delay_type() const; + protected: + bool synth_async_block_substatement_(Design*des, NetScope*scope, + NexusSet&nex_map, + NetBus&accumulated_nex_out, + NetProc*substmt); private: friend class NetBlock; NetProc*next_; @@ -2799,7 +2895,8 @@ class NetBlock : public NetProc { NetBus&accumulated_nex_out); bool synth_sync(Design*des, NetScope*scope, - NetNet*ff_clk, NetNet*ff_ce, + NetNet*ff_clk, NetBus&ff_ce, + NetBus&ff_aclr,NetBus&ff_aset, NexusSet&nex_map, NetBus&nex_out, const std::vector&events); @@ -2844,10 +2941,10 @@ class NetCase : public NetProc { TYPE type() const; const NetExpr*expr() const { return expr_; } - unsigned nitems() const { return nitems_; } + inline unsigned nitems() const { return items_.size(); } - const NetExpr*expr(unsigned idx) const { return items_[idx].guard;} - const NetProc*stat(unsigned idx) const { return items_[idx].statement; } + inline const NetExpr*expr(unsigned idx) const { return items_[idx].guard;} + inline const NetProc*stat(unsigned idx) const { return items_[idx].statement; } virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&out); @@ -2868,16 +2965,20 @@ class NetCase : public NetProc { bool evaluate_function_real_(const LineInfo&loc, map&ctx) const; + bool synth_async_casez_(Design*des, NetScope*scope, + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out); + TYPE type_; struct Item { + inline Item() : guard(0), statement(0) { } NetExpr*guard; NetProc*statement; }; NetExpr* expr_; - unsigned nitems_; - Item*items_; + std::vectoritems_; }; /* @@ -2933,7 +3034,8 @@ class NetCondit : public NetProc { NetBus&accumulated_nex_out); bool synth_sync(Design*des, NetScope*scope, - NetNet*ff_clk, NetNet*ff_ce, + NetNet*ff_clk, NetBus&ff_ce, + NetBus&ff_aclr,NetBus&ff_aset, NexusSet&nex_map, NetBus&nex_out, const std::vector&events); @@ -3184,9 +3286,9 @@ class NetEvWait : public NetProc { void add_event(NetEvent*tgt); void replace_event(NetEvent*orig, NetEvent*repl); - unsigned nevents() const; - const NetEvent*event(unsigned) const; - NetEvent*event(unsigned); + inline unsigned nevents() const { return events_.size(); } + inline const NetEvent*event(unsigned idx) const { return events_[idx]; } + inline NetEvent*event(unsigned idx) { return events_[idx]; } NetProc*statement(); @@ -3209,7 +3311,8 @@ class NetEvWait : public NetProc { NetBus&accumulated_nex_out); virtual bool synth_sync(Design*des, NetScope*scope, - NetNet*ff_clk, NetNet*ff_ce, + NetNet*ff_clk, NetBus&ff_ce, + NetBus&ff_aclr,NetBus&ff_aset, NexusSet&nex_map, NetBus&nex_out, const std::vector&events); @@ -3220,9 +3323,8 @@ class NetEvWait : public NetProc { private: NetProc*statement_; - - unsigned nevents_; - NetEvent**events_; + // Events that I might wait for. + std::vectorevents_; }; ostream& operator << (ostream&out, const NetEvWait&obj); @@ -3294,6 +3396,44 @@ class NetForever : public NetProc { NetProc*statement_; }; +class NetForLoop : public NetProc { + + public: + explicit NetForLoop(NetNet*index, NetExpr*initial_expr, NetExpr*cond, + NetProc*sub, NetProc*step); + ~NetForLoop(); + + void wrap_up(); + + void emit_recurse(struct target_t*) const; + + virtual NexusSet* nex_input(bool rem_out = true); + virtual void nex_output(NexusSet&); + 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; + + // synthesize as asynchronous logic, and return true. + bool synth_async(Design*des, NetScope*scope, + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out); + + private: + NetNet*index_; + NetExpr*init_expr_; + NetExpr*condition_; + NetProc*statement_; + NetProc*step_statement_; + + // The code generator needs to see this rewritten as a while + // loop with synthetic statements. This is a hack that I + // should probably take out later as the ivl_target learns + // about for loops. + NetBlock*as_block_; +}; + class NetFree : public NetProc { public: @@ -3485,6 +3625,31 @@ class NetTaskDef : public NetBaseDef { NetTaskDef& operator= (const NetTaskDef&); }; +/* + * The NetELast expression node takes as an argument a net, that is + * intended to be a queue or dynamic array object. The return value is + * the index of the last item in the node. This is intended to + * implement the '$' is the expression "foo[$]". + */ +class NetELast : public NetExpr { + + public: + explicit NetELast(NetNet*sig); + ~NetELast(); + + inline const NetNet*sig() const { return sig_; } + + virtual ivl_variable_type_t expr_type() const; + virtual void dump(std::ostream&) const; + + virtual void expr_scan(struct expr_scan_t*) const; + virtual NetELast*dup_expr() const; + virtual NexusSet* nex_input(bool rem_out = true); + + private: + NetNet*sig_; +}; + /* * This node represents a function call in an expression. The object * contains a pointer to the function definition, which is used to @@ -4136,14 +4301,18 @@ class NetENull : public NetExpr { * The NetEProperty represents a SystemVerilog property 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. + * + * The canon_index is an optional expression to address an element for + * parameters that are arrays. */ class NetEProperty : public NetExpr { public: - NetEProperty(NetNet*n, perm_string pname); + NetEProperty(NetNet*n, perm_string pname, NetExpr*canon_index =0); ~NetEProperty(); inline const NetNet* get_sig() const { return net_; } inline size_t property_idx() const { return pidx_; } + inline const NetExpr*get_index() const { return index_; } public: // Overridden methods ivl_variable_type_t expr_type() const; @@ -4156,6 +4325,7 @@ class NetEProperty : public NetExpr { private: NetNet*net_; size_t pidx_; + NetExpr*index_; }; /* @@ -4628,6 +4798,11 @@ class Design : public Definitions { // Look for defparams that never matched, and print warnings. void residual_defparams(); + // Do elaborate_sig for objects in $root scope. + void root_elaborate_sig(void); + + void root_elaborate(void); + /* This method locates a signal, starting at a given scope. The name parameter may be partially hierarchical, so this method, unlike the NetScope::find_signal method, @@ -4640,6 +4815,12 @@ class Design : public Definitions { // Tasks NetScope* find_task(NetScope*scope, const pform_name_t&name); + void add_root_task(NetScope*tscope, PTaskFunc*tf); + std::list find_roottask_scopes(void) const; + + // Find a class in the $root scope. + void add_class(netclass_t*cl, PClass*pclass); + netclass_t* find_class(perm_string name) const; // NODES void add_node(NetNode*); @@ -4675,6 +4856,12 @@ class Design : public Definitions { // packages do not nest. std::mappackages_; + // Tasks in the $root scope + std::maproot_tasks_; + + // Need this for elaboration of $root scope pclass objects. + std::map class_to_pclass_; + // List the nodes in the design. NetNode*nodes_; // These are in support of the node functor iterator. @@ -4800,4 +4987,4 @@ inline unsigned Link::get_pin() const return pin_; } -#endif +#endif /* IVL_netlist_H */ diff --git a/netmisc.cc b/netmisc.cc index e08f3a9f1..8a676685e 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -20,7 +20,9 @@ # include "config.h" # include +# include # include "netlist.h" +# include "netparray.h" # include "netvector.h" # include "netmisc.h" # include "PExpr.h" @@ -319,7 +321,7 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, 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; + min_wid += 2; /* Pad the base expression to the correct width. */ base = pad_to_width(base, min_wid, *base); /* If the base expression is unsigned and either the lsb @@ -354,7 +356,7 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, 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; + min_wid += 2; /* 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 @@ -537,10 +539,8 @@ static void make_strides(const vector&dims, * 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) +static NetExpr* normalize_variable_unpacked(const vector&dims, 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()); @@ -570,10 +570,20 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) return canonical_expr; } -NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) { const vector&dims = net->unpacked_dims(); + return normalize_variable_unpacked(dims, indices); +} +NetExpr* normalize_variable_unpacked(const netsarray_t*stype, list&indices) +{ + const vector&dims = stype->static_dimensions(); + return normalize_variable_unpacked(dims, indices); +} + +NetExpr* normalize_variable_unpacked(const LineInfo&loc, const vector&dims, list&indices) +{ // Make strides for each index. The stride is the distance (in // words) to the next element in the canonical array. vector stride (dims.size()); @@ -606,14 +616,14 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) // 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; + if (use_stride != 1) + min_wid += num_bits(use_stride); - tmp = pad_to_width(tmp, min_wid, *net); + tmp = pad_to_width(tmp, min_wid, loc); // Now generate the math to calculate the canonical address. NetExpr*tmp_scaled = 0; @@ -652,11 +662,54 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) // 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); + ivl_assert(loc, canonical_expr); return canonical_expr; } +NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +{ + const vector&dims = net->unpacked_dims(); + return normalize_variable_unpacked(*net, dims, indices); +} + +NetExpr* normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*stype, list&indices) +{ + const vector&dims = stype->static_dimensions(); + return normalize_variable_unpacked(loc, dims, indices); +} + +NetExpr* make_canonical_index(Design*des, NetScope*scope, + const LineInfo*loc, + const std::list&src, + const netsarray_t*stype, + bool need_const) +{ + NetExpr*canon_index = 0; + + list indices_const; + list indices_expr; + indices_flags flags; + indices_to_expressions(des, scope, loc, + src, src.size(), + need_const, stype->static_dimensions().size(), + flags, + indices_expr, indices_const); + + if (flags.undefined) { + cerr << loc->get_fileline() << ": warning: " + << "ignoring undefined value array access." << endl; + + } else if (flags.variable) { + canon_index = normalize_variable_unpacked(*loc, stype, indices_expr); + + } else { + canon_index = normalize_variable_unpacked(stype, indices_const); + } + + return canon_index; +} + NetEConst* make_const_x(unsigned long wid) { verinum xxx (verinum::Vx, wid); @@ -678,6 +731,14 @@ NetEConst* make_const_val(unsigned long value) return res; } +NetEConst* make_const_val_s(long value) +{ + verinum tmp (value, integer_width); + tmp.has_sign(true); + NetEConst*res = new NetEConst(tmp); + return res; +} + NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid) { verinum xxx (verinum::Vx, wid); @@ -781,13 +842,14 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe, // If we can get the same result using a smaller expression // width, do so. - if ((context_width > 0) && (!force_expand) - && (pe->expr_type() != IVL_VT_REAL) - && (expr_width > pos_context_width)) { - expr_width = max(pe->min_width(), pos_context_width); + + unsigned min_width = pe->min_width(); + if ((min_width != UINT_MAX) && (pe->expr_type() != IVL_VT_REAL) + && (pos_context_width > 0) && (expr_width > pos_context_width)) { + expr_width = max(min_width, pos_context_width); if (debug_elaborate) { - cerr << pe->get_fileline() << ": " + cerr << pe->get_fileline() << ": : " << "pruned to width=" << expr_width << endl; } } @@ -926,6 +988,48 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, return tmp; } +bool evaluate_ranges(Design*des, NetScope*scope, + vector&llist, + const list&rlist) +{ + bool bad_msb = false, bad_lsb = false; + + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + long use_msb, use_lsb; + + NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); + if (! eval_as_long(use_msb, texpr)) { + cerr << cur->first->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->first->get_fileline() << " : " + "This MSB expression violates the rule: " + << *cur->first << endl; + des->errors += 1; + bad_msb = true; + } + + delete texpr; + + texpr = elab_and_eval(des, scope, cur->second, -1, true); + if (! eval_as_long(use_lsb, texpr)) { + cerr << cur->second->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->second->get_fileline() << " : " + "This LSB expression violates the rule: " + << *cur->second << endl; + des->errors += 1; + bad_lsb = true; + } + + delete texpr; + + llist.push_back(netrange_t(use_msb, use_lsb)); + } + + return bad_msb | bad_lsb; +} + void eval_expr(NetExpr*&expr, int context_width) { assert(expr); @@ -1001,50 +1105,48 @@ hname_t eval_path_component(Design*des, NetScope*scope, if (comp.index.empty()) return hname_t(comp.name); - // The parser will assure that path components will have only - // one index. For example, foo[N] is one index, foo[n][m] is two. - assert(comp.index.size() == 1); + vector index_values; - const index_component_t&index = comp.index.front(); + for (list::const_iterator cur = comp.index.begin() + ; cur != comp.index.end() ; ++cur) { + const index_component_t&index = *cur; - if (index.sel != index_component_t::SEL_BIT) { - cerr << index.msb->get_fileline() << ": error: " - << "Part select is not valid for this kind of object." << endl; - des->errors += 1; - return hname_t(comp.name, 0); - } + if (index.sel != index_component_t::SEL_BIT) { + cerr << index.msb->get_fileline() << ": error: " + << "Part select is not valid for this kind of object." << endl; + des->errors += 1; + return hname_t(comp.name, 0); + } - // The parser will assure that path components will have only - // bit select index expressions. For example, "foo[n]" is OK, - // but "foo[n:m]" is not. - assert(index.sel == index_component_t::SEL_BIT); + // The parser will assure that path components will have only + // bit select index expressions. For example, "foo[n]" is OK, + // but "foo[n:m]" is not. + assert(index.sel == index_component_t::SEL_BIT); - // Evaluate the bit select to get a number. - NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); - ivl_assert(*index.msb, tmp); - - // Now we should have a constant value for the bit select - // expression, and we can use it to make the final hname_t - // value, for example "foo[5]". - if (NetEConst*ctmp = dynamic_cast(tmp)) { - hname_t res(comp.name, ctmp->value().as_long()); - delete ctmp; - return res; - } + // Evaluate the bit select to get a number. + NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); + ivl_assert(*index.msb, tmp); + if (NetEConst*ctmp = dynamic_cast(tmp)) { + index_values.push_back(ctmp->value().as_long()); + delete ctmp; + continue; + } #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. - cerr << index.msb->get_fileline() << ": error: " - << "Scope index expression is not constant: " - << *index.msb << endl; - des->errors += 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. + cerr << index.msb->get_fileline() << ": error: " + << "Scope index expression is not constant: " + << *index.msb << endl; + des->errors += 1; #endif - error_flag = true; + error_flag = true; - delete tmp; - return hname_t (comp.name, 0); + delete tmp; + } + + return hname_t(comp.name, index_values); } std::list eval_scope_path(Design*des, NetScope*scope, @@ -1389,3 +1491,123 @@ NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net, eval_expr(res, -1); return res; } + +void assign_unpacked_with_bufz(Design*des, NetScope*scope, + const LineInfo*loc, + NetNet*lval, NetNet*rval) +{ + ivl_assert(*loc, lval->pin_count()==rval->pin_count()); + + for (unsigned idx = 0 ; idx < lval->pin_count() ; idx += 1) { + NetBUFZ*driver = new NetBUFZ(scope, scope->local_symbol(), + lval->vector_width(), false); + driver->set_line(*loc); + des->add_node(driver); + + connect(lval->pin(idx), driver->pin(0)); + connect(driver->pin(1), rval->pin(idx)); + } +} + +/* + * synthesis sometimes needs to unpack assignment to a part + * select. That looks like this: + * + * foo[N] <= ; + * + * The NetAssignBase::synth_async() method will turn that into a + * netlist like this: + * + * NetAssignBase(PV) --> base()== + * (0) (1) + * | | + * v v + * foo + * + * This search will return a pointer to the NetAssignBase(PV) object, + * but only if it matches this pattern. + */ +NetPartSelect* detect_partselect_lval(Link&pin) +{ + NetPartSelect*found_ps = 0; + + Nexus*nex = pin.nexus(); + for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) { + NetPins*obj; + unsigned obj_pin; + cur->cur_link(obj, obj_pin); + + // Skip NexusSet objects. + if (obj == 0) + continue; + + // NetNet pins have no effect on this search. + if (dynamic_cast (obj)) + continue; + + if (NetPartSelect*ps = dynamic_cast (obj)) { + + // If this is the input side of a NetPartSelect, skip. + if (ps->pin(obj_pin).get_dir()==Link::INPUT) + continue; + + // Oops, driven by the wrong size of a + // NetPartSelect, so this is not going to work out. + if (ps->dir()==NetPartSelect::VP) + return 0; + + // So now we know this is a NetPartSelect::PV. It + // is a candidate for our part-select assign. If + // we already have a candidate, then give up. + if (found_ps) + return 0; + + // This is our candidate. Carry on. + found_ps = ps; + continue; + + } + + // If this is a driver to the Nexus that is not a + // NetPartSelect device. This cannot happen to + // part selected lval nets, so quit now. + if (obj->pin(obj_pin).get_dir() == Link::OUTPUT) + return 0; + + } + + return found_ps; +} + +const netclass_t* find_class_containing_scope(const LineInfo&loc, const NetScope*scope) +{ + while (scope && scope->type() != NetScope::CLASS) + scope = scope->parent(); + + if (scope == 0) + return 0; + + const netclass_t*found_in = scope->class_def(); + ivl_assert(loc, found_in); + return found_in; +} +/* + * Find the scope that contains this scope, that is the method for a + * class scope. Look for the scope whose PARENT is the scope for a + * class. This is going to be a method. + */ +NetScope* find_method_containing_scope(const LineInfo&, NetScope*scope) +{ + NetScope*up = scope->parent(); + + while (up && up->type() != NetScope::CLASS) { + scope = up; + up = up->parent(); + } + + if (up == 0) return 0; + + // Should I check if this scope is a TASK or FUNC? + + return scope; +} diff --git a/netmisc.h b/netmisc.h index 86537e36a..0a93ca636 100644 --- a/netmisc.h +++ b/netmisc.h @@ -1,7 +1,7 @@ -#ifndef __netmisc_H -#define __netmisc_H +#ifndef IVL_netmisc_H +#define IVL_netmisc_H /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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,6 +21,8 @@ # include "netlist.h" +class netsarray_t; + /* * Search for a symbol using the "start" scope as the starting * point. If the path includes a scope part, then locate the @@ -186,7 +188,20 @@ extern void indices_to_expressions(Design*des, NetScope*scope, list&indices,list&indices_const); extern NetExpr*normalize_variable_unpacked(const NetNet*net, list&indices); +extern NetExpr*normalize_variable_unpacked(const netsarray_t*net, list&indices); + extern NetExpr*normalize_variable_unpacked(const NetNet*net, list&indices); +extern NetExpr*normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*net, list&indices); + +extern NetExpr*make_canonical_index(Design*des, NetScope*scope, + // loc for error messages + const LineInfo*loc, + // src is the index list + const std::list&src, + // This is the reference type + const netsarray_t*stype, + // True if the expression MUST be constant. + bool need_const); /* * This function takes as input a NetNet signal and adds a constant @@ -206,6 +221,7 @@ extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig); extern NetEConst*make_const_x(unsigned long wid); extern NetEConst*make_const_0(unsigned long wid); extern NetEConst*make_const_val(unsigned long val); +extern NetEConst*make_const_val_s(long val); /* * Make A const net @@ -285,6 +301,9 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, unsigned lv_width, PExpr*expr, bool need_const =false); +extern bool evaluate_ranges(Design*des, NetScope*scope, + std::vector&llist, + const std::list&rlist); /* * This procedure evaluates an expression and if the evaluation is * successful the original expression is replaced with the new one. @@ -308,6 +327,13 @@ extern hname_t eval_path_component(Design*des, NetScope*scope, const name_component_t&comp, bool&error_flag); +/* + * If this scope is contained within a class scope (i.e. a method of a + * class) then return the class definition that contains it. + */ +extern const netclass_t*find_class_containing_scope(const LineInfo&loc,const NetScope*scope); +extern NetScope* find_method_containing_scope(const LineInfo&log, NetScope*scope); + /* * Return true if the data type is a type that is normally available * in vector for. IVL_VT_BOOL and IVL_VT_LOGIC are vectorable, @@ -357,4 +383,10 @@ extern NetExpr*collapse_array_exprs(Design*des, NetScope*scope, const LineInfo*loc, NetNet*net, const list&indices); -#endif +extern void assign_unpacked_with_bufz(Design*des, NetScope*scope, + const LineInfo*loc, + NetNet*lval, NetNet*rval); + +extern NetPartSelect* detect_partselect_lval(Link&pin); + +#endif /* IVL_netmisc_H */ diff --git a/netparray.cc b/netparray.cc index d8779a92d..f71b9785a 100644 --- a/netparray.cc +++ b/netparray.cc @@ -22,6 +22,10 @@ using namespace std; +netsarray_t::~netsarray_t() +{ +} + netparray_t::~netparray_t() { } @@ -34,8 +38,8 @@ 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) { + for (vector::const_iterator cur = static_dimensions().begin() + ; cur != static_dimensions().end() ; ++cur) { cur_width *= cur->width(); } @@ -44,14 +48,25 @@ long netparray_t::packed_width(void) const vector netparray_t::slice_dimensions() const { + const vector&packed_dims = static_dimensions(); + vector elem_dims = element_type()->slice_dimensions(); - vector res (packed_dims_.size() + elem_dims.size()); + 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 < packed_dims.size() ; idx += 1) + res[idx] = packed_dims[idx]; for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1) - res[idx+packed_dims_.size()] = elem_dims[idx]; + res[idx+packed_dims.size()] = elem_dims[idx]; return res; } + +netuarray_t::~netuarray_t() +{ +} + +vector netuarray_t::slice_dimensions() const +{ + return static_dimensions(); +} diff --git a/netparray.h b/netparray.h index 015e97928..6753d8bf0 100644 --- a/netparray.h +++ b/netparray.h @@ -1,7 +1,7 @@ -#ifndef __netarray_H -#define __netarray_H +#ifndef IVL_netarray_H +#define IVL_netarray_H /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -23,10 +23,39 @@ # include "nettypes.h" # include +/* + * Arrays with static dimensions (packed and unpacked) share this + * common base type. + */ +class netsarray_t : public netarray_t { + + public: + explicit netsarray_t(const std::vector&packed, + ivl_type_t etype); + ~netsarray_t(); + + public: + // Virtual methods from the ivl_type_s type... + + public: + inline const std::vector& static_dimensions() const + { return dims_; } + + private: + std::vector dims_; + +}; + +inline netsarray_t::netsarray_t(const std::vector&pd, + ivl_type_t etype) +: netarray_t(etype), dims_(pd) +{ +} + /* * Packed arrays. */ -class netparray_t : public netarray_t { +class netparray_t : public netsarray_t { public: explicit netparray_t(const std::vector&packed, @@ -38,19 +67,33 @@ class netparray_t : public netarray_t { 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&pd, ivl_type_t etype) -: netarray_t(etype), packed_dims_(pd) +: netsarray_t(pd, etype) { } -#endif +/* + * Unpacked arrays are very similar, but lack packed slices. + */ +class netuarray_t : public netsarray_t { + + public: + explicit netuarray_t(const std::vector&packed, + ivl_type_t etype); + ~netuarray_t(); + + public: + // Virtual methods from the ivl_type_s type... + std::vector slice_dimensions() const; +}; + +inline netuarray_t::netuarray_t(const std::vector&pd, + ivl_type_t etype) +: netsarray_t(pd, etype) +{ +} + +#endif /* IVL_netarray_H */ diff --git a/netqueue.cc b/netqueue.cc new file mode 100644 index 000000000..a850e3b46 --- /dev/null +++ b/netqueue.cc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 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 "netqueue.h" +# include + +using namespace std; + +netqueue_t::netqueue_t(ivl_type_t vec) +: netdarray_t(vec) +{ +} + +netqueue_t::~netqueue_t() +{ +} + +ivl_variable_type_t netqueue_t::base_type() const +{ + return IVL_VT_QUEUE; +} + +bool netqueue_t::test_compatibility(ivl_type_t that) const +{ + const netqueue_t*that_q = dynamic_cast(that); + if (that_q == 0) + return false; + + return element_type()->type_compatible(that_q->element_type()); +} diff --git a/netqueue.h b/netqueue.h new file mode 100644 index 000000000..af2de0a1c --- /dev/null +++ b/netqueue.h @@ -0,0 +1,47 @@ +#ifndef IVL__netqueue_H +#define IVL__netqueue_H +/* + * Copyright (c) 2014 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" +# include "ivl_target.h" + +/* + * A queue type is actually a dynamic array with a few extra + * methods. This will probably result in a different implementation at + * run-time, but for the most part this applies during elaboration. + */ +class netqueue_t : public netdarray_t { + + public: + explicit netqueue_t(ivl_type_t vec); + ~netqueue_t(); + + // This is the "base_type()" virtual method of the + // nettype_base_t. The ivl_target api expects this to return + // IVL_VT_QUEUE for queues. + ivl_variable_type_t base_type() const; + + std::ostream& debug_dump(std::ostream&) const; + + private: + bool test_compatibility(ivl_type_t that) const; +}; + +#endif diff --git a/netscalar.h b/netscalar.h index 9559b7841..ad63d404d 100644 --- a/netscalar.h +++ b/netscalar.h @@ -1,7 +1,7 @@ -#ifndef __netscalar_H -#define __netscalar_H +#ifndef IVL_netscalar_H +#define IVL_netscalar_H /* - * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2013-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -46,4 +46,4 @@ class netstring_t : public ivl_type_s { static netstring_t type_string; }; -#endif +#endif /* IVL_netscalar_H */ diff --git a/netstruct.h b/netstruct.h index 8c0f4a88e..d5f9eb0a2 100644 --- a/netstruct.h +++ b/netstruct.h @@ -1,7 +1,7 @@ -#ifndef __netstruct_H -#define __netstruct_H +#ifndef IVL_netstruct_H +#define IVL_netstruct_H /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -80,4 +80,4 @@ class netstruct_t : public LineInfo, public ivl_type_s { inline bool netstruct_t::union_flag(void) const { return union_; } inline bool netstruct_t::packed(void) const { return packed_; } -#endif +#endif /* IVL_netstruct_H */ diff --git a/nettypes.cc b/nettypes.cc index 1a36b177a..4a01d4d8a 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -18,6 +18,7 @@ */ # include "nettypes.h" +# include # include using namespace std; @@ -101,6 +102,12 @@ bool prefix_to_slice(const std::vector&dims, { assert(prefix.size() < dims.size()); + // Figure out the width of the slice, given the number of + // prefix numbers there are. We don't need to look at the + // actual values yet, but we do need to know how many there + // are compared to the actual dimensions of the target. So do + // this by multiplying the widths of the dims that are NOT + // accounted for by the prefix or sb indices. size_t acc_wid = 1; vector::const_iterator pcur = dims.end(); for (size_t idx = prefix.size()+1 ; idx < dims.size() ; idx += 1) { @@ -108,8 +115,12 @@ bool prefix_to_slice(const std::vector&dims, acc_wid *= pcur->width(); } - lwid = acc_wid; + lwid = acc_wid; // lwid is now the final slice width. + // pcur is pointing to the dimension AFTER the dimension that + // we have an index for, so step back one, then this will be + // used with the sb index. Start accumulating in the acc_off + // the offset into the n-dimensional vector. -- pcur; if (sb < pcur->get_msb() && sb < pcur->get_lsb()) return false; @@ -122,16 +133,18 @@ bool prefix_to_slice(const std::vector&dims, else acc_off += (pcur->get_lsb() - sb) * acc_wid; + // If there are no more prefix items, we are done. if (prefix.empty()) { loff = acc_off; return true; } - lwid *= pcur->width(); - + // Now similarly go through the prefix numbers, working + // through the dimensions until we run out. Accumulate a + // growing slice width (acc_wid) that is used to caculate the + // growing offset (acc_off). list::const_iterator icur = prefix.end(); do { - -- pcur; -- icur; acc_wid *= pcur->width(); if (pcur->get_msb() >= pcur->get_lsb()) @@ -139,8 +152,11 @@ bool prefix_to_slice(const std::vector&dims, else acc_off += (pcur->get_lsb() - *icur) * acc_wid; + -- pcur; + } while (icur != prefix.begin()); + // Got our final offset. loff = acc_off; return true; diff --git a/nettypes.h b/nettypes.h index 5729602eb..e9c51fb34 100644 --- a/nettypes.h +++ b/nettypes.h @@ -1,7 +1,7 @@ -#ifndef __nettypes_H -#define __nettypes_H +#ifndef IVL_nettypes_H +#define IVL_nettypes_H /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 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 @@ -70,6 +70,8 @@ class netarray_t : public ivl_type_s { public: // Some virtual methods have a common implementation for arrays. + + // The base_type() for arrays is the base_Typeof the element. ivl_variable_type_t base_type() const; public: @@ -142,4 +144,4 @@ extern bool prefix_to_slice(const std::vector&dims, const std::list&prefix, long sb, long&loff, unsigned long&lwid); -#endif +#endif /* IVL_nettypes_H */ diff --git a/netvector.h b/netvector.h index 8e2148c18..12acfae1f 100644 --- a/netvector.h +++ b/netvector.h @@ -1,7 +1,7 @@ -#ifndef __netvector_H -#define __netvector_H +#ifndef IVL_netvector_H +#define IVL_netvector_H /* - * Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 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 @@ -107,4 +107,4 @@ inline static std::ostream& operator << (std::ostream&out, const netvector_t&obj return obj.debug_dump(out); } -#endif +#endif /* IVL_netvector_H */ diff --git a/nodangle.cc b/nodangle.cc index 19336fc23..3dcb32391 100644 --- a/nodangle.cc +++ b/nodangle.cc @@ -117,7 +117,7 @@ void nodangle_f::event(Design*, NetEvent*ev) NetEvent*tmp = *idx; assert(tmp != ev); - tmp ->replace_event(ev); + tmp ->replace_event(ev); } } } @@ -144,6 +144,12 @@ void nodangle_f::signal(Design*, NetNet*sig) && (sig->scope()->attribute(perm_string::literal("ivl_synthesis_cell")) != verinum())) return; + /* Don't delete signals that are marked with the + ivl_do_not_elide property. */ + if (!sig->local_flag() + && (sig->attribute(perm_string::literal("ivl_do_not_elide")) != verinum())) + return; + /* Check to see if the signal is completely unconnected. If all the bits are unlinked, then delete it. */ if (! sig->is_linked()) { diff --git a/parse.y b/parse.y index d9b8f0166..89b27e0c5 100644 --- a/parse.y +++ b/parse.y @@ -46,12 +46,8 @@ static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; static struct { NetNet::Type port_net_type; NetNet::PortType port_type; - ivl_variable_type_t var_type; - bool sign_flag; data_type_t* data_type; - list* range; -} port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, - IVL_VT_NO_TYPE, false, 0, 0}; +} port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, 0}; /* The task and function rules need to briefly hold the pointer to the task/function that is currently in progress. */ @@ -97,13 +93,26 @@ static list*attributes_in_context = 0; /* Recent version of bison expect that the user supply a YYLLOC_DEFAULT macro that makes up a yylloc value from existing values. I need to supply an explicit version to account for the - text field, that otherwise won't be copied. */ -# define YYLLOC_DEFAULT(Current, Rhs, N) do { \ - (Current).first_line = (Rhs)[1].first_line; \ - (Current).first_column = (Rhs)[1].first_column; \ - (Current).last_line = (Rhs)[N].last_line; \ - (Current).last_column = (Rhs)[N].last_column; \ - (Current).text = (Rhs)[1].text; } while (0) + text field, that otherwise won't be copied. + + The YYLLOC_DEFAULT blends the file range for the tokens of Rhs + rule, which has N tokens. +*/ +# define YYLLOC_DEFAULT(Current, Rhs, N) do { \ + if (N) { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + (Current).text = YYRHSLOC (Rhs, 1).text; \ + } else { \ + (Current).first_line = YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = YYRHSLOC (Rhs, 0).last_column; \ + (Current).last_line = YYRHSLOC (Rhs, 0).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, 0).last_column; \ + (Current).text = YYRHSLOC (Rhs, 0).text; \ + } \ + } while (0) /* * These are some common strength pairs that are used as defaults when @@ -174,7 +183,7 @@ template void append(vector&out, const vector&in) */ static void strip_tail_items(list*lst) { - while (lst->size() > 0) { + while (! lst->empty()) { if (lst->back() != 0) return; lst->pop_back(); @@ -267,7 +276,7 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) if (s == 0) { /* if the statement list is null, then the parser detected the case that there are no statements in the - task. If this is System Verilog, handle it as an + task. If this is SystemVerilog, handle it as an an empty block. */ if (!gn_system_verilog()) { yyerror(loc, "error: Support for empty tasks requires SystemVerilog."); @@ -305,7 +314,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector if (s == 0) { /* if the statement list is null, then the parser detected the case that there are no statements in the - task. If this is System Verilog, handle it as an + task. If this is SystemVerilog, handle it as an an empty block. */ if (!gn_system_verilog()) { yyerror(loc, "error: Support for empty functions requires SystemVerilog."); @@ -417,6 +426,11 @@ static void current_function_set_statement(const YYLTYPE&loc, vector property_qualifier_t property_qualifier; PPackage*package; + struct { + char*text; + data_type_t*type; + } type_identifier; + struct { data_type_t*type; list*exprs; @@ -431,7 +445,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector }; %token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL -%token TYPE_IDENTIFIER +%token TYPE_IDENTIFIER %token PACKAGE_IDENTIFIER %token DISCIPLINE_IDENTIFIER %token PATHPULSE_IDENTIFIER @@ -532,7 +546,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %token K_timer K_transition K_units K_white_noise K_wreal %token K_zi_nd K_zi_np K_zi_zd K_zi_zp -%type from_exclude +%type from_exclude block_item_decls_opt %type number pos_neg_number %type signing unsigned_signed_opt signed_unsigned_opt %type K_automatic_opt K_packed_opt K_reg_opt K_static_opt K_virtual_opt @@ -730,10 +744,11 @@ class_identifier $$ = tmp; } | TYPE_IDENTIFIER - { class_type_t*tmp = dynamic_cast($1); + { class_type_t*tmp = dynamic_cast($1.type); if (tmp == 0) { - yyerror(@1, "Type name is not a predeclared class name."); + yyerror(@1, "Type name \"%s\"is not a predeclared class name.", $1.text); } + delete[]$1.text; $$ = tmp; } ; @@ -743,13 +758,14 @@ class_identifier does indeed match a name. */ class_declaration_endlabel_opt : ':' TYPE_IDENTIFIER - { class_type_t*tmp = dynamic_cast ($2); + { class_type_t*tmp = dynamic_cast ($2.type); if (tmp == 0) { - yyerror(@2, "error: class declaration endlabel is not a class name\n"); + yyerror(@2, "error: class declaration endlabel \"%s\" is not a class name\n", $2.text); $$ = 0; } else { $$ = strdupnew(tmp->name.str()); } + delete[]$2.text; } | ':' IDENTIFIER { $$ = $2; } @@ -767,12 +783,14 @@ class_declaration_endlabel_opt class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ : K_extends TYPE_IDENTIFIER - { $$.type = $2; + { $$.type = $2.type; $$.exprs= 0; + delete[]$2.text; } | K_extends TYPE_IDENTIFIER '(' expression_list_with_nuls ')' - { $$.type = $2; + { $$.type = $2.type; $$.exprs = $4; + delete[]$2.text; } | { $$.type = 0; $$.exprs = 0; } @@ -826,6 +844,30 @@ class_item /* IEEE1800-2005: A.1.8 */ | method_qualifier_opt function_declaration { /* The function_declaration rule puts this into the class */ } + /* External class method definitions... */ + + | K_extern method_qualifier_opt K_function K_new ';' + { yyerror(@1, "sorry: External constructors are not yet supported."); } + | K_extern method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + { yyerror(@1, "sorry: External constructors are not yet supported."); } + | K_extern method_qualifier_opt K_function data_type_or_implicit_or_void + IDENTIFIER ';' + { yyerror(@1, "sorry: External methods are not yet supported."); + delete[] $5; + } + | K_extern method_qualifier_opt K_function data_type_or_implicit_or_void + IDENTIFIER '(' tf_port_list_opt ')' ';' + { yyerror(@1, "sorry: External methods are not yet supported."); + delete[] $5; + } + | K_extern method_qualifier_opt K_task IDENTIFIER ';' + { yyerror(@1, "sorry: External methods are not yet supported."); + delete[] $4; + } + | K_extern method_qualifier_opt K_task IDENTIFIER '(' tf_port_list_opt ')' ';' + { yyerror(@1, "sorry: External methods are not yet supported."); + delete[] $4; + } /* Class constraints... */ @@ -1013,14 +1055,16 @@ data_type /* IEEE1800-2005: A.2.2.1 */ $$ = tmp; } | TYPE_IDENTIFIER dimensions_opt - { if ($2) $$ = new parray_type_t($1, $2); - else $$ = $1; + { if ($2) $$ = new parray_type_t($1.type, $2); + else $$ = $1.type; + delete[]$1.text; } | PACKAGE_IDENTIFIER K_SCOPE_RES { lex_in_package_scope($1); } TYPE_IDENTIFIER { lex_in_package_scope(0); - $$ = $4; + $$ = $4.type; + delete[]$4.text; } | K_string { string_type_t*tmp = new string_type_t; @@ -1153,7 +1197,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ } if (! gn_system_verilog()) { yyerror(@11, "error: Function end label require " - "System Verilog."); + "SystemVerilog."); } delete[]$11; } @@ -1187,7 +1231,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ } if (! gn_system_verilog()) { yyerror(@14, "error: Function end labels require " - "System Verilog."); + "SystemVerilog."); } delete[]$14; } @@ -1214,7 +1258,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ } if (! gn_system_verilog()) { yyerror(@8, "error: Function end labels require " - "System Verilog."); + "SystemVerilog."); } delete[]$8; } @@ -1307,10 +1351,42 @@ loop_statement /* IEEE1800-2005: A.6.8 */ $$ = tmp; } + // Handle for_variable_declaration syntax by wrapping the for(...) + // statement in a synthetic named block. We can name the block + // after the variable that we are creating, that identifier is + // safe in the controlling scope. | K_for '(' data_type IDENTIFIER '=' expression ';' expression ';' for_step ')' + { static unsigned for_counter = 0; + char for_block_name [64]; + snprintf(for_block_name, sizeof for_block_name, "$ivl_for_loop%u", for_counter); + for_counter += 1; + PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + current_block_stack.push(tmp); + + listassign_list; + decl_assignment_t*tmp_assign = new decl_assignment_t; + tmp_assign->name = lex_strings.make($4); + assign_list.push_back(tmp_assign); + pform_makewire(@4, 0, str_strength, &assign_list, NetNet::REG, $3); + } statement_or_null - { $$ = 0; - yyerror(@3, "sorry: for_variable_declaration not supported"); + { pform_name_t tmp_hident; + tmp_hident.push_back(name_component_t(lex_strings.make($4))); + + PEIdent*tmp_ident = pform_new_ident(tmp_hident); + FILE_NAME(tmp_ident, @4); + + PForStatement*tmp_for = new PForStatement(tmp_ident, $6, $8, $10, $13); + FILE_NAME(tmp_for, @1); + + pform_pop_scope(); + vectortmp_for_list (1); + tmp_for_list[0] = tmp_for; + PBlock*tmp_blk = current_block_stack.top(); + tmp_blk->set_statement(tmp_for_list); + $$ = tmp_blk; + delete[]$4; } | K_forever statement_or_null @@ -1337,12 +1413,29 @@ loop_statement /* IEEE1800-2005: A.6.8 */ $$ = tmp; } - | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' statement_or_null - { yyerror(@1, "sorry: foreach loops not supported"); - delete[]$3; - delete $5; - delete $8; - $$ = 0; + // When matching a foreach loop, implicitly create a named block + // to hold the definitions for the index variables. + | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' + { static unsigned foreach_counter = 0; + char for_block_name[64]; + snprintf(for_block_name, sizeof for_block_name, "$ivl_foreach%u", foreach_counter); + foreach_counter += 1; + + PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + current_block_stack.push(tmp); + + pform_make_foreach_declarations(@1, $5); + } + statement_or_null + { PForeach*tmp_for = pform_make_foreach(@1, $3, $5, $9); + + pform_pop_scope(); + vectortmp_for_list(1); + tmp_for_list[0] = tmp_for; + PBlock*tmp_blk = current_block_stack.top(); + tmp_blk->set_statement(tmp_for_list); + $$ = tmp_blk; } /* Error forms for loop statements. */ @@ -1495,6 +1588,16 @@ package_declaration /* IEEE1800-2005 A.1.2 */ } ; +module_package_import_list_opt + : + | package_import_list + ; + +package_import_list + : package_import_declaration + | package_import_list package_import_declaration + ; + package_import_declaration /* IEEE1800-2005 A.2.1.3 */ : K_import package_import_item_list ';' { } @@ -1523,6 +1626,7 @@ package_item /* IEEE1800-2005 A.1.10 */ | function_declaration | task_declaration | data_declaration + | class_declaration ; package_item_list @@ -1688,7 +1792,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ } if (! gn_system_verilog()) { yyerror(@10, "error: Task end labels require " - "System Verilog."); + "SystemVerilog."); } delete[]$10; } @@ -1722,7 +1826,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ } if (! gn_system_verilog()) { yyerror(@13, "error: Task end labels require " - "System Verilog."); + "SystemVerilog."); } delete[]$13; } @@ -1762,7 +1866,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ } if (! gn_system_verilog()) { yyerror(@12, "error: Task end labels require " - "System Verilog."); + "SystemVerilog."); } delete[]$12; } @@ -1785,7 +1889,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ } if (! gn_system_verilog()) { yyerror(@7, "error: Task end labels require " - "System Verilog."); + "SystemVerilog."); } delete[]$7; } @@ -1857,27 +1961,16 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ if ($4 != 0) { yyerror(@4, "internal error: How can there be an unpacked range here?\n"); } - if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { - tmp = pform_make_task_ports(@3, use_port_type, - port_declaration_context.data_type, - ilist); - } else { - tmp = pform_make_task_ports(@3, use_port_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - copy_range(port_declaration_context.range), - ilist); - } + tmp = pform_make_task_ports(@3, use_port_type, + port_declaration_context.data_type, + ilist); + } else { // Otherwise, the decorations for this identifier // indicate the type. Save the type for any right // context thta may come later. port_declaration_context.port_type = use_port_type; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; if ($2 == 0) { $2 = new vector_type_t(IVL_VT_LOGIC, false, 0); FILE_NAME($2, @3); @@ -2003,11 +2096,9 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ | '[' '$' ']' { // SystemVerilog queue list *tmp = new list; - pform_range_t index (0,0); - if (gn_system_verilog()) { - yyerror("sorry: Dynamic array ranges not supported."); - } else { - yyerror("error: Queue declarations require System Verilog."); + pform_range_t index (new PENull,0); + if (!gn_system_verilog()) { + yyerror("error: Queue declarations require SystemVerilog."); } tmp->push_back(index); $$ = tmp; @@ -2018,9 +2109,11 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ variety of different objects. The syntax inside the (* *) is a comma separated list of names or names with assigned values. */ attribute_list_opt - : attribute_instance_list - | { $$ = 0; } - ; + : attribute_instance_list + { $$ = $1; } + | + { $$ = 0; } + ; attribute_instance_list : K_PSTAR K_STARP { $$ = 0; } @@ -2130,8 +2223,8 @@ block_item_decls ; block_item_decls_opt - : block_item_decls - | + : block_item_decls { $$ = true; } + | { $$ = false; } ; /* Type declarations are parsed here. The rule actions call pform @@ -2143,6 +2236,20 @@ type_declaration delete[]$3; } + /* If the IDENTIFIER already is a typedef, it is possible for this + code to override the definition, but only if the typedef is + inherited from a different scope. */ + | K_typedef data_type TYPE_IDENTIFIER ';' + { perm_string name = lex_strings.make($3.text); + if (pform_test_type_identifier_local(name)) { + yyerror(@3, "error: Typedef identifier \"%s\" is already a type name.", $3.text); + + } else { + pform_set_typedef(name, $2); + } + delete[]$3.text; + } + /* These are forward declarations... */ | K_typedef K_class IDENTIFIER ';' @@ -2170,9 +2277,6 @@ type_declaration delete[]$2; } - | K_typedef data_type TYPE_IDENTIFIER ';' - { yyerror(@3, "error: Typedef identifier is already a type name."); } - | K_typedef error ';' { yyerror(@2, "error: Syntax error in typedef clause."); yyerrok; @@ -3108,9 +3212,10 @@ expr_primary /* There are a few special cases (notably $bits argument) where the expression may be a type name. Let the elaborator sort this out. */ | TYPE_IDENTIFIER - { PETypename*tmp = new PETypename($1); + { PETypename*tmp = new PETypename($1.type); FILE_NAME(tmp,@1); $$ = tmp; + delete[]$1.text; } /* The hierarchy_identifier rule matches simple identifiers as well as @@ -3130,7 +3235,7 @@ expr_primary /* An identifier followed by an expression list in parentheses is a function call. If a system identifier, then a system function - call. */ + call. It can also be a call to a class method (functino). */ | hierarchy_identifier '(' expression_list_with_nuls ')' { list*expr_list = $3; @@ -3139,6 +3244,19 @@ expr_primary delete $1; $$ = tmp; } + | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' + { pform_name_t*t_name = $1; + while (! $3->empty()) { + t_name->push_back($3->front()); + $3->pop_front(); + } + list*expr_list = $5; + strip_tail_items(expr_list); + PECallFunction*tmp = pform_make_call_function(@1, *t_name, *expr_list); + delete $1; + delete $3; + $$ = tmp; + } | SYSTEM_IDENTIFIER '(' expression_list_proper ')' { perm_string tn = lex_strings.make($1); PECallFunction*tmp = new PECallFunction(tn, *$3); @@ -3173,12 +3291,12 @@ expr_primary } | implicit_class_handle '.' hierarchy_identifier - { pform_name_t*nam = $1; + { pform_name_t*t_name = $1; while (! $3->empty()) { - nam->push_back($3->front()); + t_name->push_back($3->front()); $3->pop_front(); } - PEIdent*tmp = new PEIdent(*nam); + PEIdent*tmp = new PEIdent(*t_name); FILE_NAME(tmp,@1); delete $1; delete $3; @@ -3391,11 +3509,14 @@ expr_primary | '{' '}' { // This is the empty queue syntax. if (gn_system_verilog()) { - yyerror(@1, "sorry: Expty queue expressions not supported."); + list empty_list; + PEConcat*tmp = new PEConcat(empty_list); + FILE_NAME(tmp, @1); + $$ = tmp; } else { yyerror(@1, "error: Concatenations are not allowed to be empty."); + $$ = 0; } - $$ = 0; } /* Cast expressions are primaries */ @@ -3652,6 +3773,20 @@ hierarchy_identifier tail.index.push_back(itmp); $$ = tmp; } + | hierarchy_identifier '[' '$' ']' + { pform_name_t * tmp = $1; + name_component_t&tail = tmp->back(); + if (! gn_system_verilog()) { + yyerror(@3, "error: Last element expression ($) " + "requires SystemVerilog. Try enabling SystemVerilog."); + } + index_component_t itmp; + itmp.sel = index_component_t::SEL_BIT_LAST; + itmp.msb = 0; + itmp.lsb = 0; + tail.index.push_back(itmp); + $$ = tmp; + } | hierarchy_identifier '[' expression ':' expression ']' { pform_name_t * tmp = $1; name_component_t&tail = tmp->back(); @@ -3762,10 +3897,7 @@ list_of_port_declarations pform_module_define_port(@3, name, port_declaration_context.port_type, 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); + port_declaration_context.data_type, 0); delete[]$3; $$ = tmp; } @@ -3785,21 +3917,14 @@ port_declaration : attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt { Module::port_t*ptmp; perm_string name = lex_strings.make($5); + data_type_t*use_type = $4; + if ($6) use_type = new uarray_type_t(use_type, $6); 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); + pform_module_define_port(@2, name, NetNet::PINPUT, $3, use_type, $1); port_declaration_context.port_type = NetNet::PINPUT; 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 = 0; port_declaration_context.data_type = $4; delete[]$5; - if ($6) { - yyerror(@6, "sorry: Input ports with unpacked dimensions not supported."); - delete $6; - } $$ = ptmp; } | attribute_list_opt @@ -3808,15 +3933,13 @@ port_declaration perm_string name = lex_strings.make($4); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + real_type_t*real_type = new real_type_t(real_type_t::REAL); + FILE_NAME(real_type, @3); pform_module_define_port(@2, name, NetNet::PINPUT, - NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1); + NetNet::WIRE, real_type, $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; + port_declaration_context.data_type = real_type; delete[]$4; $$ = ptmp; } @@ -3824,14 +3947,9 @@ port_declaration { Module::port_t*ptmp; 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); + pform_module_define_port(@2, name, NetNet::PINOUT, $3, $4, $1); port_declaration_context.port_type = NetNet::PINOUT; 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 = 0; port_declaration_context.data_type = $4; delete[]$5; if ($6) { @@ -3846,21 +3964,21 @@ port_declaration perm_string name = lex_strings.make($4); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + real_type_t*real_type = new real_type_t(real_type_t::REAL); + FILE_NAME(real_type, @3); pform_module_define_port(@2, name, NetNet::PINOUT, - NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1); + NetNet::WIRE, real_type, $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; + port_declaration_context.data_type = real_type; delete[]$4; $$ = ptmp; } | attribute_list_opt K_output net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt { Module::port_t*ptmp; perm_string name = lex_strings.make($5); + data_type_t*use_dtype = $4; + if ($6) use_dtype = new uarray_type_t(use_dtype, $6); NetNet::Type use_type = $3; if (use_type == NetNet::IMPLICIT) { if (vector_type_t*dtype = dynamic_cast ($4)) { @@ -3882,20 +4000,11 @@ port_declaration } } 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); + pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, use_dtype, $1); port_declaration_context.port_type = NetNet::POUTPUT; 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; delete[]$5; - if ($6) { - yyerror(@6, "sorry: Output ports with unpacked dimensions not supported."); - delete $6; - } $$ = ptmp; } | attribute_list_opt @@ -3904,15 +4013,13 @@ port_declaration perm_string name = lex_strings.make($4); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + real_type_t*real_type = new real_type_t(real_type_t::REAL); + FILE_NAME(real_type, @3); pform_module_define_port(@2, name, NetNet::POUTPUT, - NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1); + NetNet::WIRE, real_type, $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; + port_declaration_context.data_type = real_type; delete[]$4; $$ = ptmp; } @@ -3931,14 +4038,9 @@ port_declaration } } 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); + pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, $4, $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); @@ -4001,15 +4103,15 @@ lpvalue } | implicit_class_handle '.' hierarchy_identifier - { pform_name_t*tmp1 = $1; + { pform_name_t*t_name = $1; while (!$3->empty()) { - tmp1->push_back($3->front()); + t_name->push_back($3->front()); $3->pop_front(); } - PEIdent*tmp = new PEIdent(*tmp1); + PEIdent*tmp = new PEIdent(*t_name); FILE_NAME(tmp, @1); $$ = tmp; - delete tmp1; + delete $1; delete $3; } @@ -4097,10 +4199,11 @@ local_timeunit_prec_decl2 module : attribute_list_opt module_start IDENTIFIER { pform_startmodule(@2, $3, $2==K_program, $1); } + module_package_import_list_opt module_parameter_port_list_opt module_port_list_opt module_attribute_foreign ';' - { pform_module_set_ports($6); } + { pform_module_set_ports($7); } local_timeunit_prec_decl_opt { have_timeunit_decl = true; // Every thing past here is have_timeprec_decl = true; // a check! @@ -4126,13 +4229,13 @@ module } // Check that program/endprogram and module/endmodule // keywords match. - if ($2 != $13) { + if ($2 != $14) { switch ($2) { case K_module: - yyerror(@13, "error: module not closed by endmodule."); + yyerror(@14, "error: module not closed by endmodule."); break; case K_program: - yyerror(@13, "error: program not closed by endprogram."); + yyerror(@14, "error: program not closed by endprogram."); break; default: break; @@ -4148,15 +4251,15 @@ module // endlabel_opt but still have the pform_endmodule() called // early enough that the lexor can know we are outside the // module. - if ($15) { - if (strcmp($3,$15) != 0) { + if ($16) { + if (strcmp($3,$16) != 0) { switch ($2) { case K_module: - yyerror(@15, "error: End label doesn't match " + yyerror(@16, "error: End label doesn't match " "module name."); break; case K_program: - yyerror(@15, "error: End label doesn't match " + yyerror(@16, "error: End label doesn't match " "program name."); break; default: @@ -4164,10 +4267,10 @@ module } } if (($2 == K_module) && (! gn_system_verilog())) { - yyerror(@7, "error: Module end labels require " - "System Verilog."); + yyerror(@8, "error: Module end labels require " + "SystemVerilog."); } - delete[]$15; + delete[]$16; } delete[]$3; } @@ -4593,7 +4696,7 @@ module_item if ($4) { if (!gn_system_verilog()) { yyerror(@4, "error: Function end names require " - "System Verilog."); + "SystemVerilog."); } delete[]$4; } @@ -4665,7 +4768,7 @@ generate_block } if (! gn_system_verilog()) { yyerror(@6, "error: Begin end labels require " - "System Verilog."); + "SystemVerilog."); } delete[]$6; } @@ -5602,11 +5705,40 @@ statement_item /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } - | K_begin statement_or_null_list K_end - { PBlock*tmp = new PBlock(PBlock::BL_SEQ); + /* In SystemVerilog an unnamed block can contain variable declarations. */ + | K_begin + { PBlock*tmp = pform_push_block_scope(0, PBlock::BL_SEQ); FILE_NAME(tmp, @1); - tmp->set_statement(*$2); - delete $2; + current_block_stack.push(tmp); + } + block_item_decls_opt + { if ($3) { + if (! gn_system_verilog()) { + yyerror("error: Variable declaration in unnamed block " + "requires SystemVerilog."); + } + } else { + /* If there are no declarations in the scope then just delete it. */ + pform_pop_scope(); + assert(! current_block_stack.empty()); + PBlock*tmp = current_block_stack.top(); + current_block_stack.pop(); + delete tmp; + } + } + statement_or_null_list K_end + { PBlock*tmp; + if ($3) { + pform_pop_scope(); + assert(! current_block_stack.empty()); + tmp = current_block_stack.top(); + current_block_stack.pop(); + } else { + tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + } + if ($5) tmp->set_statement(*$5); + delete $5; $$ = tmp; } | K_begin ':' IDENTIFIER @@ -5628,7 +5760,7 @@ statement_item /* This is roughly statement_item in the LRM */ } if (! gn_system_verilog()) { yyerror(@8, "error: Begin end labels require " - "System Verilog."); + "SystemVerilog."); } delete[]$8; } @@ -5646,11 +5778,41 @@ statement_item /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } - | K_fork statement_or_null_list join_keyword - { PBlock*tmp = new PBlock($3); + /* In SystemVerilog an unnamed block can contain variable declarations. */ + | K_fork + { PBlock*tmp = pform_push_block_scope(0, PBlock::BL_PAR); FILE_NAME(tmp, @1); - tmp->set_statement(*$2); - delete $2; + current_block_stack.push(tmp); + } + block_item_decls_opt + { if ($3) { + if (! gn_system_verilog()) { + yyerror("error: Variable declaration in unnamed block " + "requires SystemVerilog."); + } + } else { + /* If there are no declarations in the scope then just delete it. */ + pform_pop_scope(); + assert(! current_block_stack.empty()); + PBlock*tmp = current_block_stack.top(); + current_block_stack.pop(); + delete tmp; + } + } + statement_or_null_list join_keyword + { PBlock*tmp; + if ($3) { + pform_pop_scope(); + assert(! current_block_stack.empty()); + tmp = current_block_stack.top(); + current_block_stack.pop(); + tmp->set_join_type($6); + } else { + tmp = new PBlock($6); + FILE_NAME(tmp, @1); + } + if ($5) tmp->set_statement(*$5); + delete $5; $$ = tmp; } | K_fork ':' IDENTIFIER @@ -5673,7 +5835,7 @@ statement_item /* This is roughly statement_item in the LRM */ } if (! gn_system_verilog()) { yyerror(@8, "error: Fork end labels require " - "System Verilog."); + "SystemVerilog."); } delete[]$8; } @@ -5920,12 +6082,12 @@ statement_item /* This is roughly statement_item in the LRM */ } | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';' - { pform_name_t*nam = $1; + { pform_name_t*t_name = $1; while (! $3->empty()) { - nam->push_back($3->front()); + t_name->push_back($3->front()); $3->pop_front(); } - PCallTask*tmp = new PCallTask(*nam, *$5); + PCallTask*tmp = new PCallTask(*t_name, *$5); FILE_NAME(tmp, @1); delete $1; delete $3; @@ -5950,6 +6112,7 @@ statement_item /* This is roughly statement_item in the LRM */ | implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' ';' { PChainConstructor*tmp = new PChainConstructor(*$5); FILE_NAME(tmp, @3); + delete $1; $$ = tmp; } | hierarchy_identifier '(' error ')' ';' @@ -6342,7 +6505,7 @@ udp_primitive } if (! gn_system_verilog()) { yyerror(@11, "error: Primitive end labels " - "require System Verilog."); + "require SystemVerilog."); } delete[]$11; } @@ -6369,7 +6532,7 @@ udp_primitive } if (! gn_system_verilog()) { yyerror(@14, "error: Primitive end labels " - "require System Verilog."); + "require SystemVerilog."); } delete[]$14; } diff --git a/parse_api.h b/parse_api.h index a9de02dcf..a698c3bee 100644 --- a/parse_api.h +++ b/parse_api.h @@ -1,7 +1,7 @@ -#ifndef __parse_api_H -#define __parse_api_H +#ifndef IVL_parse_api_H +#define IVL_parse_api_H /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -28,7 +28,9 @@ class Design; class Module; +class PClass; class PPackage; +class PTaskFunc; class PUdp; class data_type_t; struct enum_type_t; @@ -42,11 +44,17 @@ extern std::map pform_modules; extern std::map pform_primitives; extern std::map pform_typedefs; extern std::set pform_enum_sets; - +extern std::map pform_tasks; +extern std::map pform_classes; extern std::map pform_packages; + +extern void pform_dump(std::ostream&out, const PClass*pac); extern void pform_dump(std::ostream&out, const PPackage*pac); +extern void pform_dump(std::ostream&out, const PTaskFunc*tf); extern void elaborate_rootscope_enumerations(Design*des); +extern void elaborate_rootscope_classes(Design*des); +extern void elaborate_rootscope_tasks(Design*des); /* * This code actually invokes the parser to make modules. The first @@ -64,4 +72,4 @@ extern void pform_set_timescale(int units, int prec, const char*file, extern int def_ts_units; extern int def_ts_prec; -#endif +#endif /* IVL_parse_api_H */ diff --git a/parse_misc.cc b/parse_misc.cc index 74c4df9ed..2de0dfee1 100644 --- a/parse_misc.cc +++ b/parse_misc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -51,8 +51,9 @@ void VLerror(const YYLTYPE&loc, const char*msg, ...) va_list ap; va_start(ap, msg); - fprintf(stderr, "%s:%u: ", loc.text, loc.first_line); + fprintf(stderr, "%s:%d: ", loc.text, loc.first_line); vfprintf(stderr, msg, ap); + va_end(ap); fprintf(stderr, "\n"); error_count += 1; diff --git a/parse_misc.h b/parse_misc.h index 7887818c0..ddee21bf7 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -1,7 +1,7 @@ -#ifndef __parse_misc_H -#define __parse_misc_H +#ifndef IVL_parse_misc_H +#define IVL_parse_misc_H /* - * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -30,10 +30,10 @@ * YYLTYPE compels the lexor to use this type and not something other. */ struct vlltype { - unsigned first_line; - unsigned first_column; - unsigned last_line; - unsigned last_column; + int first_line; + int first_column; + int last_line; + int last_column; const char*text; std::string get_fileline() const; }; @@ -96,6 +96,8 @@ extern void lex_in_package_scope(PPackage*pkg); extern data_type_t* pform_test_type_identifier(const char*txt); extern data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt); +extern bool pform_test_type_identifier_local(perm_string txt); + /* * Test if this identifier is a package name. The pform needs to help * the lexor here because the parser detects packages and saves them. @@ -114,4 +116,4 @@ extern verinum*make_unsized_hex(const char*txt); extern char* strdupnew(char const *str); -#endif +#endif /* IVL_parse_misc_H */ diff --git a/pform.cc b/pform.cc index f2d360521..30a1f4ed6 100644 --- a/pform.cc +++ b/pform.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -43,6 +43,15 @@ # include "ivl_assert.h" # include "ivl_alloc.h" +/* + * The "// synthesis translate_on/off" meta-comments cause this flag + * to be turned off or on. The pform_make_behavior and similar + * functions look at this flag and may choose to add implicit ivl + * synthesis flags. + */ +static bool pform_mc_translate_flag = true; +void pform_mc_translate_on(bool flag) { pform_mc_translate_flag = flag; } + /* * The pform_modules is a map of the modules that have been defined in * the top level. This should not contain nested modules/programs. @@ -57,6 +66,16 @@ map pform_primitives; mappform_typedefs; setpform_enum_sets; +/* + * Class definitions in the $root scope go here. + */ +map pform_classes; + +/* + * Task and function definitions in the $root scope go here. + */ +map pform_tasks; + std::string vlltype::get_fileline() const { ostringstream buf; @@ -233,6 +252,11 @@ static listpform_cur_module; bool pform_library_flag = false; +/* + * Give each unnamed block that has a variable declaration a unique name. + */ +static unsigned scope_unnamed_block_with_decl = 1; + /* increment this for generate schemes within a module, and set it to zero when a new module starts. */ static unsigned scope_generate_counter = 1; @@ -314,9 +338,17 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name) assert(!pform_cur_generate); + /* If no scope was found then this is being defined in the + * compilation unit scope. */ + if (scopex == 0) { + pform_classes[name] = class_scope; + lexical_scope = class_scope; + return class_scope; + } + if (scopex->classes.find(name) != scopex->classes.end()) { cerr << class_scope->get_fileline() << ": error: duplicate " - " definition for class '" << name << "' in '" + "definition for class '" << name << "' in '" << scopex->pscope_name() << "'." << endl; error_count += 1; } @@ -344,7 +376,11 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) FILE_NAME(task, loc); PScopeExtra*scopex = find_nearest_scopex(lexical_scope); - assert(scopex); + if ((scopex == 0) && !gn_system_verilog()) { + cerr << task->get_fileline() << ": error: task declarations " + "must be contained within a module." << endl; + error_count += 1; + } if (pform_cur_generate) { // Check if the task is already in the dictionary. @@ -357,7 +393,7 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) error_count += 1; } pform_cur_generate->tasks[task->pscope_name()] = task; - } else { + } else if (scopex) { // Check if the task is already in the dictionary. if (scopex->tasks.find(task->pscope_name()) != scopex->tasks.end()) { cerr << task->get_fileline() << ": error: duplicate " @@ -366,6 +402,15 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) error_count += 1; } scopex->tasks[task->pscope_name()] = task; + + } else { + if (pform_tasks.find(task_name) != pform_tasks.end()) { + cerr << task->get_fileline() << ": error: " + << "Duplicate definition for task '" << name + << "' in $root scope." << endl; + error_count += 1; + } + pform_tasks[task_name] = task; } lexical_scope = task; @@ -381,13 +426,12 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, PFunction*func = new PFunction(func_name, lexical_scope, is_auto); FILE_NAME(func, loc); - LexicalScope*scope = lexical_scope; - PScopeExtra*scopex = dynamic_cast (scope); - while (scope && !scopex) { - scope = scope->parent_scope(); - scopex = dynamic_cast (scope); + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); + if ((scopex == 0) && (generation_flag < GN_VER2005_SV)) { + cerr << func->get_fileline() << ": error: function declarations " + "must be contained within a module." << endl; + error_count += 1; } - assert(scopex); if (pform_cur_generate) { // Check if the function is already in the dictionary. @@ -400,7 +444,8 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, error_count += 1; } pform_cur_generate->funcs[func->pscope_name()] = func; - } else { + + } else if (scopex != 0) { // Check if the function is already in the dictionary. if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) { cerr << func->get_fileline() << ": error: duplicate " @@ -409,7 +454,17 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, error_count += 1; } scopex->funcs[func->pscope_name()] = func; + + } else { + if (pform_tasks.find(func_name) != pform_tasks.end()) { + cerr << func->get_fileline() << ": error: " + << "Duplicate definition for function '" << name + << "' in $root scope." << endl; + error_count += 1; + } + pform_tasks[func_name] = func; } + lexical_scope = func; return func; @@ -417,7 +472,16 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) { - perm_string block_name = lex_strings.make(name); + perm_string block_name; + if (name) block_name = lex_strings.make(name); + else { + // Create a unique name for this unnamed block. + char tmp[32]; + snprintf(tmp, sizeof tmp, "$unm_blk_%u", + scope_unnamed_block_with_decl); + block_name = lex_strings.make(tmp); + scope_unnamed_block_with_decl += 1; + } PBlock*block = new PBlock(block_name, lexical_scope, bt); lexical_scope = block; @@ -584,6 +648,31 @@ data_type_t* pform_test_type_identifier(const char*txt) return 0; } +/* + * The parser uses this function to test if the name is a typedef in + * the current scope. We use this to know if we can override the + * definition because it shadows a containing scope. + */ +bool pform_test_type_identifier_local(perm_string name) +{ + if (lexical_scope == 0) { + if (test_type_identifier_in_root(name)) + return true; + else + return false; + } + + LexicalScope*cur_scope = lexical_scope; + + map::iterator cur; + + cur = cur_scope->typedefs.find(name); + if (cur != cur_scope->typedefs.end()) + return true; + + return false; +} + PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, const list&parms) @@ -643,6 +732,45 @@ PCallTask* pform_make_call_task(const struct vlltype&loc, return tmp; } +void pform_make_foreach_declarations(const struct vlltype&loc, + std::list*loop_vars) +{ + static const struct str_pair_t str = { IVL_DR_STRONG, IVL_DR_STRONG }; + + listassign_list; + for (list::const_iterator cur = loop_vars->begin() + ; cur != loop_vars->end() ; ++ cur) { + decl_assignment_t*tmp_assign = new decl_assignment_t; + tmp_assign->name = lex_strings.make(*cur); + assign_list.push_back(tmp_assign); + } + + pform_makewire(loc, 0, str, &assign_list, NetNet::REG, &size_type); +} + +PForeach* pform_make_foreach(const struct vlltype&loc, + char*name, + list*loop_vars, + Statement*stmt) +{ + perm_string use_name = lex_strings.make(name); + delete[]name; + + if (loop_vars==0 || loop_vars->empty()) { + cerr << loc.get_fileline() << ": error: " + << "No loop variables at all in foreach index." << endl; + error_count += 1; + } + + ivl_assert(loc, loop_vars); + PForeach*fe = new PForeach(use_name, *loop_vars, stmt); + FILE_NAME(fe, loc); + + delete loop_vars; + + return fe; +} + static void pform_put_behavior_in_scope(PProcess*pp) { lexical_scope->behaviors.push_back(pp); @@ -1496,7 +1624,7 @@ void pform_make_udp(perm_string name, list*parms, unsigned idx; for (cur = parms->begin(), idx = 0 ; cur != parms->end() - ; idx++, cur++) { + ; ++ idx, ++ cur) { pins[idx] = defs[*cur]; pin_names[idx] = *cur; } @@ -1662,7 +1790,7 @@ void pform_make_udp(perm_string name, bool synchronous_flag, unsigned idx; for (cur = parms->begin(), idx = 1 ; cur != parms->end() - ; idx += 1, cur++) { + ; idx += 1, ++ cur) { assert(idx < pins.count()); pins[idx] = new PWire(*cur, NetNet::WIRE, NetNet::PINPUT, IVL_VT_LOGIC); @@ -1784,7 +1912,6 @@ static void pform_set_net_range(list*names, } delete names; - delete range; } /* @@ -2129,15 +2256,14 @@ void pform_make_reginit(const struct vlltype&li, */ void pform_module_define_port(const struct vlltype&li, perm_string name, - NetNet::PortType port_type, + NetNet::PortType port_kind, 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; + ivl_variable_type_t data_type = IVL_VT_NO_TYPE; + bool signed_flag = false; PWire*cur = pform_get_wire_in_scope(name); if (cur) { @@ -2149,27 +2275,34 @@ 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); + // Packed ranges + list*prange = 0; + // Unpacked dimensions + list*urange = 0; + + // If this is an unpacked array, then split out the parts that + // we can send to the PWire object that we create. + if (uarray_type_t*uarr_type = dynamic_cast (vtype)) { + urange = uarr_type->dims.get(); + vtype = uarr_type->base_type; } 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(); + prange = 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); + prange = 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; + prange = 0; if (rtype->type_code != real_type_t::REAL) { VLerror(li, "sorry: Only real (not shortreal) supported here (%s:%d).", @@ -2179,7 +2312,7 @@ void pform_module_define_port(const struct vlltype&li, } else if ((struct_type = dynamic_cast(vtype))) { data_type = struct_type->figure_packed_base_type(); signed_flag = false; - range = 0; + prange = 0; } else if (vtype) { VLerror(li, "sorry: Given type %s not supported here (%s:%d).", @@ -2191,7 +2324,7 @@ void pform_module_define_port(const struct vlltype&li, if (data_type == IVL_VT_NO_TYPE) data_type = IVL_VT_LOGIC; - cur = new PWire(name, type, port_type, data_type); + cur = new PWire(name, type, port_kind, data_type); FILE_NAME(cur, li); cur->set_signed(signed_flag); @@ -2199,11 +2332,15 @@ void pform_module_define_port(const struct vlltype&li, if (struct_type) { cur->set_data_type(struct_type); - } else if (range == 0) { + } else if (prange == 0) { cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } else { - cur->set_range(*range, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); + cur->set_range(*prange, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); + } + + if (urange) { + cur->set_unpacked_idx(*urange); } pform_bind_attributes(cur->attributes, attr); @@ -2864,13 +3001,13 @@ extern PSpecPath* pform_make_specify_path(const struct vlltype&li, list::const_iterator cur; idx = 0; - for (idx = 0, cur = src->begin() ; cur != src->end() ; idx++, cur++) { + for (idx = 0, cur = src->begin() ; cur != src->end() ; ++ idx, ++ cur) { path->src[idx] = *cur; } assert(idx == path->src.size()); delete src; - for (idx = 0, cur = dst->begin() ; cur != dst->end() ; idx++, cur++) { + for (idx = 0, cur = dst->begin() ; cur != dst->end() ; ++ idx, ++ cur) { path->dst[idx] = *cur; } assert(idx == path->dst.size()); @@ -3149,6 +3286,18 @@ PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, { PProcess*pp = new PProcess(type, st); + // If we are in a part of the code where the meta-comment + // synthesis translate_off is in effect, then implicitly add + // the ivl_synthesis_off attribute to any behavioral code that + // we run into. + if (pform_mc_translate_flag == false) { + if (attr == 0) attr = new list; + named_pexpr_t tmp; + tmp.name = perm_string::literal("ivl_synthesis_off"); + tmp.parm = 0; + attr->push_back(tmp); + } + pform_bind_attributes(pp->attributes, attr); pform_put_behavior_in_scope(pp); diff --git a/pform.h b/pform.h index 420f437bd..b1b3039c7 100644 --- a/pform.h +++ b/pform.h @@ -1,7 +1,7 @@ -#ifndef __pform_H -#define __pform_H +#ifndef IVL_pform_H +#define IVL_pform_H /* - * Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -168,10 +168,7 @@ extern void pform_module_define_port(const struct vlltype&li, perm_string name, NetNet::PortType, NetNet::Type type, - ivl_variable_type_t data_type, - bool signed_flag, data_type_t*vtype, - list*range, list*attr); extern Module::port_t* pform_module_port_reference(perm_string name, @@ -288,6 +285,12 @@ extern PCallTask* pform_make_call_task(const struct vlltype&loc, const pform_name_t&name, const std::list&parms); +extern void pform_make_foreach_declarations(const struct vlltype&loc, + std::list*loop_vars); +extern PForeach* pform_make_foreach(const struct vlltype&loc, + char*ident, + std::list*loop_vars, + Statement*stmt); /* * The makewire functions announce to the pform code new wires. These @@ -352,7 +355,7 @@ extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list*names, NetNet::Type net_type, 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_string_type(const 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); @@ -409,6 +412,7 @@ extern void pform_module_specify_path(PSpecPath*obj); */ extern PProcess* pform_make_behavior(ivl_process_type_t, Statement*, list*attr); +extern void pform_mc_translate_on(bool flag); extern std::vector* pform_make_udp_input_ports(list*); @@ -526,4 +530,4 @@ extern void pform_set_timeunit(const char*txt, bool in_module, bool only_check); extern void pform_set_timeprecision(const char*txt, bool in_module, bool only_check); -#endif +#endif /* IVL_pform_H */ diff --git a/pform_dump.cc b/pform_dump.cc index a8b08c04b..981fbecd2 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -31,6 +31,7 @@ # include "PGenerate.h" # include "PPackage.h" # include "PSpec.h" +# include "PTask.h" # include "discipline.h" # include "ivl_target_priv.h" # include @@ -62,6 +63,9 @@ ostream& operator<< (ostream&out, const index_component_t&that) case index_component_t::SEL_BIT: out << *that.msb; break; + case index_component_t::SEL_BIT_LAST: + out << "$"; + break; case index_component_t::SEL_PART: out << *that.msb << ":" << *that.lsb; break; @@ -160,13 +164,6 @@ void parray_type_t::pform_dump(ostream&out, unsigned indent) const base_type->pform_dump(out, indent+4); } -void uarray_type_t::pform_dump(ostream&out, unsigned indent) const -{ - out << setw(indent) << "" << "Unpacked 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") @@ -181,12 +178,31 @@ void struct_type_t::pform_dump(ostream&out, unsigned indent) const } } +void uarray_type_t::pform_dump(ostream&out, unsigned indent) const +{ + out << setw(indent) << "" << "Unpacked array " << "[...]" + << " of:" << endl; + base_type->pform_dump(out, indent+4); +} + +void vector_type_t::pform_dump(ostream&fd, unsigned indent) const +{ + fd << setw(indent) << "" << "vector of " << base_type; + if (pdims.get()) { + for (list::iterator cur = pdims->begin() + ; cur != pdims->end() ; ++cur) { + fd << "[" << *(cur->first) << ":" << *(cur->second) << "]"; + } + } + fd << endl; +} + void class_type_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << "class " << name; if (base_type) out << " extends "; - if (base_args.size() > 0) { + if (! base_args.empty()) { out << " ("; for (list::const_iterator cur = base_args.begin() ; cur != base_args.end() ; ++cur) { @@ -954,6 +970,20 @@ void PForce::dump(ostream&out, unsigned ind) const << "; /* " << get_fileline() << " */" << endl; } +void PForeach::dump(ostream&fd, unsigned ind) const +{ + fd << setw(ind) << "" << "foreach " + << "variable=" << array_var_ + << ", indices=["; + for (size_t idx = 0 ; idx < index_vars_.size() ; idx += 1) { + if (idx > 0) fd << ","; + fd << index_vars_[idx]; + } + + fd << "] /* " << get_fileline() << " */" << endl; + statement_->dump(fd, ind+3); +} + void PForever::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "forever /* " << get_fileline() << " */" << endl; @@ -982,20 +1012,20 @@ void PFunction::dump(ostream&out, unsigned ind) const else out << setw(ind+8) << "" << "" << endl; - dump_ports_(out, ind); + dump_ports_(out, ind+2); - dump_parameters_(out, ind); + dump_parameters_(out, ind+2); - dump_localparams_(out, ind); + dump_localparams_(out, ind+2); - dump_events_(out, ind); + dump_events_(out, ind+2); - dump_wires_(out, ind); + dump_wires_(out, ind+2); if (statement_) - statement_->dump(out, ind); + statement_->dump(out, ind+2); else - out << setw(ind) << "" << "/* NOOP */" << endl; + out << setw(ind+2) << "" << "/* NOOP */" << endl; } void PRelease::dump(ostream&out, unsigned ind) const @@ -1024,20 +1054,20 @@ void PTask::dump(ostream&out, unsigned ind) const out << pscope_name() << ";" << endl; if (method_of()) out << setw(ind) << "" << "method of " << method_of()->name << ";" << endl; - dump_ports_(out, ind); + dump_ports_(out, ind+2); - dump_parameters_(out, ind); + dump_parameters_(out, ind+2); - dump_localparams_(out, ind); + dump_localparams_(out, ind+2); - dump_events_(out, ind); + dump_events_(out, ind+2); - dump_wires_(out, ind); + dump_wires_(out, ind+2); if (statement_) - statement_->dump(out, ind); + statement_->dump(out, ind+2); else - out << setw(ind) << "" << "/* NOOP */" << endl; + out << setw(ind+2) << "" << "/* NOOP */" << endl; } void PTaskFunc::dump_ports_(std::ostream&out, unsigned ind) const @@ -1610,6 +1640,11 @@ void pform_dump(std::ostream&out, const ivl_discipline_s*dis) out << "enddiscipline" << endl; } +void pform_dump(std::ostream&fd, const PClass*cl) +{ + cl->dump(fd, 0); +} + void pform_dump(std::ostream&out, const PPackage*pac) { pac->pform_dump(out); @@ -1620,7 +1655,13 @@ void PPackage::pform_dump(std::ostream&out) const out << "package " << pscope_name() << endl; dump_localparams_(out, 4); dump_parameters_(out, 4); + dump_enumerations_(out, 4); dump_tasks_(out, 4); dump_funcs_(out, 4); out << "endpackage" << endl; } + +void pform_dump(std::ostream&fd, const PTaskFunc*obj) +{ + obj->dump(fd, 0); +} diff --git a/pform_pclass.cc b/pform_pclass.cc index 3b7b94d59..0636126f4 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -46,7 +46,7 @@ void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type, assert(type->base_type == 0); type->base_type = base_type; - assert(type->base_args.size() == 0); + assert(type->base_args.empty()); if (base_exprs) { for (list::iterator cur = base_exprs->begin() ; cur != base_exprs->end() ; ++ cur) { diff --git a/pform_string_type.cc b/pform_string_type.cc index 569056764..4d1f1d2dc 100644 --- a/pform_string_type.cc +++ b/pform_string_type.cc @@ -21,13 +21,13 @@ # include "parse_misc.h" # include "ivl_assert.h" -static void pform_set_string_type(string_type_t*, perm_string name, NetNet::Type net_type, list*attr) +static void pform_set_string_type(const string_type_t*, 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) +void pform_set_string_type(const string_type_t*string_type, list*names, NetNet::Type net_type, list*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur) { diff --git a/pform_types.cc b/pform_types.cc index c809ffbf6..8d8d430d0 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -24,15 +24,6 @@ data_type_t::~data_type_t() { } -ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*scope) -{ - if (cache_type_elaborate_) - return cache_type_elaborate_; - - cache_type_elaborate_ = elaborate_type_raw(des, scope); - return cache_type_elaborate_; -} - string_type_t::~string_type_t() { } @@ -51,3 +42,5 @@ ivl_variable_type_t vector_type_t::figure_packed_base_type(void) const { return base_type; } + +atom2_type_t size_type (32, true); diff --git a/pform_types.h b/pform_types.h index 32758f5e4..b36bb01e1 100644 --- a/pform_types.h +++ b/pform_types.h @@ -1,7 +1,7 @@ -#ifndef __pform_types_H -#define __pform_types_H +#ifndef IVL_pform_types_H +#define IVL_pform_types_H /* - * Copyright (c) 2007-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2014 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 @@ -39,17 +39,49 @@ class Design; class NetScope; +class Definitions; class PExpr; class PWire; class Statement; class ivl_type_s; +class netclass_t; class netenum_t; typedef named named_number_t; typedef named named_pexpr_t; + +/* + * The pform_range_t holds variable diimensions for type + * declarations. The two expressions are interpreted as the first and + * last values of the range. For example: + * + * [ : ] -- Normal array range + * first == + * second = + * + * [] -- SystemVerilog canonical range + * first = PENumber(0) + * second = - 1; + * + * [ ] -- Dynamic array + * first = 0 + * second = 0 + * + * [ $ ] -- Queue type + * first = PENull + * second = 0 + */ typedef std::pair pform_range_t; +/* + * Semantic NOTES: + * - The SEL_BIT is a single expression. This might me a bit select + * of a vector, or a word select of an array. + * + * - The SEL_BIT_LAST index component is an array/queue [$] index, + * that is the last item in the variable. + */ struct index_component_t { - enum ctype_t { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO }; + enum ctype_t { SEL_NONE, SEL_BIT, SEL_BIT_LAST, SEL_PART, SEL_IDX_UP, SEL_IDX_DO }; index_component_t() : sel(SEL_NONE), msb(0), lsb(0) { }; ~index_component_t() { } @@ -88,7 +120,7 @@ struct pform_tf_port_t { */ class data_type_t : public LineInfo { public: - inline explicit data_type_t() : cache_type_elaborate_(0) { } + inline explicit data_type_t() { } 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. @@ -102,7 +134,8 @@ class data_type_t : public LineInfo { // Elaborate the type to an ivl_type_s type. virtual ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; - ivl_type_s*cache_type_elaborate_; + // Keep per-scope elaboration results cached. + std::map cache_type_elaborate_; }; struct void_type_t : public data_type_t { @@ -151,6 +184,8 @@ struct atom2_type_t : public data_type_t { ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; }; +extern atom2_type_t size_type; + /* * The vector_type_t class represents types in the old Verilog * way. Some typical examples: @@ -175,6 +210,7 @@ struct vector_type_t : public data_type_t { std::list*pd) : base_type(bt), signed_flag(sf), reg_flag(false), integer_flag(false), implicit_flag(false), pdims(pd) { } virtual ivl_variable_type_t figure_packed_base_type(void)const; + virtual void pform_dump(std::ostream&out, unsigned indent) const; ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; ivl_variable_type_t base_type; @@ -238,7 +274,7 @@ struct string_type_t : public data_type_t { struct class_type_t : public data_type_t { inline explicit class_type_t(perm_string n) - : name(n), base_type(0) { } + : name(n), base_type(0), save_elaborated_type(0) { } void pform_dump(std::ostream&out, unsigned indent) const; void pform_dump_init(std::ostream&out, unsigned indent) const; @@ -273,6 +309,11 @@ struct class_type_t : public data_type_t { std::vector initialize_static; ivl_type_s* elaborate_type_raw(Design*, NetScope*) const; + // The save_elaborated_type member must be set to the pointer + // to the netclass_t object that is created to represent this + // type. The elaborate_type_raw() method uses this pointer, + // and it is used in some other situations as well. + netclass_t* save_elaborated_type; }; /* @@ -318,4 +359,4 @@ extern std::ostream& operator<< (std::ostream&out, const pform_name_t&); extern std::ostream& operator<< (std::ostream&out, const name_component_t&that); extern std::ostream& operator<< (std::ostream&out, const index_component_t&that); -#endif +#endif /* IVL_pform_types_H */ diff --git a/property_qual.h b/property_qual.h index aaaa37b86..0df02a3df 100644 --- a/property_qual.h +++ b/property_qual.h @@ -1,7 +1,7 @@ -#ifndef __property_qual_H -#define __property_qual_H +#ifndef IVL_property_qual_H +#define IVL_property_qual_H /* - * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2013-2014 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 @@ -57,4 +57,4 @@ class property_qualifier_t { int mask_; }; -#endif +#endif /* IVL_property_qual_H */ diff --git a/sv_vpi_user.h b/sv_vpi_user.h index ac792e56f..1282e0ee2 100644 --- a/sv_vpi_user.h +++ b/sv_vpi_user.h @@ -1,7 +1,7 @@ -#ifndef __sv_vpi_user_H -#define __sv_vpi_user_H +#ifndef SV_VPI_USER_H +#define SV_VPI_USER_H /* - * Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2014 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 @@ -44,6 +44,11 @@ EXTERN_C_START /********* OBJECT TYPES ***********/ #define vpiPackage 600 +#define vpiArrayType 606 +#define vpiStaticArray 1 +#define vpiDynamicArray 2 +#define vpiAssocArray 3 +#define vpiQueueArray 4 #define vpiLongIntVar 610 #define vpiShortIntVar 611 #define vpiIntVar 612 @@ -69,4 +74,4 @@ EXTERN_C_START EXTERN_C_END -#endif +#endif /* SV_VPI_USER_H */ diff --git a/svector.h b/svector.h index 2e9a1d3ab..bf17dcaba 100644 --- a/svector.h +++ b/svector.h @@ -1,7 +1,7 @@ -#ifndef __svector_H -#define __svector_H +#ifndef IVL_svector_H +#define IVL_svector_H /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -118,4 +118,4 @@ template inline std::vector vector_from_svector(const svector&th return res; } -#endif +#endif /* IVL_svector_H */ diff --git a/syn-rules.y b/syn-rules.y index 1507b08df..8a86fe6e5 100644 --- a/syn-rules.y +++ b/syn-rules.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -100,7 +100,13 @@ static void hookup_DFF_CE(NetFF*ff, NetESignal*d, NetEvProbe*pclk, NetNet*ce, NetAssign_*a, unsigned rval_pinoffset) { - assert(rval_pinoffset == 0); + if (rval_pinoffset != 0) { + cerr << a->get_fileline() << ": sorry: " + << "unable to hook up an R-value with offset " + << rval_pinoffset << " to signal " << a->name() + << "." << endl; + return; + } // a->sig() is a *NetNet, which doesn't have the loff_ and // lwid_ context. Add the correction for loff_ ourselves. diff --git a/sync.cc b/sync.cc index 1b3a62d88..41c210ac2 100644 --- a/sync.cc +++ b/sync.cc @@ -33,7 +33,7 @@ bool NetProc::is_synchronous() bool NetEvWait::is_synchronous() { - for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) { + for (unsigned idx = 0 ; idx < events_.size() ; idx += 1) { NetEvent*ev = events_[idx]; if (ev->nprobe() == 0) diff --git a/synth2.cc b/synth2.cc index b6dd772cf..dcc80895d 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -34,7 +34,8 @@ bool NetProc::synth_async(Design*, NetScope*, NexusSet&, NetBus&, NetBus&) } bool NetProc::synth_sync(Design*des, NetScope*scope, - NetNet* /* ff_clk */, NetNet* /* ff_ce */, + NetNet* /* ff_clk */, NetBus& /* ff_ce */, + NetBus& /* ff_aclr*/, NetBus& /* ff_aset*/, NexusSet&nex_map, NetBus&nex_out, const vector&events) { @@ -44,6 +45,11 @@ bool NetProc::synth_sync(Design*des, NetScope*scope, des->errors += 1; } + if (debug_synth2) { + cerr << get_fileline() << ": NetProc::synth_sync: " + << "This statement is an async input to a sync process." << endl; + } + /* Synthesize the input to the DFF. */ NetBus accumulated_nex_out (scope, nex_out.pin_count()); return synth_async(des, scope, nex_map, nex_out, accumulated_nex_out); @@ -62,7 +68,7 @@ bool NetProc::synth_sync(Design*des, NetScope*scope, */ bool NetAssignBase::synth_async(Design*des, NetScope*scope, NexusSet&nex_map, NetBus&nex_out, - NetBus&) + NetBus&accumulated_nex_out) { NetNet*rsig = rval_->synthesize(des, scope, rval_); assert(rsig); @@ -76,7 +82,15 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, des->errors += 1; return false; } - assert(lval_->more == 0); + if (lval_->more) { + cerr << get_fileline() << ": sorry: " + << "NetAssignBase::synth_async does not support an " + << "L-value concatenation "; + dump_lval(cerr); + cerr << endl; + des->errors += 1; + return false; + } if (debug_synth2) { cerr << get_fileline() << ": NetAssignBase::synth_async: " @@ -84,6 +98,8 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, << "r-value signal is " << rsig->vector_width() << " bits." << endl; cerr << get_fileline() << ": NetAssignBase::synth_async: " << "lval_->lwidth()=" << lval_->lwidth() << endl; + cerr << get_fileline() << ": NetAssignBase::synth_async: " + << "lsig = " << scope_path(scope) << "." << lsig->name() << endl; if (const NetExpr*base = lval_->get_base()) { cerr << get_fileline() << ": NetAssignBase::synth_async: " << "base_=" << *base << endl; @@ -93,24 +109,32 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, << ", nex_out.pin_count()==" << nex_out.pin_count() << endl; } - /* For now, assume there is exactly one output. */ - ivl_assert(*this, nex_out.pin_count() == 1); -#if 0 - if (lval_->lwidth() != lsig->vector_width()) { + // Here we note if the l-value is actually a bit/part + // select. If so, generate a NetPartSelect to perform the select. + if ((lval_->lwidth()!=lsig->vector_width()) && !scope->loop_index_tmp.empty()) { + // If we are within a NetForLoop, there may be an index + // value. That is collected from the scope member + // loop_index_tmp, and the evaluate_function method + // knows how to apply it. + ivl_assert(*this, !scope->loop_index_tmp.empty()); ivl_assert(*this, lval_->lwidth() < lsig->vector_width()); long base_off = 0; - if (! eval_as_long(base_off, lval_->get_base())) { - assert(0); + + // Evaluate the index expression to a constant. + const NetExpr*base_expr_raw = lval_->get_base(); + ivl_assert(*this, base_expr_raw); + NetExpr*base_expr = base_expr_raw->evaluate_function(*this, scope->loop_index_tmp); + if (! eval_as_long(base_off, base_expr)) { + ivl_assert(*this, 0); } ivl_assert(*this, base_off >= 0); ivl_variable_type_t tmp_data_type = rsig->data_type(); - listnot_an_array; netvector_t*tmp_type = new netvector_t(tmp_data_type, lsig->vector_width()-1,0); NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, not_an_array, tmp_type); + NetNet::WIRE, NetNet::not_an_array, tmp_type); tmp->local_flag(true); NetPartSelect*ps = new NetPartSelect(tmp, base_off, lval_->lwidth(), NetPartSelect::PV); @@ -119,9 +143,74 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, connect(ps->pin(0), rsig->pin(0)); rsig = tmp; + + } else if (lval_->lwidth() != lsig->vector_width()) { + // In this case, there is no loop_index_tmp, so we are + // not within a NetForLoop. Generate a NetSubstitute + // object to handle the bit/part-select in the l-value. + ivl_assert(*this, scope->loop_index_tmp.empty()); + ivl_assert(*this, lval_->lwidth() < lsig->vector_width()); + + long base_off = 0; + + const NetExpr*base_expr_raw = lval_->get_base(); + ivl_assert(*this, base_expr_raw); + NetExpr*base_expr = base_expr_raw->evaluate_function(*this, scope->loop_index_tmp); + if (! eval_as_long(base_off, base_expr)) { + ivl_assert(*this, 0); + } + ivl_assert(*this, base_off >= 0); + + ivl_variable_type_t tmp_data_type = rsig->data_type(); + netvector_t*tmp_type = new netvector_t(tmp_data_type, lsig->vector_width()-1,0); + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, NetNet::not_an_array, tmp_type); + //tmp->local_flag(true); + + ivl_assert(*this, accumulated_nex_out.pin_count()==1); + NetNet*use_lsig = lsig; + if (accumulated_nex_out.pin(0).is_linked()) { + if (debug_synth2) { + cerr << get_fileline() << ": NetAssignBase::synth_async: " + << " Found a use_sig:" << endl; + accumulated_nex_out.pin(0).dump_link(cerr, 8); + } + Nexus*tmp_nex = accumulated_nex_out.pin(0).nexus(); + use_lsig = tmp_nex->pick_any_net(); + ivl_assert(*this, use_lsig); + } else { + if (debug_synth2) { + cerr << get_fileline() << ": NetAssignBase::synth_async: " + << " Found no use_sig, resorting to lsig." << endl; + } + } + + NetSubstitute*ps = new NetSubstitute(use_lsig, rsig, + tmp->vector_width(), + base_off); + ps->set_line(*this); + des->add_node(ps); + + connect(ps->pin(0), tmp->pin(0)); + rsig = tmp; + } + + if (nex_out.pin_count() > 1) { + NexusSet tmp_set; + nex_output(tmp_set); + ivl_assert(*this, tmp_set.size()==1); + unsigned ptr = nex_map.find_nexus(tmp_set[0]); + ivl_assert(*this, rsig->pin_count()==1); + ivl_assert(*this, nex_map.size()==nex_out.pin_count()); + ivl_assert(*this, nex_out.pin_count() > ptr); + connect(nex_out.pin(ptr), rsig->pin(0)); + + } else { + ivl_assert(*this, nex_out.pin_count()==1); + ivl_assert(*this, rsig->pin_count()==1); + connect(nex_out.pin(0), rsig->pin(0)); } -#endif - connect(nex_out.pin(0), rsig->pin(0)); /* This lval_ represents a reg that is a WIRE in the synthesized results. This function signals the destructor @@ -133,6 +222,87 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, return true; } +bool NetProc::synth_async_block_substatement_(Design*des, NetScope*scope, + NexusSet&nex_map, + NetBus&accumulated_nex_out, + NetProc*substmt) +{ + // Create a temporary map of the output only from this statement. + NexusSet tmp_map; + substmt->nex_output(tmp_map); + if (debug_synth2) { + cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: " + << "tmp_map.size()==" << tmp_map.size() + << " for statement at " << substmt->get_fileline() + << endl; + for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count() ; idx += 1) { + cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: " + << "accumulated_nex_out[" << idx << "] dump link" << endl; + accumulated_nex_out.pin(idx).dump_link(cerr, 8); + } + } + + /* Create also a temporary NetBus to collect the + output from the synthesis. */ + NetBus tmp_out (scope, tmp_map.size()); + + // Map (and move) the accumulated_nex_out for this block + // to the version that we can pass to the next + // statement. We will move the result back later. + NetBus accumulated_tmp_out (scope, tmp_map.size()); + for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count() ; idx += 1) { + unsigned ptr = tmp_map.find_nexus(nex_map[idx]); + if (ptr >= tmp_map.size()) + continue; + + connect(accumulated_tmp_out.pin(ptr), accumulated_nex_out.pin(idx)); + accumulated_nex_out.pin(idx).unlink(); + } + + if (debug_synth2) { + for (unsigned idx = 0 ; idx < nex_map.size() ; idx += 1) { + cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: nex_map[" << idx << "] dump link, base=" << nex_map[idx].base << ", wid=" << nex_map[idx].wid << endl; + nex_map[idx].lnk.dump_link(cerr, 8); + } + for (unsigned idx = 0 ; idx < tmp_map.size() ; idx += 1) { + cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: tmp_map[" << idx << "] dump link, base=" << tmp_map[idx].base << ", wid=" << tmp_map[idx].wid << endl; + tmp_map[idx].lnk.dump_link(cerr, 8); + } + for (unsigned idx = 0 ; idx < accumulated_tmp_out.pin_count() ; idx += 1) { + cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: accumulated_tmp_out[" << idx << "] dump link" << endl; + accumulated_tmp_out.pin(idx).dump_link(cerr, 8); + } + } + + bool ok_flag = substmt->synth_async(des, scope, tmp_map, tmp_out, accumulated_tmp_out); + + if (debug_synth2) { + cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: " + "substmt->synch_async(...) --> " << (ok_flag? "true" : "false") + << " for statement at " << substmt->get_fileline() << "." << endl; + } + + if (ok_flag == false) + return false; + + // Now map the output from the substatement back to the + // accumulated_nex_out for this block. Look for the + // nex_map pin that is linked to the tmp_map.pin(idx) + // pin, and link that to the tmp_out.pin(idx) output link. + for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) { + unsigned ptr = nex_map.find_nexus(tmp_map[idx]); + ivl_assert(*this, ptr < accumulated_nex_out.pin_count()); + if (debug_synth2) { + cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: " + << "tmp_out.pin(" << idx << "):" << endl; + tmp_out.pin(idx).dump_link(cerr, 8); + } + connect(accumulated_nex_out.pin(ptr), tmp_out.pin(idx)); + } + + return true; +} + /* * Sequential blocks are translated to asynchronous logic by * translating each statement of the block, in order, into gates. The @@ -152,45 +322,13 @@ bool NetBlock::synth_async(Design*des, NetScope*scope, do { cur = cur->next_; - /* Create a temporary map of the output only from this - statement. */ - NexusSet tmp_map; - cur->nex_output(tmp_map); - - /* Create also a temporary NetBus to collect the - output from the synthesis. */ - NetBus tmp_out (scope, tmp_map.size()); - - // Map (and move) the accumulated_nex_out for this block - // to the version that we can pass to the next - // statement. We will move the result back later. - NetBus accumulated_tmp_out (scope, tmp_map.size()); - - for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count() ; idx += 1) { - unsigned ptr = tmp_map.find_nexus(nex_map[idx]); - if (ptr >= tmp_map.size()) - continue; - - connect(accumulated_tmp_out.pin(ptr), accumulated_nex_out.pin(idx)); - accumulated_nex_out.pin(idx).unlink(); - } - - bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out, accumulated_tmp_out); - + bool ok_flag = synth_async_block_substatement_(des, scope, nex_map, + accumulated_nex_out, + cur); flag = flag && ok_flag; if (ok_flag == false) continue; - // Now map the output from the substatement back to the - // accumulated_nex_out for this block. Look for the - // nex_map pin that is linked to the tmp_map.pin(idx) - // pin, and link that to the tmp_out.pin(idx) output link. - for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) { - unsigned ptr = nex_map.find_nexus(tmp_map[idx]); - ivl_assert(*this, ptr < accumulated_nex_out.pin_count()); - connect(accumulated_nex_out.pin(ptr), tmp_out.pin(idx)); - } - } while (cur != last_); // The output from the block is now the accumulated outputs. @@ -202,13 +340,23 @@ bool NetBlock::synth_async(Design*des, NetScope*scope, bool NetCase::synth_async(Design*des, NetScope*scope, NexusSet&nex_map, NetBus&nex_out, - NetBus&) + NetBus&accumulated_nex_out) { + if (type()==NetCase::EQZ || type()==NetCase::EQX) + return synth_async_casez_(des, scope, nex_map, nex_out, accumulated_nex_out); + + // Special case: If the case expression is constant, then this + // is a pattern where the guards are non-constant and tested + // against a constant case. Handle this as chained conditions + // instead. + if (dynamic_cast (expr_)) + return synth_async_casez_(des, scope, nex_map, nex_out, accumulated_nex_out); + /* Synthesize the select expression. */ NetNet*esig = expr_->synthesize(des, scope, expr_); unsigned sel_width = esig->vector_width(); - assert(sel_width > 0); + ivl_assert(*this, sel_width > 0); ivl_assert(*this, nex_map.size() == nex_out.pin_count()); @@ -222,6 +370,14 @@ bool NetCase::synth_async(Design*des, NetScope*scope, } } + // The accumulated_nex_out is taken as the input for this + // statement. Since there are collection of statements that + // start at this same point, we save all these inputs and + // reuse them for each statement. + NetBus statement_input (scope, nex_out.pin_count()); + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { + connect(statement_input.pin(idx), accumulated_nex_out.pin(idx)); + } /* Collect all the statements into a map of index to statement. The guard expression it evaluated to be the @@ -232,14 +388,14 @@ bool NetCase::synth_async(Design*des, NetScope*scope, mapstatement_map; NetProc*statement_default = 0; - for (unsigned item = 0 ; item < nitems_ ; item += 1) { + for (size_t item = 0 ; item < items_.size() ; item += 1) { if (items_[item].guard == 0) { statement_default = items_[item].statement; continue; } NetEConst*ge = dynamic_cast(items_[item].guard); - assert(ge); + ivl_assert(*this, ge); verinum gval = ge->value(); unsigned sel_idx = gval.as_ulong(); @@ -262,21 +418,28 @@ bool NetCase::synth_async(Design*des, NetScope*scope, } - /* If there is a default clause, synthesize is once and we'll + /* If there is a default clause, synthesize it once and we'll link it in wherever it is needed. */ NetBus default_bus (scope, nex_map.size()); - vectordefault_sig (nex_map.size()); - if (statement_default) { - NetBus tmp (scope, nex_out.pin_count()); - statement_default->synth_async(des, scope, nex_map, default_bus, tmp); + bool flag = synth_async_block_substatement_(des, scope, nex_map, + accumulated_nex_out, + statement_default); + if (!flag) { + return false; + } - // Get the signal from the synthesized statement. This - // will be hooked to all the default cases. - ivl_assert(*this, default_bus.pin_count()==1); - default_sig[0] = default_bus.pin(0).nexus()->pick_any_net(); - ivl_assert(*this, default_sig[0]); + for (unsigned idx = 0 ; idx < default_bus.pin_count() ; idx += 1) { + connect(default_bus.pin(idx), accumulated_nex_out.pin(idx)); + accumulated_nex_out.pin(idx).unlink(); + } + + if (debug_synth2) { + cerr << get_fileline() << ": NetCase::synth_async: " + << "synthesize default clause at " << statement_default->get_fileline() + << " is done." << endl; + } } vector mux (mux_width.size()); @@ -312,9 +475,9 @@ bool NetCase::synth_async(Design*des, NetScope*scope, NetProc*stmt = statement_map[idx]; if (stmt==0 && statement_default) { - ivl_assert(*this, default_sig.size() == mux.size()); + ivl_assert(*this, default_bus.pin_count() == mux.size()); for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1) - connect(mux[mdx]->pin_Data(idx), default_sig[mdx]->pin(0)); + connect(mux[mdx]->pin_Data(idx), default_bus.pin(mdx)); continue; } @@ -325,17 +488,19 @@ bool NetCase::synth_async(Design*des, NetScope*scope, continue; } - NetBus tmp (scope, nex_map.size()); NetBus accumulated_tmp (scope, nex_map.size()); - stmt->synth_async(des, scope, nex_map, tmp, accumulated_tmp); + for (unsigned pin = 0 ; pin < nex_map.size() ; pin += 1) + connect(accumulated_tmp.pin(pin), statement_input.pin(pin)); + + + synth_async_block_substatement_(des, scope, nex_map, accumulated_tmp, stmt); - ivl_assert(*this, tmp.pin_count() == mux.size()); for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1) { - connect(mux[mdx]->pin_Data(idx), tmp.pin(mdx)); + connect(mux[mdx]->pin_Data(idx), accumulated_tmp.pin(mdx)); if (mux[mdx]->pin_Data(idx).nexus()->pick_any_net()==0) { cerr << get_fileline() << ": warning: case " << idx - << " has no input for mux " << mdx << "." << endl; + << " has no input for mux slice " << mdx << "." << endl; ivl_variable_type_t mux_data_type = IVL_VT_LOGIC; netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width[mdx]-1, 0); @@ -352,6 +517,188 @@ bool NetCase::synth_async(Design*des, NetScope*scope, return true; } +/* + * casez statements are hard to implement as a single wide mux because + * the test doesn't really map to a select input. Instead, implement + * it as a chain of binary muxes. This gives the synthesizer my + * flexibility, and is more typically what is desired from a casez anyhow. + */ +bool NetCase::synth_async_casez_(Design*des, NetScope*scope, + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out) +{ + /* Synthesize the select expression. */ + NetNet*esig = expr_->synthesize(des, scope, expr_); + + unsigned sel_width = esig->vector_width(); + ivl_assert(*this, sel_width > 0); + + ivl_assert(*this, nex_map.size() == nex_out.pin_count()); + + if (debug_synth2) { + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { + cerr << get_fileline() << ": NetCase::synth_async_casez_: " + << "nex_out.pin(" << idx << "):" << endl; + nex_out.pin(idx).dump_link(cerr, 8); + } + for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count() ; idx += 1) { + cerr << get_fileline() << ": NetCase::synth_async_casez_: " + << "accumulated_nex_out.pin(" << idx << "):" << endl; + accumulated_nex_out.pin(idx).dump_link(cerr, 8); + } + } + + vectormux_width (nex_out.pin_count()); + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { + mux_width[idx] = nex_map[idx].wid; + if (debug_synth2) { + cerr << get_fileline() << ": NetCase::synth_async_casez_: " + << "idx=" << idx + << ", mux_width[idx]=" << mux_width[idx] << endl; + } + } + + // The accumulated_nex_out is taken as the input for this + // statement. Since there are collection of statements that + // start at this same point, we save all these inputs and + // reuse them for each statement. + NetBus statement_input (scope, nex_out.pin_count()); + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { + connect(statement_input.pin(idx), accumulated_nex_out.pin(idx)); + } + + // Look for a default statement. + NetProc*statement_default = 0; + for (size_t item = 0 ; item < items_.size() ; item += 1) { + if (items_[item].guard != 0) + continue; + + ivl_assert(*this, statement_default==0); + statement_default = items_[item].statement; + } + + NetBus default_bus (scope, nex_out.pin_count()); + if (statement_default) { + bool flag = synth_async_block_substatement_(des, scope, nex_map, + accumulated_nex_out, + statement_default); + if (!flag) { + return false; + } + + for (unsigned idx = 0 ; idx < default_bus.pin_count() ; idx += 1) { + connect(default_bus.pin(idx), accumulated_nex_out.pin(idx)); + accumulated_nex_out.pin(idx).unlink(); + } + + if (debug_synth2) { + cerr << get_fileline() << ": NetCase::synth_async_casez_: " + << "synthesize default clause at " << statement_default->get_fileline() + << " is done." << endl; + } + } + + netvector_t*condit_type = new netvector_t(IVL_VT_LOGIC, 0, 0); + + NetCaseCmp::kind_t case_kind; + switch (type()) { + case NetCase::EQ: + case_kind = NetCaseCmp::EEQ; + break; + case NetCase::EQX: + case_kind = NetCaseCmp::XEQ; + break; + case NetCase::EQZ: + case_kind = NetCaseCmp::ZEQ; + break; + default: + assert(0); + } + + // Process the items from last to first. We generate a + // true/false mux, with the select being the comparison of + // the case select with the guard expression. The true input + // (data1) is the current statement, and the false input is + // the result of a later statement. + vectormux_prev (mux_width.size()); + for (size_t idx = 0 ; idx < items_.size() ; idx += 1) { + size_t item = items_.size()-idx-1; + if (items_[item].guard == 0) + continue; + + NetProc*stmt = items_[item].statement; + ivl_assert(*this, stmt); + + NetExpr*guard_expr = items_[item].guard; + NetNet*guard = guard_expr->synthesize(des, scope, guard_expr); + + NetCaseCmp*condit_dev = new NetCaseCmp(scope, scope->local_symbol(), + sel_width, case_kind); + des->add_node(condit_dev); + condit_dev->set_line(*this); + // Note that the expression that may have windcards must + // go in the pin(2) input. This is the definiton of the + // NetCaseCmp statement. + connect(condit_dev->pin(1), esig->pin(0)); + connect(condit_dev->pin(2), guard->pin(0)); + + NetNet*condit = new NetNet(scope, scope->local_symbol(), + NetNet::TRI, condit_type); + condit->set_line(*this); + condit->local_flag(true); + connect(condit_dev->pin(0), condit->pin(0)); + + // Synthesize the guarded statement. + NetBus true_bus (scope, nex_out.pin_count()); + for (unsigned pin = 0 ; pin < nex_map.size() ; pin += 1) + connect(true_bus.pin(pin), statement_input.pin(pin)); + + synth_async_block_substatement_(des, scope, nex_map, true_bus, stmt); + + for (unsigned mdx = 0 ; mdx < mux_width.size() ; mdx += 1) { + NetMux*mux_cur = new NetMux(scope, scope->local_symbol(), + mux_width[mdx], 2, 1); + des->add_node(mux_cur); + mux_cur->set_line(*this); + connect(mux_cur->pin_Sel(), condit->pin(0)); + + connect(mux_cur->pin_Data(1), true_bus.pin(mdx)); + + // If there is a previous mux, then use that as the + // false clause input. Otherwise, use the + // default. But wait, if there is no default, then + // use the accumulated input. + if (mux_prev[mdx]) { + connect(mux_cur->pin_Data(0), mux_prev[mdx]->pin_Result()); + } else if (default_bus.pin(mdx).is_linked()) { + connect(mux_cur->pin_Data(0), default_bus.pin(mdx)); + + } else { + connect(mux_cur->pin_Data(0), statement_input.pin(mdx)); + } + + // Make a NetNet for the result. + ivl_variable_type_t mux_data_type = IVL_VT_LOGIC; + netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width[mdx]-1, 0); + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::TRI, tmp_vec); + tmp->local_flag(true); + ivl_assert(*this, tmp->vector_width() != 0); + connect(mux_cur->pin_Result(), tmp->pin(0)); + + // This mux becomes the "false" input to the next mux. + mux_prev[mdx] = mux_cur; + } + } + + // Connect the last mux to the output. + for (size_t mdx = 0 ; mdx < mux_prev.size() ; mdx += 1) { + connect(mux_prev[mdx]->pin_Result(), nex_out.pin(mdx)); + } + + return true; +} + /* * A condit statement (if (cond) ... else ... ;) infers an A-B mux, * with the cond expression acting as a select input. If the cond @@ -375,21 +722,40 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, cerr << get_fileline() << ": error: Asynchronous if statement" << " cannot synthesize missing \"else\"" << " without generating latches." << endl; - return false; + //return false; } } ivl_assert(*this, if_ != 0); - // Synthesize the condition. This will act as a select signal // for a binary mux. NetNet*ssig = expr_->synthesize(des, scope, expr_); assert(ssig); + if (debug_synth2) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "Synthesize if clause at " << if_->get_fileline() + << endl; + for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count(); idx += 1) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "accumulated_nex_out.pin(" << idx << "):" << endl; + accumulated_nex_out.pin(idx).dump_link(cerr, 8); + } + } + + NetBus statement_input (scope, nex_out.pin_count()); + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { + connect(statement_input.pin(idx), accumulated_nex_out.pin(idx)); + if (debug_synth2) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "statement_input.pin(" << idx << "):" << endl; + statement_input.pin(idx).dump_link(cerr, 8); + } + } + bool flag; NetBus asig(scope, nex_out.pin_count()); - NetBus atmp(scope, nex_out.pin_count()); - flag = if_->synth_async(des, scope, nex_map, asig, atmp); + flag = if_->synth_async(des, scope, nex_map, asig, accumulated_nex_out); if (!flag) { return false; } @@ -402,33 +768,188 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, connect(bsig.pin(idx), accumulated_nex_out.pin(idx)); accumulated_nex_out.pin(idx).unlink(); } + } else { - flag = else_->synth_async(des, scope, nex_map, bsig, btmp); + + if (debug_synth2) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "Synthesize else clause at " << else_->get_fileline() + << endl; + for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count(); idx += 1) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "accumulated_nex_out.pin(" << idx << "):" << endl; + accumulated_nex_out.pin(idx).dump_link(cerr, 8); + } + for (unsigned idx = 0 ; idx < statement_input.pin_count() ; idx += 1) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "statement_input.pin(" << idx << "):" << endl; + statement_input.pin(idx).dump_link(cerr, 8); + } + } + + NetBus accumulated_btmp_out (scope, statement_input.pin_count()); + for (unsigned idx = 0 ; idx < accumulated_btmp_out.pin_count() ; idx += 1) { + if (statement_input.pin(idx).is_linked()) + connect(accumulated_btmp_out.pin(idx), statement_input.pin(idx)); + else + connect(accumulated_btmp_out.pin(idx), accumulated_nex_out.pin(idx)); + } + if (debug_synth2) { + for (unsigned idx = 0 ; idx < accumulated_btmp_out.pin_count() ; idx += 1) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "accumulated_btmp_out.pin(" << idx << "):" << endl; + accumulated_btmp_out.pin(idx).dump_link(cerr, 8); + } + } + + flag = synth_async_block_substatement_(des, scope, nex_map, accumulated_btmp_out, else_); if (!flag) { return false; } + if (debug_synth2) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "synthesize else clause at " << else_->get_fileline() + << " is done." << endl; + for (unsigned idx = 0 ; idx < accumulated_btmp_out.pin_count() ; idx += 1) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "accumulated_btmp_out.pin(" << idx << "):" << endl; + accumulated_btmp_out.pin(idx).dump_link(cerr, 8); + } + } + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { + connect(bsig.pin(idx), accumulated_btmp_out.pin(idx)); + accumulated_btmp_out.pin(idx).unlink(); + } + } + /* The nex_out output, asig input, and bsig input all have the + same pin count (usually, but not always 1) because they are + net arrays of the same dimension. The for loop below creates + a NetMux for each pin of the output. (Note that pins may + be, in fact usually are, vectors.) */ + ivl_assert(*this, nex_out.pin_count()==asig.pin_count()); ivl_assert(*this, nex_out.pin_count()==bsig.pin_count()); + bool rc_flag = true; for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { - ivl_assert(*this, asig.pin(idx).nexus()->pick_any_net()); - ivl_assert(*this, bsig.pin(idx).nexus()->pick_any_net()); + // It should not be possible for the a (true) or b + // (false) signals to be missing. If either is, print a + // warning and clear a flag so that the rest of this + // code can find a way to cope. + bool asig_is_present = true; + if (! asig.pin(idx).nexus()->pick_any_net()) { + cerr << get_fileline() << ": warning: " + << "True clause of conditional statement might not" + << " drive all expected outputs." << endl; + asig_is_present = false; + } + + bool bsig_is_present = true; + if (! bsig.pin(idx).nexus()->pick_any_net()) { + cerr << get_fileline() << ": warning: " + << "False clause of conditional statement might not" + << " drive all expected outputs." << endl; + bsig_is_present = false; + } + // Guess the mux type from the type of the output. ivl_variable_type_t mux_data_type = IVL_VT_LOGIC; if (NetNet*tmp = nex_out.pin(idx).nexus()->pick_any_net()) { mux_data_type = tmp->data_type(); } - unsigned mux_width = asig.pin(idx).nexus()->vector_width(); + + unsigned mux_off = 0; + unsigned mux_width; + if (asig_is_present) + mux_width = asig.pin(idx).nexus()->vector_width(); + else if (bsig_is_present) + mux_width = bsig.pin(idx).nexus()->vector_width(); + else + mux_width = 0; + + if (debug_synth2) { + if (asig_is_present) + cerr << get_fileline() << ": NetCondit::synth_async: " + << "asig_is_present," + << " asig width=" << asig.pin(idx).nexus()->vector_width() + << endl; + if (bsig_is_present) + cerr << get_fileline() << ": NetCondit::synth_async: " + << "bsig_is_present," + << " bsig width=" << bsig.pin(idx).nexus()->vector_width() + << endl; + cerr << get_fileline() << ": NetCondit::synth_async: " + << "Calculated mux_width=" << mux_width + << endl; + } + + NetPartSelect*apv = detect_partselect_lval(asig.pin(idx)); + if (debug_synth2 && apv) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "Assign-to-part apv base=" << apv->base() + << ", width=" << apv->width() << endl; + } + + NetPartSelect*bpv = detect_partselect_lval(bsig.pin(idx)); + if (debug_synth2 && bpv) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "Assign-to-part bpv base=" << bpv->base() + << ", width=" << bpv->width() << endl; + } + + unsigned mux_lwidth = mux_width; ivl_assert(*this, mux_width != 0); - ivl_assert(*this, mux_width==bsig.pin(idx).nexus()->vector_width()); + + if (apv && bpv && apv->width()==bpv->width() && apv->base()==bpv->base()) { + // The a and b sides are both assigning to the + // same bits of the output, so we can use that to + // create a much narrower mux that only + // manipulates the width of the part. + mux_width = apv->width(); + mux_off = apv->base(); + asig.pin(idx).unlink(); + bsig.pin(idx).unlink(); + connect(asig.pin(idx), apv->pin(0)); + connect(bsig.pin(idx), bpv->pin(0)); + delete apv; + delete bpv; + } else { + // The part selects are of no use. Forget them. + apv = 0; + bpv = 0; + } + + if (bsig_is_present && mux_width != bsig.pin(idx).nexus()->vector_width()) { + cerr << get_fileline() << ": internal error: " + << "NetCondit::synth_async: " + << "Mux input sizes do not match." + << " A size=" << mux_lwidth + << ", B size=" << bsig.pin(idx).nexus()->vector_width() + << endl; + cerr << get_fileline() << ": : " + << "asig node pins:" << endl; + asig.dump_node_pins(cerr, 8); + cerr << get_fileline() << ": : " + << "if_ statement:" << endl; + if_->dump(cerr, 8); + cerr << get_fileline() << ": : " + << "bsig node pins:" << endl; + bsig.dump_node_pins(cerr, 4); + if (else_) { + cerr << get_fileline() << ": : " + << "else_ statement:" << endl; + else_->dump(cerr, 8); + } + rc_flag = false; + } NetMux*mux = new NetMux(scope, scope->local_symbol(), mux_width, 2, 1); + mux->set_line(*this); - listnot_an_array; - netvector_t*tmp_type; + netvector_t*tmp_type = 0; if (mux_width==1) tmp_type = new netvector_t(mux_data_type); else @@ -436,19 +957,72 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, // Bind some temporary signals to carry pin type. NetNet*otmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, not_an_array, tmp_type); + NetNet::WIRE, NetNet::not_an_array, tmp_type); otmp->local_flag(true); - connect(nex_out.pin(idx),otmp->pin(0)); + connect(mux->pin_Result(),otmp->pin(0)); connect(mux->pin_Sel(), ssig->pin(0)); connect(mux->pin_Data(1), asig.pin(idx)); connect(mux->pin_Data(0), bsig.pin(idx)); - connect(nex_out.pin(idx), mux->pin_Result()); + + if (! asig_is_present) { + tmp_type = new netvector_t(mux_data_type, mux_width-1,0); + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, NetNet::not_an_array, tmp_type); + connect(mux->pin_Data(1), tmp->pin(0)); + } + + if (! bsig_is_present) { + tmp_type = new netvector_t(mux_data_type, mux_width-1,0); + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, NetNet::not_an_array, tmp_type); + connect(mux->pin_Data(0), tmp->pin(0)); + } + + // We are only muxing a part of the output vector, so + // make a NetPartSelect::PV to widen the vector to the + // output at hand. + if (mux_width < mux_lwidth) { + tmp_type = new netvector_t(mux_data_type, mux_lwidth-1,0); + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, NetNet::not_an_array, tmp_type); + NetPartSelect*ps = new NetPartSelect(tmp, mux_off, mux_width, NetPartSelect::PV); + des->add_node(ps); + connect(ps->pin(0), otmp->pin(0)); + otmp = tmp; + } + + connect(nex_out.pin(idx), otmp->pin(0)); + + // Handle the special case that this NetMux is only + // assigning to a part of the vector. If that is the + // case, then we need to blend this output with the + // already calculated input to this statement so that we + // don't accidentally disconnect the other drivers to + // other bits. + // FIXME: NEED TO CHECK THAT THESE DRIVERS DON'T + // OVERLAP. THIS CODE CURRENTLY DOESN'T DO THAT TEST. + if (mux_width < mux_lwidth && if_ && else_) { + if (debug_synth2) { + cerr << get_fileline() << ": NetCondit::synth_async: " + << "This NetMux only impacts a few bits of output," + << " so combine nex_out with statement input." + << endl; + cerr << get_fileline() << ": NetCondit::synth_async: " + << "MISSING TEST FOR CORRECTNESS OF THE BLEND!" + << endl; + } + vectormask = statement_input.pin(idx).nexus()->driven_mask(); + for (size_t bit = mux_off ; bit < mux_off+mux_width ; bit += 1) { + ivl_assert(*this, mask[bit]==false); + } + connect(nex_out.pin(idx), statement_input.pin(idx)); + } des->add_node(mux); } - return true; + return rc_flag; } bool NetEvWait::synth_async(Design*des, NetScope*scope, @@ -459,6 +1033,108 @@ bool NetEvWait::synth_async(Design*des, NetScope*scope, return flag; } +bool NetForLoop::synth_async(Design*des, NetScope*scope, + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out) +{ + if (debug_synth2) { + cerr << get_fileline() << ": NetForLoop::synth_async: " + << "Index variable is " << index_->name() << endl; + cerr << get_fileline() << ": NetForLoop::synth_async: " + << "Initialization expression: " << *init_expr_ << endl; + } + + // Get the step assignment statement and break it into the + // l-value (should be the index) and the r-value, which is the + // step expressions. + NetAssign*step_assign = dynamic_cast (step_statement_); + char assign_operator = step_assign->assign_operator(); + ivl_assert(*this, step_assign); + NetExpr*step_expr = step_assign->rval(); + + // Tell the scope that this index value is like a genvar. + LocalVar index_var; + index_var.nwords = 0; + + map index_args; + + // Calculate the initial value for the index. + index_var.value = init_expr_->evaluate_function(*this, index_args); + ivl_assert(*this, index_var.value); + index_args[index_->name()] = index_var; + + for (;;) { + // Evaluate the condition expression. If it is false, + // then we are going to break out of this synthesis loop. + NetExpr*tmp = condition_->evaluate_function(*this, index_args); + ivl_assert(*this, tmp); + + long cond_value; + bool rc = eval_as_long(cond_value, tmp); + ivl_assert(*this, rc); + delete tmp; + if (!cond_value) break; + + scope->genvar_tmp = index_->name(); + rc = eval_as_long(scope->genvar_tmp_val, index_var.value); + ivl_assert(*this, rc); + + if (debug_synth2) { + cerr << get_fileline() << ": NetForLoop::synth_async: " + << "Synthesis iteration with " << index_->name() + << "=" << *index_var.value << endl; + } + + // Synthesize the iterated expression. Stash the loop + // index value so that the substatements can see this + // value and use it during its own synthesis. + ivl_assert(*this, scope->loop_index_tmp.empty()); + scope->loop_index_tmp = index_args; + + rc = synth_async_block_substatement_(des, scope, nex_map, + accumulated_nex_out, + statement_); + + scope->loop_index_tmp.clear(); + + // Evaluate the step_expr to generate the next index value. + tmp = step_expr->evaluate_function(*this, index_args); + ivl_assert(*this, tmp); + + // If there is an assign_operator, then replace the + // index_var.value with (value tmp) and evaluate + // that to get the next value. "value" is the existing + // value, and "tmp" is the step value. We are replacing + // (value += tmp) with (value = value + tmp) and + // evaluating it. + switch (assign_operator) { + case 0: + break; + case '+': + case '-': + index_var.value = new NetEBAdd(assign_operator, tmp, index_var.value, 32, true); + tmp = index_var.value->evaluate_function(*this, index_args); + break; + + default: + cerr << get_fileline() << ": internal error: " + << "NetForLoop::synth_async: What to do with assign_operator=" << assign_operator << endl; + ivl_assert(*this, 0); + } + delete index_var.value; + index_var.value = tmp; + index_args[index_->name()] = index_var; + } + + delete index_var.value; + + // The output from the block is now the accumulated outputs. + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) + connect(nex_out.pin(idx), accumulated_nex_out.pin(idx)); + + return true; +} + /* * This method is called when the process is shown to be * asynchronous. Figure out the nexus set of outputs from this @@ -482,10 +1158,9 @@ bool NetProcTop::synth_async(Design*des) NexusSet::elem_t&item = nex_set[idx]; if (item.base != 0 || item.wid!=item.lnk.nexus()->vector_width()) { ivl_variable_type_t tmp_data_type = IVL_VT_LOGIC; - listnot_an_array; netvector_t*tmp_type = new netvector_t(tmp_data_type, item.lnk.nexus()->vector_width()-1,0); NetNet*tmp_sig = new NetNet(scope(), scope()->local_symbol(), - NetNet::WIRE, not_an_array, tmp_type); + NetNet::WIRE, NetNet::not_an_array, tmp_type); tmp_sig->local_flag(true); NetPartSelect*tmp = new NetPartSelect(tmp_sig, item.base, @@ -520,10 +1195,16 @@ bool NetProcTop::synth_async(Design*des) * the statements may each infer different reset and enable signals. */ bool NetBlock::synth_sync(Design*des, NetScope*scope, - NetNet*ff_clk, NetNet*ff_ce, + NetNet*ff_clk, NetBus&ff_ce, + NetBus&ff_aclr,NetBus&ff_aset, NexusSet&nex_map, NetBus&nex_out, const vector&events_in) { + if (debug_synth2) { + cerr << get_fileline() << ": NetBlock::synth_sync: " + << "Examine this block for synchronous logic." << endl; + } + bool flag = true; NetProc*cur = last_; @@ -534,22 +1215,32 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NexusSet tmp_set; cur->nex_output(tmp_set); - /* NOTE: After this point, tmp_set should not be used as - the various functions I call do a lot of connecting, - and the nexa in the tmp_set may get realloced. Use - the tmp_map instead. */ - /* Create also a temporary net_out to collect the output. The tmp1 and tmp2 map and out sets together are used to collect the outputs from the substatement for the inputs of the FF bank. */ NetBus tmp_out (scope, tmp_set.size()); + /* Create a temporary ff_ce (FF clock-enable) that + accounts for the subset of outputs that this + substatement drives. This allows for the possibility + that the substatement has CE patterns of its own. */ + NetBus tmp_ce (scope, tmp_set.size()); + for (unsigned idx = 0 ; idx < tmp_ce.pin_count() ; idx += 1) { + unsigned ptr = nex_map.find_nexus(tmp_set[idx]); + ivl_assert(*this, ptr < nex_out.pin_count()); + if (ff_ce.pin(ptr).is_linked()) { + connect(tmp_ce.pin(idx), ff_ce.pin(ptr)); + ff_ce.pin(ptr).unlink(); + } + } + /* Now go on with the synchronous synthesis for this subset of the statement. The tmp_map is the output nexa that we expect, and the tmp_out is where we want those outputs connected. */ - bool ok_flag = cur->synth_sync(des, scope, ff_clk, ff_ce, + bool ok_flag = cur->synth_sync(des, scope, ff_clk, tmp_ce, + ff_aclr, ff_aset, tmp_set, tmp_out, events_in); flag = flag && ok_flag; @@ -563,12 +1254,18 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, an assignment is smaller than the r-value. */ for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) { unsigned ptr = nex_map.find_nexus(tmp_set[idx]); - assert(ptr < nex_out.pin_count()); + ivl_assert(*this, ptr < nex_out.pin_count()); connect(nex_out.pin(ptr), tmp_out.pin(idx)); + connect(ff_ce.pin(ptr), tmp_ce.pin(idx)); } } while (cur != last_); + if (debug_synth2) { + cerr << get_fileline() << ": NetBlock::synth_sync: " + << "Done Examining this block for synchronous logic." << endl; + } + return flag; } @@ -579,7 +1276,8 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, * expression is connected to an event, or not. */ bool NetCondit::synth_sync(Design*des, NetScope*scope, - NetNet*ff_clk, NetNet*ff_ce, + NetNet*ff_clk, NetBus&ff_ce, + NetBus&ff_aclr,NetBus&ff_aset, NexusSet&nex_map, NetBus&nex_out, const vector&events_in) { @@ -599,65 +1297,80 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, if (! expr_input->contains(pin_set)) continue; - cerr << get_fileline() << ": sorry: " - << "Forgot how to implement asynchronous set/reset." << endl; - return false; -#if 0 - /* Ah, this edge is in the sensitivity list for the - expression, so we have an asynchronous - input. Synthesize the set/reset input expression. */ - - NetNet*rst = expr_->synthesize(des); - assert(rst->pin_count() == 1); + // Synthesize the set/reset input expression. + NetNet*rst = expr_->synthesize(des, scope, expr_); + ivl_assert(*this, rst->pin_count() == 1); /* XXXX I really should find a way to check that the edge used on the reset input is correct. This would involve interpreting the expression that is fed by the reset expression. */ - //assert(ev->edge() == NetEvProbe::POSEDGE); + ivl_assert(*this, ev->edge() == NetEvProbe::POSEDGE); - /* Synthesize the true clause to figure out what - kind of set/reset we have. */ - NetNet*asig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, nex_map->pin_count()); - asig->local_flag(true); + // Synthesize the true clause to figure out what kind of + // set/reset we have. This should synthesize down to a + // constant. If not, we have an asynchronous LOAD, a + // very different beast. + ivl_assert(*this, if_); + bool flag; + NetBus tmp_out(scope, nex_out.pin_count()); + NetBus accumulated_tmp_out(scope, nex_out.pin_count()); + flag = if_->synth_async(des, scope, nex_map, tmp_out, accumulated_tmp_out); + if (! flag) return false; - assert(if_ != 0); - bool flag = if_->synth_async(des, scope, nex_map, asig); + ivl_assert(*this, tmp_out.pin_count() == ff_aclr.pin_count()); + ivl_assert(*this, tmp_out.pin_count() == ff_aset.pin_count()); - assert(asig->pin_count() == ff->width()); + for (unsigned pin = 0 ; pin < tmp_out.pin_count() ; pin += 1) { + Nexus*rst_nex = tmp_out.pin(pin).nexus(); - /* Collect the set/reset value into a verinum. If - this turns out to be entirely 0 values, then - use the Aclr input. Otherwise, use the Aset - input and save the set value. */ - verinum tmp (verinum::V0, ff->width()); - for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) { + vector rst_mask = rst_nex->driven_mask(); + if (debug_synth2) { + cerr << get_fileline() << ": NetCondit::synth_sync: " + << "nex_out pin=" << pin + << ", rst_mask.size()==" << rst_mask.size() + << ", rst_nex->vector_width()=" << rst_nex->vector_width() + << endl; + } - assert(asig->pin(bit).nexus()->drivers_constant()); - tmp.set(bit, asig->pin(bit).nexus()->driven_value()); + for (size_t bit = 0 ; bit < rst_mask.size() ; bit += 1) { + if (rst_mask[bit]==false) { + cerr << get_fileline() << ": sorry: " + << "Asynchronous LOAD not implemented." << endl; + return false; + } + } + + verinum rst_drv = rst_nex->driven_vector(); + ivl_assert(*this, rst_drv.len()==rst_mask.size()); + + verinum zero (verinum::V0, rst_drv.len()); + verinum ones (verinum::V1, rst_drv.len()); + + if (rst_drv==zero) { + // Don't yet support multiple asynchronous reset inputs. + ivl_assert(*this, ! ff_aclr.pin(pin).is_linked()); + + ivl_assert(*this, rst->pin_count()==1); + connect(ff_aclr.pin(pin), rst->pin(0)); + + } else if (rst_drv==ones) { + // Don't yet support multiple asynchronous set inputs. + ivl_assert(*this, ! ff_aset.pin(pin).is_linked()); + + ivl_assert(*this, rst->pin_count()==1); + connect(ff_aset.pin(pin), rst->pin(0)); + + } else { + cerr << get_fileline() << ": sorry: " + << "Forgot how to implement asynchronous scramble (set to x/z)." << endl; + return false; + } } - assert(tmp.is_defined()); - if (tmp.is_zero()) { - connect(ff->pin_Aclr(), rst->pin(0)); - - } else { - connect(ff->pin_Aset(), rst->pin(0)); - ff->aset_value(tmp); - } - - delete asig; - delete expr_input; - - assert(events_in.count() == 1); - assert(else_ != 0); - flag = else_->synth_sync(des, scope, ff, nex_map, - nex_out, svector(0)) - && flag; - DEBUG_SYNTH2_EXIT("NetCondit",flag) - return flag; -#endif + return else_->synth_sync(des, scope, ff_clk, ff_ce, + ff_aclr, ff_aset, + nex_map, nex_out, vector(0)); } delete expr_input; @@ -748,7 +1461,33 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, /* Synthesize the enable expression. */ NetNet*ce = expr_->synthesize(des, scope, expr_); - ivl_assert(*this, ce->pin_count()==1 && ce->vector_width()==1); + ivl_assert(*this, ce && ce->pin_count()==1 && ce->vector_width()==1); + + if (debug_synth2) { + NexusSet if_set; + if_->nex_output(if_set); + + cerr << get_fileline() << ": NetCondit::synth_sync: " + << "Found ce pattern." + << " ff_ce.pin_count()=" << ff_ce.pin_count() + << endl; + for (unsigned idx = 0 ; idx < nex_map.size() ; idx += 1) { + cerr << get_fileline() << ": NetCondit::synth_sync: " + << "nex_map[" << idx << "]: " + << "base=" << nex_map[idx].base + << ", wid=" << nex_map[idx].wid + << endl; + nex_map[idx].lnk.dump_link(cerr, 8); + } + for (unsigned idx = 0 ; idx < if_set.size() ; idx += 1) { + cerr << get_fileline() << ": NetCondit::synth_sync: " + << "if_set[" << idx << "]: " + << "base=" << if_set[idx].base + << ", wid=" << if_set[idx].wid + << endl; + if_set[idx].lnk.dump_link(cerr, 8); + } + } /* What's left, is a synchronous CE statement like this: @@ -767,32 +1506,40 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, In this case, we are working on the inner IF, so we AND the a and b expressions to make a new CE. */ - if (ff_ce->pin(0).is_linked()) { - NetLogic*ce_and = new NetLogic(scope, - scope->local_symbol(), 3, - NetLogic::AND, 1); - des->add_node(ce_and); - connect(ff_ce->pin(0), ce_and->pin(1)); - connect(ce->pin(0), ce_and->pin(2)); + for (unsigned idx = 0 ; idx < ff_ce.pin_count() ; idx += 1) { + if (ff_ce.pin(idx).is_linked()) { + NetLogic*ce_and = new NetLogic(scope, + scope->local_symbol(), 3, + NetLogic::AND, 1); + des->add_node(ce_and); + connect(ff_ce.pin(idx), ce_and->pin(1)); + connect(ce->pin(0), ce_and->pin(2)); - ff_ce->pin(0).unlink(); - connect(ff_ce->pin(0), ce_and->pin(0)); + ff_ce.pin(idx).unlink(); + connect(ff_ce.pin(idx), ce_and->pin(0)); - } else { + } else { - connect(ff_ce->pin(0), ce->pin(0)); + connect(ff_ce.pin(idx), ce->pin(0)); + } } - bool flag = if_->synth_sync(des, scope, ff_clk, ff_ce, nex_map, nex_out, events_in); + bool flag = if_->synth_sync(des, scope, ff_clk, ff_ce, ff_aclr, ff_aset, nex_map, nex_out, events_in); return flag; } bool NetEvWait::synth_sync(Design*des, NetScope*scope, - NetNet*ff_clk, NetNet*ff_ce, + NetNet*ff_clk, NetBus&ff_ce, + NetBus&ff_aclr,NetBus&ff_aset, NexusSet&nex_map, NetBus&nex_out, const vector&events_in) { + if (debug_synth2) { + cerr << get_fileline() << ": NetEvWait::synth_sync: " + << "Synchronous process an event statement." << endl; + } + if (events_in.size() > 0) { cerr << get_fileline() << ": error: Events are unaccounted" << " for in process synthesis." << endl; @@ -803,7 +1550,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, /* This can't be other than one unless there are named events, which I cannot synthesize. */ - assert(nevents_ == 1); + ivl_assert(*this, events_.size() == 1); NetEvent*ev = events_[0]; assert(ev->nprobe() >= 1); @@ -847,6 +1594,11 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, return false; } + if (debug_synth2) { + cerr << get_fileline() << ": NetEvWait::synth_sync: " + << "Found and synthesized the FF clock." << endl; + } + connect(ff_clk->pin(0), pclk->pin(0)); if (pclk->edge() == NetEvProbe::NEGEDGE) { perm_string polarity = perm_string::literal("Clock:LPM_Polarity"); @@ -861,6 +1613,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, /* Synthesize the input to the DFF. */ bool flag = statement_->synth_sync(des, scope, ff_clk, ff_ce, + ff_aclr, ff_aset, nex_map, nex_out, events); return flag; @@ -874,7 +1627,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, bool NetProcTop::synth_sync(Design*des) { if (debug_synth2) { - cerr << get_fileline() << ": debug: " + cerr << get_fileline() << ": NetProcTop::synth_sync: " << "Process is apparently synchronous. Making NetFFs." << endl; } @@ -891,12 +1644,17 @@ bool NetProcTop::synth_sync(Design*des) NetNet::TRI, &netvector_t::scalar_logic); clock->local_flag(true); +#if 0 NetNet*ce = new NetNet(scope(), scope()->local_symbol(), NetNet::TRI, &netvector_t::scalar_logic); ce->local_flag(true); - +#else + NetBus ce (scope(), nex_set.size()); +#endif NetBus nex_d (scope(), nex_set.size()); NetBus nex_q (scope(), nex_set.size()); + NetBus aclr (scope(), nex_set.size()); + NetBus aset (scope(), nex_set.size()); /* The Q of the NetFF devices is connected to the output that we are. The nex_q is a bundle of the outputs. We will also @@ -909,7 +1667,7 @@ bool NetProcTop::synth_sync(Design*des) // Connect the input later. /* Synthesize the input to the DFF. */ - bool flag = statement_->synth_sync(des, scope(), clock, ce, + bool flag = statement_->synth_sync(des, scope(), clock, ce, aclr, aset, nex_set, nex_d, vector()); if (! flag) { @@ -942,12 +1700,13 @@ bool NetProcTop::synth_sync(Design*des) connect(tmp->pin(0), ff2->pin_Data()); connect(clock->pin(0), ff2->pin_Clock()); - connect(ce->pin(0), ff2->pin_Enable()); + if (ce.pin(idx).is_linked()) + connect(ce.pin(idx), ff2->pin_Enable()); + if (aclr.pin(idx).is_linked()) + connect(aclr.pin(idx), ff2->pin_Aclr()); + if (aset.pin(idx).is_linked()) + connect(aset.pin(idx), ff2->pin_Aset()); #if 0 - if (ff->pin_Aset().is_linked()) - connect(ff->pin_Aset(), ff2->pin_Aset()); - if (ff->pin_Aclr().is_linked()) - connect(ff->pin_Aclr(), ff2->pin_Aclr()); if (ff->pin_Sset().is_linked()) connect(ff->pin_Sset(), ff2->pin_Sset()); if (ff->pin_Sclr().is_linked()) @@ -959,7 +1718,9 @@ bool NetProcTop::synth_sync(Design*des) // back to the flip-flop. Delete them now. The connections // will persist. delete clock; +#if 0 delete ce; +#endif return true; } @@ -986,7 +1747,7 @@ void synth2_f::process(Design*des, NetProcTop*top) if (top->scope()->attribute(perm_string::literal("ivl_synthesis_cell")).len() > 0) return; - if (top->is_synchronous()) do { + if (top->is_synchronous()) { bool flag = top->synth_sync(des); if (! flag) { cerr << top->get_fileline() << ": error: " @@ -996,7 +1757,7 @@ void synth2_f::process(Design*des, NetProcTop*top) } des->delete_process(top); return; - } while (0); + } if (! top->is_asynchronous()) { bool synth_error_flag = false; diff --git a/t-dll-api.cc b/t-dll-api.cc index 4fcd623f8..31389cba5 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -84,7 +84,11 @@ extern "C" void ivl_design_roots(ivl_design_t des, ivl_scope_t **scopes, assert (nscopes && scopes); if (des->root_scope_list.size() == 0) { size_t fill = 0; - des->root_scope_list.resize(des->packages.size() + des->roots.size() + des->classes.size()); + des->root_scope_list.resize(des->root_tasks.size() + des->packages.size() + des->roots.size() + des->classes.size()); + for (map::iterator idx = des->root_tasks.begin() + ; idx != des->root_tasks.end() ; ++ idx) + des->root_scope_list[fill++] = idx->second; + for (map::iterator idx = des->classes.begin() ; idx != des->classes.end() ; ++ idx) des->root_scope_list[fill++] = idx->second; @@ -485,6 +489,9 @@ extern "C" ivl_expr_t ivl_expr_oper1(ivl_expr_t net) case IVL_EX_BINARY: return net->u_.binary_.lef_; + case IVL_EX_PROPERTY: + return net->u_.property_.index; + case IVL_EX_SELECT: return net->u_.select_.expr_; @@ -1075,6 +1082,8 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net) case IVL_LPM_PART_VP: case IVL_LPM_PART_PV: return net->u_.part.base; + case IVL_LPM_SUBSTITUTE: + return net->u_.substitute.base; default: assert(0); return 0; @@ -1164,6 +1173,8 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) case IVL_LPM_ADD: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: @@ -1227,6 +1238,13 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) assert(idx < (net->u_.sfunc.ports-1)); return net->u_.sfunc.pins[idx+1]; + case IVL_LPM_SUBSTITUTE: + assert(idx <= 1); + if (idx == 0) + return net->u_.substitute.a; + else + return net->u_.substitute.s; + case IVL_LPM_UFUNC: // Skip the return port. assert(idx < (net->u_.ufunc.ports-1)); @@ -1309,6 +1327,8 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net) case IVL_LPM_CMP_EQ: case IVL_LPM_CMP_NE: case IVL_LPM_CMP_EEQ: + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_NEE: case IVL_LPM_DIVIDE: case IVL_LPM_MOD: @@ -1353,6 +1373,9 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net) case IVL_LPM_REPEAT: return net->u_.repeat.q; + case IVL_LPM_SUBSTITUTE: + return net->u_.substitute.q; + case IVL_LPM_ARRAY: return net->u_.array.q; @@ -1447,6 +1470,8 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) case IVL_LPM_CAST_REAL: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: @@ -1482,6 +1507,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) case IVL_LPM_PART_PV: return net->u_.part.signed_flag; case IVL_LPM_REPEAT: + case IVL_LPM_SUBSTITUTE: return 0; case IVL_LPM_ARRAY: // Array ports take the signedness of the array. return net->u_.array.sig->net_type->get_signed()? 1 : 0; @@ -1521,6 +1547,8 @@ extern "C" unsigned ivl_lpm_size(ivl_lpm_t net) case IVL_LPM_ADD: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: @@ -1648,7 +1676,7 @@ extern "C" const char* ivl_nexus_name(ivl_nexus_t net) assert(net); if (net->name_ == 0) { char tmp[2 * sizeof(net) + 5]; - snprintf(tmp, sizeof tmp, "n%p", net); + snprintf(tmp, sizeof tmp, "n%p", (void *)net); net->name_ = api_strings.add(tmp); } return net->name_; diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 30c73122e..7ab761ea5 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -343,6 +343,38 @@ void dll_target::expr_creal(const NetECReal*net) expr_->u_.real_.value = net->value().as_double(); } +void dll_target::expr_last(const NetELast*net) +{ + assert(expr_ == 0); + ivl_expr_t expr = new struct ivl_expr_s; + expr->type_ = IVL_EX_SFUNC; + expr->value_ = IVL_VT_LOGIC; + expr->width_ = 32; + expr->signed_ = 1; + expr->sized_ = 1; + expr->net_type = 0; + FILE_NAME(expr, net); + + expr->u_.sfunc_.name_ = "$high"; + + ivl_signal_t sig = find_signal(des_, net->sig()); + + ivl_expr_t esig = new struct ivl_expr_s; + esig->type_ = IVL_EX_SIGNAL; + esig->value_ = IVL_VT_DARRAY; + esig->net_type= sig->net_type; + esig->width_ = 1; + FILE_NAME(esig, net); + esig->u_.signal_.word = 0; + esig->u_.signal_.sig = sig; + + expr->u_.sfunc_.parms = 1; + expr->u_.sfunc_.parm = new ivl_expr_t[1]; + expr->u_.sfunc_.parm[0] = esig; + + expr_ = expr; +} + void dll_target::expr_new(const NetENew*net) { ivl_expr_t size = 0; @@ -388,6 +420,12 @@ void dll_target::expr_null(const NetENull*net) void dll_target::expr_property(const NetEProperty*net) { + ivl_expr_t index = 0; + if (const NetExpr*index_expr = net->get_index()) { + index_expr->expr_scan(this); + index = expr_; + expr_ = 0; + } assert(expr_ == 0); expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_->width_ = net->expr_width(); @@ -399,6 +437,7 @@ void dll_target::expr_property(const NetEProperty*net) expr_->net_type= net->net_type(); expr_->u_.property_.sig = find_signal(des_, net->get_sig()); expr_->u_.property_.prop_idx = net->property_idx(); + expr_->u_.property_.index = index; } void dll_target::expr_event(const NetEEvent*net) @@ -619,6 +658,11 @@ void dll_target::expr_ufunc(const NetEUFunc*net) FILE_NAME(expr, net); expr->u_.ufunc_.def = lookup_scope_(net->func()); + if (expr->u_.ufunc_.def == 0) { + cerr << net->get_fileline() << ": internal error: " + << "dll_target::expr_ufunc: " + << "Unable to match scope " << scope_path(net->func()) << endl; + } ivl_assert(*net, expr->u_.ufunc_.def); ivl_assert(*net, expr->u_.ufunc_.def->type_ == IVL_SCT_FUNCTION); diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 87b49ed5c..e668919eb 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -80,6 +80,8 @@ void dll_target::task_def(const NetScope*net) ivl_scope_t scop = lookup_scope_(net); const NetTaskDef*def = net->task_def(); + assert(def); + assert(def->proc()); assert(stmt_cur_ == 0); stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_); def->proc()->emit_proc(this); @@ -102,6 +104,8 @@ bool dll_target::func_def(const NetScope*net) ivl_scope_t scop = lookup_scope_(net); const NetFuncDef*def = net->func_def(); + assert(def); + assert(def->proc()); assert(stmt_cur_ == 0); stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_); def->proc()->emit_proc(this); diff --git a/t-dll.cc b/t-dll.cc index d28d44c48..f9854e793 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -160,12 +160,21 @@ inline static const char *basename(ivl_scope_t scope, const char *inst) static perm_string make_scope_name(const hname_t&name) { - if (! name.has_number()) + if (! name.has_numbers()) return name.peek_name(); char buf[1024]; - snprintf(buf, sizeof buf, "%s[%d]", - name.peek_name().str(), name.peek_number()); + snprintf(buf, sizeof buf, "%s", name.peek_name().str()); + + char*cp = buf + strlen(buf); + size_t ncp = sizeof buf - (cp-buf); + + for (size_t idx = 0 ; idx < name.has_numbers() ; idx += 1) { + int len = snprintf(cp, ncp, "[%d]", name.peek_number(idx)); + cp += len; + ncp -= len; + } + return lex_strings.make(buf); } @@ -252,6 +261,12 @@ ivl_scope_t dll_target::find_scope(ivl_design_s &des, const NetScope*cur) return tmp; } + if (cur->type()==NetScope::TASK || cur->type()==NetScope::FUNC) { + map::const_iterator idx = des.root_tasks.find(cur); + if (idx != des.root_tasks.end()) + return idx->second; + } + for (unsigned idx = 0; idx < des.roots.size(); idx += 1) { assert(des.roots[idx]); ivl_scope_t scope = find_scope_from_root(des.roots[idx], cur); @@ -596,6 +611,13 @@ void dll_target::add_root(const NetScope *s) root_->lpm_ = 0; root_->def = 0; make_scope_parameters(root_, s); + root_->tname_ = root_->name_; + root_->time_precision = s->time_precision(); + root_->time_units = s->time_unit(); + root_->nattr = s->attr_cnt(); + root_->attr = fill_in_attributes(s); + root_->is_auto = 0; + root_->is_cell = s->is_cell(); switch (s->type()) { case NetScope::PACKAGE: root_->type_ = IVL_SCT_PACKAGE; @@ -606,16 +628,25 @@ void dll_target::add_root(const NetScope *s) case NetScope::CLASS: root_->type_ = IVL_SCT_CLASS; break; + case NetScope::TASK: { + const NetTaskDef*def = s->task_def(); + if (def == 0) { + cerr << "?:?" << ": internal error: " + << "task " << root_->name_ + << " has no definition." << endl; + } + assert(def); + root_->type_ = IVL_SCT_TASK; + root_->tname_ = def->scope()->basename(); + break; + } + break; + case NetScope::FUNC: + root_->type_ = IVL_SCT_FUNCTION; + break; default: assert(0); } - root_->tname_ = root_->name_; - root_->time_precision = s->time_precision(); - root_->time_units = s->time_unit(); - root_->nattr = s->attr_cnt(); - root_->attr = fill_in_attributes(s); - root_->is_auto = 0; - root_->is_cell = s->is_cell(); switch (s->type()) { case NetScope::MODULE: @@ -641,6 +672,11 @@ void dll_target::add_root(const NetScope *s) des_.classes[s] = root_; break; + case NetScope::TASK: + case NetScope::FUNC: + des_.root_tasks[s] = root_; + break; + default: assert(0); break; @@ -682,16 +718,22 @@ bool dll_target::start_design(const Design*des) } assert(idx == des_.disciplines.size()); - list package_scopes = des->find_package_scopes(); - for (list::const_iterator scop = package_scopes.begin() - ; scop != package_scopes.end(); ++ scop ) { - add_root(*scop); + list scope_list = des->find_roottask_scopes(); + for (list::const_iterator cur = scope_list.begin() + ; cur != scope_list.end() ; ++ cur) { + add_root(*cur); } - list root_scopes = des->find_root_scopes(); - for (list::const_iterator scop = root_scopes.begin() - ; scop != root_scopes.end(); ++ scop ) { - add_root(*scop); + scope_list = des->find_package_scopes(); + for (list::const_iterator cur = scope_list.begin() + ; cur != scope_list.end(); ++ cur ) { + add_root(*cur); + } + + scope_list = des->find_root_scopes(); + for (list::const_iterator cur = scope_list.begin() + ; cur != scope_list.end(); ++ cur ) { + add_root(*cur); } target_ = (target_design_f)ivl_dlsym(dll_, LU "target_design" TU); @@ -1091,6 +1133,32 @@ bool dll_target::tran(const NetTran*net) return true; } +bool dll_target::substitute(const NetSubstitute*net) +{ + ivl_lpm_t obj = new struct ivl_lpm_s; + obj->type = IVL_LPM_SUBSTITUTE; + obj->name = net->name(); + assert(net->scope()); + obj->scope = find_scope(des_, net->scope()); + assert(obj->scope); + FILE_NAME(obj, net); + + obj->width = net->width(); + obj->u_.substitute.base = net->base(); + + obj->u_.substitute.q = net->pin(0).nexus()->t_cookie(); + obj->u_.substitute.a = net->pin(1).nexus()->t_cookie(); + obj->u_.substitute.s = net->pin(2).nexus()->t_cookie(); + nexus_lpm_add(obj->u_.substitute.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG); + nexus_lpm_add(obj->u_.substitute.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + nexus_lpm_add(obj->u_.substitute.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); + + return true; +} + bool dll_target::sign_extend(const NetSignExtend*net) { struct ivl_lpm_s*obj = new struct ivl_lpm_s; @@ -1181,7 +1249,20 @@ bool dll_target::ureduce(const NetUReduce*net) void dll_target::net_case_cmp(const NetCaseCmp*net) { struct ivl_lpm_s*obj = new struct ivl_lpm_s; - obj->type = net->eeq()? IVL_LPM_CMP_EEQ : IVL_LPM_CMP_NEE; + switch (net->kind()) { + case NetCaseCmp::EEQ: + obj->type = IVL_LPM_CMP_EEQ; + break; + case NetCaseCmp::NEQ: + obj->type = IVL_LPM_CMP_NEE; + break; + case NetCaseCmp::XEQ: + obj->type = IVL_LPM_CMP_EQX; + break; + case NetCaseCmp::ZEQ: + obj->type = IVL_LPM_CMP_EQZ; + break; + } obj->name = net->name(); obj->scope = find_scope(des_, net->scope()); assert(obj->scope); @@ -2031,6 +2112,13 @@ void dll_target::lpm_mux(const NetMux*net) nex = net->pin_Data(sdx).nexus(); ivl_nexus_t tmp = nex->t_cookie(); obj->u_.mux.d[sdx] = tmp; + if (tmp == 0) { + cerr << net->get_fileline() << ": internal error: " + << "dll_target::lpm_mux: " + << "Missing data port " << sdx + << " of mux " << obj->name << "." << endl; + } + ivl_assert(*net, tmp); nexus_lpm_add(tmp, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); } @@ -2356,6 +2444,11 @@ void dll_target::scope(const NetScope*net) { if (net->parent()==0 && net->type()==NetScope::CLASS) { + if (debug_emit) { + cerr << "dll_target::scope: " + << "Add class " << scope_path(net) + << " as a root scope." << endl; + } add_root(net); } if (net->parent() == 0) { diff --git a/t-dll.h b/t-dll.h index f357ab384..918a95bde 100644 --- a/t-dll.h +++ b/t-dll.h @@ -1,7 +1,7 @@ -#ifndef __t_dll_H -#define __t_dll_H +#ifndef IVL_t_dll_H +#define IVL_t_dll_H /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -90,6 +90,7 @@ struct dll_target : public target_t, public expr_scan_t { bool net_literal(const NetLiteral*); void net_probe(const NetEvProbe*); bool sign_extend(const NetSignExtend*); + bool substitute(const NetSubstitute*); bool process(const NetProcTop*); bool process(const NetAnalogTop*); @@ -140,6 +141,7 @@ 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_last(const NetELast*); void expr_new(const NetENew*); void expr_null(const NetENull*); void expr_param(const NetEConstParam*); @@ -344,6 +346,7 @@ struct ivl_expr_s { struct { ivl_signal_t sig; unsigned prop_idx; + ivl_expr_t index; } property_; } u_; }; @@ -437,6 +440,11 @@ struct ivl_lpm_s { ivl_event_t trigger; } sfunc; + struct ivl_lpm_substitute { + unsigned base; + ivl_nexus_t q, a, s; + } substitute; + struct ivl_lpm_ufunc_s { ivl_scope_t def; unsigned ports; @@ -476,7 +484,7 @@ struct ivl_lval_s { * structural context. */ struct ivl_net_const_s { - ivl_variable_type_t type : 3; + ivl_variable_type_t type : 4; unsigned width_ : 24; unsigned signed_ : 1; perm_string file; @@ -625,7 +633,7 @@ struct ivl_parameter_s { */ struct ivl_process_s { ivl_process_type_t type_ : 2; - int analog_flag : 1; + unsigned int analog_flag : 1; ivl_scope_t scope_; ivl_statement_t stmt_; perm_string file; @@ -923,4 +931,4 @@ static inline void FILE_NAME(ivl_signal_t net, const LineInfo*info) net->lineno = info->get_lineno(); } -#endif +#endif /* IVL_t_dll_H */ diff --git a/target.cc b/target.cc index bb5bfb8c1..a4fe8b44a 100644 --- a/target.cc +++ b/target.cc @@ -270,6 +270,13 @@ bool target_t::sign_extend(const NetSignExtend*) return false; } +bool target_t::substitute(const NetSubstitute*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetSubstitute node." << endl; + return false; +} + bool target_t::process(const NetProcTop*) { cerr << "target (" << typeid(*this).name() << "): " @@ -464,6 +471,12 @@ void expr_scan_t::expr_const(const NetEConst*) "unhandled expr_const." << endl; } +void expr_scan_t::expr_last(const NetELast*exp) +{ + cerr << exp->get_fileline() << ": expr_scan_t(" << typeid(*this).name() << "): " + << "unhandled expr_last." << endl; +} + void expr_scan_t::expr_new(const NetENew*) { cerr << "expr_scan_t (" << typeid(*this).name() << "): " diff --git a/target.h b/target.h index cf87bea9d..ec834418d 100644 --- a/target.h +++ b/target.h @@ -1,7 +1,7 @@ -#ifndef __target_H -#define __target_H +#ifndef IVL_target_H +#define IVL_target_H /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -116,6 +116,7 @@ struct target_t { virtual bool net_literal(const NetLiteral*); virtual void net_probe(const NetEvProbe*); virtual bool sign_extend(const NetSignExtend*); + virtual bool substitute(const NetSubstitute*); /* Output a process (called for each process). It is up to the target to recurse if desired. */ @@ -158,6 +159,7 @@ struct expr_scan_t { virtual void expr_access_func(const NetEAccess*); virtual void expr_array_pattern(const NetEArrayPattern*); virtual void expr_const(const NetEConst*); + virtual void expr_last(const NetELast*); virtual void expr_new(const NetENew*); virtual void expr_null(const NetENull*); virtual void expr_param(const NetEConstParam*); @@ -188,4 +190,4 @@ extern string mangle(const string&str); used inside a string constant for a C++ compiler. */ extern string stresc(const string&str); -#endif +#endif /* IVL_target_H */ diff --git a/tgt-blif/Makefile.in b/tgt-blif/Makefile.in index 1c63c8776..88a984b04 100644 --- a/tgt-blif/Makefile.in +++ b/tgt-blif/Makefile.in @@ -57,7 +57,8 @@ distclean: clean rm -f Makefile config.log cppcheck: $(O:.o=.cc) - cppcheck --enable=all -f $(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=tgt-blif/$@ diff --git a/tgt-blif/README-BLIF.txt b/tgt-blif/README-BLIF.txt index ce337de06..b65fb955f 100644 --- a/tgt-blif/README-BLIF.txt +++ b/tgt-blif/README-BLIF.txt @@ -21,7 +21,7 @@ code. To convert a design to blif, use this command: iverilog -tblif -o.blif ... -The source files can be Verilog, System Verilog, VHDL, whatever Icarus +The source files can be Verilog, SystemVerilog, VHDL, whatever Icarus Verilog supports, so long as it elaborates down to the limited subset that the code generator supports. In other words, the files must be structural. diff --git a/tgt-blif/cppcheck.sup b/tgt-blif/cppcheck.sup new file mode 100644 index 000000000..94e263a9f --- /dev/null +++ b/tgt-blif/cppcheck.sup @@ -0,0 +1,8 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:blif.cc:66 + +// target_query() +unusedFunction:blif.cc:98 diff --git a/tgt-blif/nex_data.h b/tgt-blif/nex_data.h index 04b6445b9..0614e28de 100644 --- a/tgt-blif/nex_data.h +++ b/tgt-blif/nex_data.h @@ -1,7 +1,7 @@ -#ifndef __nex_data_H -#define __nex_data_H +#ifndef IVL_nex_data_H +#define IVL_nex_data_H /* - * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2013-2014 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 @@ -72,4 +72,4 @@ class blif_nex_data_t { void make_name_from_sig_(ivl_signal_t sig); }; -#endif +#endif /* IVL_nex_data_H */ diff --git a/tgt-blif/priv.h b/tgt-blif/priv.h index db83c0e99..3bd6a1f02 100644 --- a/tgt-blif/priv.h +++ b/tgt-blif/priv.h @@ -1,7 +1,7 @@ -#ifndef __priv_H -#define __priv_H +#ifndef IVL_priv_H +#define IVL_priv_H /* - * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2013-2014 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 @@ -55,4 +55,4 @@ extern void emit_constants(FILE*fd, ivl_design_t des, ivl_scope_t model); */ extern bool scope_is_in_model(ivl_scope_t model, ivl_scope_t scope); -#endif +#endif /* IVL_priv_H */ diff --git a/tgt-fpga/Makefile.in b/tgt-fpga/Makefile.in index cee67286b..72546b5a6 100644 --- a/tgt-fpga/Makefile.in +++ b/tgt-fpga/Makefile.in @@ -44,7 +44,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ D = d-generic.o d-generic-edif.o d-lpm.o d-virtex.o d-virtex2.o @@ -61,7 +61,8 @@ distclean: clean rm -f Makefile config.log cppcheck: $(O:.o=.c) - cppcheck --enable=all -f $(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=tgt-fpga/$@ diff --git a/tgt-fpga/cppcheck.sup b/tgt-fpga/cppcheck.sup new file mode 100644 index 000000000..18c1c0abc --- /dev/null +++ b/tgt-fpga/cppcheck.sup @@ -0,0 +1,5 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:fpga.c:104 diff --git a/tgt-fpga/d-generic-edif.c b/tgt-fpga/d-generic-edif.c index cfa0b3af0..247f23a8c 100644 --- a/tgt-fpga/d-generic-edif.c +++ b/tgt-fpga/d-generic-edif.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -378,30 +378,29 @@ static void edif_show_logic(ivl_net_logic_t net) break; default: - fprintf(stderr, "UNSUPPORT LOGIC TYPE: %u\n", ivl_logic_type(net)); + fprintf(stderr, "UNSUPPORT LOGIC TYPE: %d\n", ivl_logic_type(net)); } } static void edif_show_generic_dff(ivl_lpm_t net) { - ivl_nexus_t nex; char jbuf[1024]; unsigned idx; ivl_nexus_t aclr = ivl_lpm_async_clr(net); ivl_nexus_t aset = ivl_lpm_async_set(net); - ivl_expr_t avalue = 0; const char*abits = 0; const char*fdcell = "FDCE"; if (aset != 0) { + ivl_expr_t avalue = ivl_lpm_aset_value(net); fdcell = "FDCPE"; - avalue = ivl_lpm_aset_value(net); assert(avalue); abits = ivl_expr_bits(avalue); assert(abits); } for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { + ivl_nexus_t nex; edif_uref += 1; diff --git a/tgt-fpga/d-generic.c b/tgt-fpga/d-generic.c index e75f568ff..92c969293 100644 --- a/tgt-fpga/d-generic.c +++ b/tgt-fpga/d-generic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -246,7 +246,7 @@ static void generic_show_logic(ivl_net_logic_t net) break; default: - fprintf(stderr, "fpga.tgt: unknown logic type %u\n", + fprintf(stderr, "fpga.tgt: unknown logic type %d\n", ivl_logic_type(net)); break; } @@ -358,7 +358,7 @@ static void generic_show_cmp_eq(ivl_lpm_t net) static void generic_show_mux(ivl_lpm_t net) { char name[1024]; - ivl_nexus_t nex, sel; + ivl_nexus_t sel; unsigned idx; xnf_mangle_lpm_name(net, name, sizeof name); @@ -369,6 +369,8 @@ static void generic_show_mux(ivl_lpm_t net) sel = ivl_lpm_select(net, 0); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { + ivl_nexus_t nex; + fprintf(xnf, "SYM, %s/M%u, EQN, " "EQN=((I0 * ~I2) + (I1 * I2))\n", name, idx); diff --git a/tgt-fpga/d-lpm.c b/tgt-fpga/d-lpm.c index 8d95aa547..6f7b84e60 100644 --- a/tgt-fpga/d-lpm.c +++ b/tgt-fpga/d-lpm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 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 @@ -396,7 +396,7 @@ static void lpm_logic(ivl_net_logic_t net) break; default: - fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n", + fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %d\n", ivl_logic_type(net)); break; } @@ -735,7 +735,6 @@ static void lpm_show_mult(ivl_lpm_t net) edif_cell_t cell; edif_cellref_t ref; - edif_joint_t jnt; sprintf(name, "mult%u", ivl_lpm_width(net)); cell = edif_xlibrary_findcell(xlib, name); @@ -773,6 +772,7 @@ static void lpm_show_mult(ivl_lpm_t net) for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { unsigned pin; ivl_nexus_t nex; + edif_joint_t jnt; sprintf(name, "Result%u", idx); pin = edif_cell_port_byname(cell, name); diff --git a/tgt-fpga/device.h b/tgt-fpga/device.h index 78e842599..03cb08b1b 100644 --- a/tgt-fpga/device.h +++ b/tgt-fpga/device.h @@ -1,7 +1,7 @@ -#ifndef __device_H -#define __device_H +#ifndef IVL_device_H +#define IVL_device_H /* - * Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -74,4 +74,4 @@ struct device_s { */ extern device_t device_from_arch(const char*arch); -#endif +#endif /* IVL_device_H */ diff --git a/tgt-fpga/edif.h b/tgt-fpga/edif.h index 38d54fe70..5d7144b92 100644 --- a/tgt-fpga/edif.h +++ b/tgt-fpga/edif.h @@ -1,7 +1,7 @@ -#ifndef __edif_H -#define __edif_H +#ifndef IVL_edif_H +#define IVL_edif_H /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 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 @@ -226,4 +226,4 @@ extern void edif_add_to_joint(edif_joint_t jnt, */ extern void edif_print(FILE*fd, edif_t design); -#endif +#endif /* IVL_edif_H */ diff --git a/tgt-fpga/fpga.c b/tgt-fpga/fpga.c index 116d381a4..95c9fc65b 100644 --- a/tgt-fpga/fpga.c +++ b/tgt-fpga/fpga.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -39,11 +39,10 @@ device_t device = 0; int scope_has_attribute(ivl_scope_t s, const char *name) { int i; - const struct ivl_attribute_s *a; for (i=0; ikey,name) == 0) - return 1; + const struct ivl_attribute_s *a; + a = ivl_scope_attr_val(s, i); + if (strcmp(a->key,name) == 0) return 1; } return 0; } diff --git a/tgt-fpga/fpga_priv.h b/tgt-fpga/fpga_priv.h index 8c1b60f24..f9b29c3de 100644 --- a/tgt-fpga/fpga_priv.h +++ b/tgt-fpga/fpga_priv.h @@ -1,7 +1,7 @@ -#ifndef __fpga_priv_H -#define __fpga_priv_H +#ifndef IVL_fpga_priv_H +#define IVL_fpga_priv_H /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -47,4 +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 +#endif /* IVL_fpga_priv_H */ diff --git a/tgt-fpga/gates.c b/tgt-fpga/gates.c index aca09ec78..b443e11e2 100644 --- a/tgt-fpga/gates.c +++ b/tgt-fpga/gates.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -148,7 +148,7 @@ static void show_gate_lpm(ivl_lpm_t net) break; default: - fprintf(stderr, "fpga.tgt: unknown LPM type %u\n", + fprintf(stderr, "fpga.tgt: unknown LPM type %d\n", ivl_lpm_type(net)); break; } diff --git a/tgt-fpga/generic.h b/tgt-fpga/generic.h index e81633438..42807bdc6 100644 --- a/tgt-fpga/generic.h +++ b/tgt-fpga/generic.h @@ -1,7 +1,7 @@ -#ifndef __generic_H -#define __generic_H +#ifndef IVL_generic_H +#define IVL_generic_H /* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 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 @@ -39,4 +39,4 @@ extern edif_cell_t cell_ipad; extern edif_cell_t cell_opad; extern edif_cell_t cell_iopad; -#endif +#endif /* IVL_generic_H */ diff --git a/tgt-fpga/xilinx.c b/tgt-fpga/xilinx.c index eb5390e63..eb1ad7738 100644 --- a/tgt-fpga/xilinx.c +++ b/tgt-fpga/xilinx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012 Stephen Williams (steve at icarus.com) + * Copyright (c) 2003-2014 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 @@ -505,8 +505,7 @@ static void edif_cellref_logic(ivl_net_logic_t net, const char*def) char*pins; edif_cell_t cell; edif_cellref_t ref; - edif_joint_t jnt; - unsigned idx, port; + unsigned idx; pins = strchr(str, ':'); assert(pins); @@ -520,6 +519,8 @@ static void edif_cellref_logic(ivl_net_logic_t net, const char*def) for (idx = 0 ; idx < ivl_logic_pins(net) ; idx += 1) { char*tmp; + edif_joint_t jnt; + unsigned port; assert(pins); tmp = strchr(pins,','); @@ -693,7 +694,7 @@ void xilinx_logic(ivl_net_logic_t net) break; default: - fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n", + fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %d\n", ivl_logic_type(net)); break; } @@ -707,9 +708,6 @@ void xilinx_mux(ivl_lpm_t net) { unsigned idx; - edif_cellref_t lut; - edif_joint_t jnt; - assert(ivl_lpm_selects(net) == 1); /* A/B Mux devices are made from LUT3 devices. I0 is connected @@ -730,6 +728,8 @@ void xilinx_mux(ivl_lpm_t net) INIT = "CA" */ for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { + edif_cellref_t lut; + edif_joint_t jnt; lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib)); @@ -756,8 +756,6 @@ void xilinx_mux(ivl_lpm_t net) void xilinx_add(ivl_lpm_t net) { const char*ha_init = 0; - edif_cellref_t lut; - edif_joint_t jnt; switch (ivl_lpm_type(net)) { case IVL_LPM_ADD: @@ -774,6 +772,8 @@ void xilinx_add(ivl_lpm_t net) half-adder. Normally this is an XOR, but if this is a SUB then it is an XNOR. */ if (ivl_lpm_width(net) == 1) { + edif_cellref_t lut; + edif_joint_t jnt; lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); @@ -801,7 +801,7 @@ void xilinx_add(ivl_lpm_t net) void xilinx_shiftl(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); - unsigned nsel = 0, swid = 0; + unsigned nsel = 0; unsigned sdx, qdx; edif_cellref_t* cells; @@ -818,6 +818,7 @@ void xilinx_shiftl(ivl_lpm_t net) emits zeros. */ while (nsel < ivl_lpm_selects(net)) { + unsigned swid; nsel += 1; diff --git a/tgt-fpga/xilinx.h b/tgt-fpga/xilinx.h index 3789c561d..b3b0ae7ac 100644 --- a/tgt-fpga/xilinx.h +++ b/tgt-fpga/xilinx.h @@ -1,7 +1,7 @@ -#ifndef __xilinx_H -#define __xilinx_H +#ifndef IVL_xilinx_H +#define IVL_xilinx_H /* - * Copyright (c) 2003 Stephen Williams (steve at icarus.com) + * Copyright (c) 2003-2014 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 @@ -125,4 +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); -#endif +#endif /* IVL_xilinx_H */ diff --git a/tgt-null/Makefile.in b/tgt-null/Makefile.in index 1de125ccd..c414f2fbe 100644 --- a/tgt-null/Makefile.in +++ b/tgt-null/Makefile.in @@ -40,7 +40,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = null.o @@ -56,7 +56,8 @@ distclean: clean rm -f Makefile config.log cppcheck: $(O:.o=.c) - cppcheck --enable=all -f $(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=tgt-null/$@ diff --git a/tgt-null/cppcheck.sup b/tgt-null/cppcheck.sup new file mode 100644 index 000000000..4d17f7a66 --- /dev/null +++ b/tgt-null/cppcheck.sup @@ -0,0 +1,8 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:null.c:50 + +// target_query() +unusedFunction:null.c:57 diff --git a/tgt-null/null.c b/tgt-null/null.c index 35f2869ca..184fba111 100644 --- a/tgt-null/null.c +++ b/tgt-null/null.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -30,7 +30,7 @@ static const char*version_string = "Icarus Verilog NULL Code Generator " VERSION " (" VERSION_TAG ")\n\n" -"Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com)\n\n" +"Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)\n\n" " This program is free software; you can redistribute it and/or modify\n" " it under the terms of the GNU General Public License as published by\n" " the Free Software Foundation; either version 2 of the License, or\n" @@ -49,6 +49,7 @@ static const char*version_string = int target_design(ivl_design_t des) { + (void)des; /* Parameter is not used. */ return 0; } diff --git a/tgt-pal/Makefile.in b/tgt-pal/Makefile.in index b880cba02..291acac9d 100644 --- a/tgt-pal/Makefile.in +++ b/tgt-pal/Makefile.in @@ -39,7 +39,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = imain.o dump_final.o emit_jed.o enables.o fit_log.o fit_reg.o pads.o @@ -55,7 +55,8 @@ distclean: clean rm -f Makefile config.log cppcheck: $(O:.o=.c) - cppcheck --enable=all -f $(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=tgt-pal/$@ diff --git a/tgt-pal/cppcheck.sup b/tgt-pal/cppcheck.sup new file mode 100644 index 000000000..7d4b20042 --- /dev/null +++ b/tgt-pal/cppcheck.sup @@ -0,0 +1,5 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:imain.c:59 diff --git a/tgt-pal/priv.h b/tgt-pal/priv.h index d0dbc5846..adcb8f6a2 100644 --- a/tgt-pal/priv.h +++ b/tgt-pal/priv.h @@ -1,7 +1,7 @@ -#ifndef __priv_H -#define __priv_H +#ifndef IVL_priv_H +#define IVL_priv_H /* - * Copyright (c) 2000 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -97,4 +97,4 @@ extern int fit_logic(void); extern int emit_jedec(const char*path); -#endif +#endif /* IVL_priv_H */ diff --git a/tgt-pcb/Makefile.in b/tgt-pcb/Makefile.in index abf46cf93..dd73e27ea 100644 --- a/tgt-pcb/Makefile.in +++ b/tgt-pcb/Makefile.in @@ -61,7 +61,11 @@ distclean: clean rm -f stamp-pcb_config-h pcb_config.h cppcheck: $(O:.o=.cc) - cppcheck --enable=all -f $(INCLUDE_PATH) $^ + cppcheck --enable=all -f --suppressions-list=$(srcdir)/cppcheck.sup \ + -UYY_USER_INIT \ + -UYYPARSE_PARAM -UYYPRINT -Ushort -Usize_t -Uyyoverflow \ + -UYYTYPE_INT8 -UYYTYPE_INT16 -UYYTYPE_UINT8 -UYYTYPE_UINT16 \ + --relative-paths=$(srcdir) $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in ../config.status cd ..; ./config.status --file=tgt-pcb/$@ diff --git a/tgt-pcb/cppcheck.sup b/tgt-pcb/cppcheck.sup new file mode 100644 index 000000000..d0bfcfe5b --- /dev/null +++ b/tgt-pcb/cppcheck.sup @@ -0,0 +1,8 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:pcb.cc:52 + +// target_query() +unusedFunction:pcb.cc:84 diff --git a/tgt-pcb/fp_api.h b/tgt-pcb/fp_api.h index eadbf46d4..4e6084183 100644 --- a/tgt-pcb/fp_api.h +++ b/tgt-pcb/fp_api.h @@ -1,7 +1,7 @@ -#ifndef __fp_api_H -#define __fp_api_H +#ifndef IVL_fp_api_H +#define IVL_fp_api_H /* - * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 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 @@ -63,4 +63,4 @@ extern void callback_fp_element(const struct fp_element_t&); //extern int parse_errors; extern int parse_fp_sorrys; -#endif +#endif /* IVL_fp_api_H */ diff --git a/tgt-pcb/pcb_config.h.in b/tgt-pcb/pcb_config.h.in index 806c281ba..8dc3f40d7 100644 --- a/tgt-pcb/pcb_config.h.in +++ b/tgt-pcb/pcb_config.h.in @@ -1,7 +1,7 @@ -#ifndef __pcb_config_H -#define __pcb_config_H +#ifndef IVL_pcb_config_H +#define IVL_pcb_config_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,4 +25,4 @@ # undef _LARGEFILE_SOURCE # undef _LARGEFILE64_SOURCE -#endif /* __pcb_config_H */ +#endif /* IVL_pcb_config_H */ diff --git a/tgt-pcb/pcb_priv.h b/tgt-pcb/pcb_priv.h index 2e85a4945..257d05644 100644 --- a/tgt-pcb/pcb_priv.h +++ b/tgt-pcb/pcb_priv.h @@ -1,7 +1,7 @@ -#ifndef __pcb_priv_H -#define __pcb_priv_H +#ifndef IVL_pcb_priv_H +#define IVL_pcb_priv_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -86,4 +86,4 @@ extern void show_netlist(const char*net_path); extern void show_pcb(const char*pcb_path); -#endif +#endif /* IVL_pcb_priv_H */ diff --git a/tgt-sizer/Makefile.in b/tgt-sizer/Makefile.in index ad771a714..dad317786 100644 --- a/tgt-sizer/Makefile.in +++ b/tgt-sizer/Makefile.in @@ -56,7 +56,8 @@ distclean: clean rm -f Makefile config.log cppcheck: $(O:.o=.cc) - cppcheck --enable=all -f $(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=tgt-sizer/$@ diff --git a/tgt-sizer/cppcheck.sup b/tgt-sizer/cppcheck.sup new file mode 100644 index 000000000..f0672ed5c --- /dev/null +++ b/tgt-sizer/cppcheck.sup @@ -0,0 +1,8 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:sizer.cc:76 + +// target_query() +unusedFunction:sizer.cc:65 diff --git a/tgt-sizer/scan_logs.cc b/tgt-sizer/scan_logs.cc index 82a4df0d9..0269543ad 100644 --- a/tgt-sizer/scan_logs.cc +++ b/tgt-sizer/scan_logs.cc @@ -32,6 +32,11 @@ void scan_logs(ivl_scope_t scope, struct sizer_statistics&stats) for (unsigned idx = 0 ; idx < ivl_scope_logs(scope) ; idx += 1) { ivl_net_logic_t log = ivl_scope_log(scope, idx); switch (ivl_logic_type(log)) { + // These logic gate types don't really exist in a + // mapped design. + case IVL_LO_BUFZ: + break; + case IVL_LO_AND: case IVL_LO_OR: case IVL_LO_XOR: diff --git a/tgt-sizer/scan_lpms.cc b/tgt-sizer/scan_lpms.cc index 6298d1275..a5164f594 100644 --- a/tgt-sizer/scan_lpms.cc +++ b/tgt-sizer/scan_lpms.cc @@ -37,7 +37,7 @@ static void scan_lpms_ff(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&sta * Count adders as 2m gates. * Also keep a count of adders by width, just out of curiosity. */ -static void scans_lpms_add(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats) +static void scan_lpms_add(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats) { unsigned wid = ivl_lpm_width(lpm); @@ -46,8 +46,44 @@ static void scans_lpms_add(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&s stats.gate_count += 2*wid; } +/* + * Count equality comparator as 2m gates. + * Also keep a count of comparators by width, just out of curiosity. + */ +static void scan_lpms_equality(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats) +{ + unsigned wid = ivl_lpm_width(lpm); + + stats.equality_count[wid] += 1; + + stats.gate_count += 2*wid; +} + +static void scan_lpms_equality_wild(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats) +{ + unsigned wid = ivl_lpm_width(lpm); + + stats.equality_wc_count[wid] += 1; + + stats.gate_count += 2*wid; +} + +/* + * Count magnitude comparators as 2m gates. + * Also keep a count of comparators by width, just out of curiosity. + */ +static void scan_lpms_magnitude(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats) +{ + unsigned wid = ivl_lpm_width(lpm); + + stats.magnitude_count[wid] += 1; + + stats.gate_count += 2*wid; +} + /* * Count mux devices as 2m gates. + * Also count the mux slices of various select sizes. */ static void scan_lpms_mux(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats) { @@ -57,10 +93,25 @@ static void scan_lpms_mux(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&st return; } + // The "width" of a mux is the number of 1-bit slices. unsigned wid = ivl_lpm_width(lpm); + + // Count the slices of the various width of muxes. + stats.mux_count[2] += wid; + stats.gate_count += 2*wid; } +/* + * Count reduction gates (wide input gates) as 1m gates. + */ +static void scan_lpms_reduction(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats) +{ + unsigned wid = ivl_lpm_width(lpm); + + stats.gate_count += wid; +} + void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats) { for (unsigned idx = 0 ; idx < ivl_scope_lpms(scope) ; idx += 1) { @@ -74,10 +125,28 @@ void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats) case IVL_LPM_CONCAT: case IVL_LPM_CONCATZ: case IVL_LPM_REPEAT: + case IVL_LPM_SUBSTITUTE: break; case IVL_LPM_ADD: - scans_lpms_add(scope, lpm, stats); + scan_lpms_add(scope, lpm, stats); + break; + + case IVL_LPM_CMP_EQ: + case IVL_LPM_CMP_NE: + case IVL_LPM_CMP_EEQ: + case IVL_LPM_CMP_NEE: + scan_lpms_equality(scope, lpm, stats); + break; + + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: + scan_lpms_equality_wild(scope, lpm, stats); + break; + + case IVL_LPM_CMP_GE: + case IVL_LPM_CMP_GT: + scan_lpms_magnitude(scope, lpm, stats); break; // D-Type flip-flops. @@ -89,6 +158,15 @@ void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats) scan_lpms_mux(scope, lpm, stats); break; + case IVL_LPM_RE_AND: + case IVL_LPM_RE_NAND: + case IVL_LPM_RE_OR: + case IVL_LPM_RE_NOR: + case IVL_LPM_RE_XOR: + case IVL_LPM_RE_XNOR: + scan_lpms_reduction(scope, lpm, stats); + break; + default: stats.lpm_bytype[ivl_lpm_type(lpm)] += 1; break; diff --git a/tgt-sizer/sizer.cc b/tgt-sizer/sizer.cc index 2c985dd3a..000496496 100644 --- a/tgt-sizer/sizer.cc +++ b/tgt-sizer/sizer.cc @@ -156,7 +156,27 @@ static void show_stats(struct sizer_statistics&stats) for (map::const_iterator cur = stats.adder_count.begin() ; cur != stats.adder_count.end() ; ++ cur) { - fprintf(sizer_out, " ADDER[%u]: %u\n", cur->first, cur->second); + fprintf(sizer_out, " ADDER[%u]: %u units\n", cur->first, cur->second); + } + + for (map::const_iterator cur = stats.equality_count.begin() + ; cur != stats.equality_count.end() ; ++ cur) { + fprintf(sizer_out, " EQUALITY[%u]: %u units\n", cur->first, cur->second); + } + + for (map::const_iterator cur = stats.equality_wc_count.begin() + ; cur != stats.equality_wc_count.end() ; ++ cur) { + fprintf(sizer_out, " EQUALITY_WC[%u]: %u units\n", cur->first, cur->second); + } + + for (map::const_iterator cur = stats.magnitude_count.begin() + ; cur != stats.magnitude_count.end() ; ++ cur) { + fprintf(sizer_out, " MAGNITUDE[%u]: %u units\n", cur->first, cur->second); + } + + for (map::const_iterator cur = stats.mux_count.begin() + ; cur != stats.mux_count.end() ; ++ cur) { + fprintf(sizer_out, " MUX[%u]: %u slices\n", cur->first, cur->second); } // These are diagnostic outputs for when more detail is needed. @@ -173,11 +193,9 @@ static void show_stats(struct sizer_statistics&stats) unsigned get_nexus_width(ivl_nexus_t nex) { - ivl_signal_t sig = 0; - for (unsigned idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) { ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx); - sig = ivl_nexus_ptr_sig(ptr); + ivl_signal_t sig = ivl_nexus_ptr_sig(ptr); if (sig) return ivl_signal_width(sig); } @@ -195,6 +213,23 @@ struct sizer_statistics& sizer_statistics::operator += (const sizer_statistics&t ; cur != that.adder_count.end() ; ++ cur) adder_count[cur->first] += cur->second; + for (map::const_iterator cur = that.equality_count.begin() + ; cur != that.equality_count.end() ; ++ cur) + equality_count[cur->first] += cur->second; + + for (map::const_iterator cur = that.equality_wc_count.begin() + ; cur != that.equality_wc_count.end() ; ++ cur) + equality_wc_count[cur->first] += cur->second; + + for (map::const_iterator cur = that.magnitude_count.begin() + ; cur != that.magnitude_count.end() ; ++ cur) + magnitude_count[cur->first] += cur->second; + + + for (map::const_iterator cur = that.mux_count.begin() + ; cur != that.mux_count.end() ; ++ cur) + mux_count[cur->first] += cur->second; + for (map::const_iterator cur = that.lpm_bytype.begin() ; cur != that.lpm_bytype.end() ; ++ cur) diff --git a/tgt-sizer/sizer_priv.h b/tgt-sizer/sizer_priv.h index 3732e3174..0ce3003ec 100644 --- a/tgt-sizer/sizer_priv.h +++ b/tgt-sizer/sizer_priv.h @@ -1,5 +1,5 @@ -#ifndef __sizer_priv_H -#define __sizer_priv_H +#ifndef IVL_sizer_priv_H +#define IVL_sizer_priv_H /* * Copyright (c) 2014 Stephen Williams (steve@icarus.com) * @@ -31,6 +31,14 @@ struct sizer_statistics { unsigned gate_count; // Count adders of various dimension std::map adder_count; + // count equality comparators + std::map equality_count; + // count equality (with wildcard) comparators + std::map equality_wc_count; + // Count magnitude comparators + std::map magnitude_count; + // Count mux's of various dimension + std::map mux_count; // Different kinds of nodes that we have not accounted for std::map lpm_bytype; std::map log_bytype; @@ -53,4 +61,4 @@ extern void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats); extern unsigned get_nexus_width(ivl_nexus_t nex); -#endif +#endif /* IVL_sizer_priv_H */ diff --git a/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index b294d3000..c136ca37c 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -41,7 +41,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = stub.o classes.o constant.o enumerate.o expression.o statement.o switches.o types.o @@ -57,7 +57,8 @@ distclean: clean rm -f Makefile config.log cppcheck: $(O:.o=.c) - cppcheck --enable=all -f $(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=tgt-stub/$@ diff --git a/tgt-stub/classes.c b/tgt-stub/classes.c index 9b4f67db4..b6dcca0c7 100644 --- a/tgt-stub/classes.c +++ b/tgt-stub/classes.c @@ -23,10 +23,8 @@ 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) { + for (int 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/cppcheck.sup b/tgt-stub/cppcheck.sup new file mode 100644 index 000000000..fe27db5e7 --- /dev/null +++ b/tgt-stub/cppcheck.sup @@ -0,0 +1,8 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:stub.c:1770 + +// target_query() +unusedFunction:stub.c:1834 diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index e80857e31..cd133baf7 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -231,7 +231,8 @@ 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); - char*signed_flag = ivl_expr_signed(net)? "signed" : "unsigned"; + const char*signed_flag = ivl_expr_signed(net)? "signed" : "unsigned"; + ivl_expr_t index; if (ivl_expr_value(net) == IVL_VT_REAL) { fprintf(out, "%*s\n", ind, "", @@ -243,6 +244,9 @@ static void show_property_expression(ivl_expr_t net, unsigned ind) fprintf(out, "%*s\n", ind, "", ivl_signal_basename(sig), pnam, ivl_expr_width(net), signed_flag); } + if ( (index=ivl_expr_oper1(net)) ) { + show_expression(index, ind+3); + } 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))); @@ -386,7 +390,7 @@ static void show_ternary_expression(ivl_expr_t net, unsigned ind) } } -void show_unary_expression(ivl_expr_t net, unsigned ind) +static void show_unary_expression(ivl_expr_t net, unsigned ind) { unsigned width = ivl_expr_width(net); const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; diff --git a/tgt-stub/priv.h b/tgt-stub/priv.h index 38fb5c08a..3d487590e 100644 --- a/tgt-stub/priv.h +++ b/tgt-stub/priv.h @@ -1,5 +1,7 @@ +#ifndef IVL_priv_H +#define IVL_priv_H /* - * Copyright (c) 2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2014 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 @@ -77,3 +79,4 @@ 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); +#endif /* IVL_priv_H */ diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 0d95f771a..4eb8037a2 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -73,6 +73,12 @@ static unsigned show_assign_lval_class(ivl_lval_t lval, unsigned ind) fprintf(out, "%*s{name=%s. l-value width=%u}\n", ind, "", ivl_signal_name(sig), sig_prop, ivl_lval_width(lval)); + if (ivl_lval_idx(lval)) { + ivl_expr_t mux = ivl_lval_idx(lval); + fprintf(out, "%*sAddress-0 select expression:\n", ind+4, ""); + show_expression(mux, ind+6); + } + return ivl_lval_width(lval); } @@ -269,7 +275,7 @@ static void show_stmt_trigger(ivl_statement_t net, unsigned ind) * The wait statement contains simply an array of events to wait on, * and a sub-statement to execute when an event triggers. */ -void show_stmt_wait(ivl_statement_t net, unsigned ind) +static void show_stmt_wait(ivl_statement_t net, unsigned ind) { unsigned idx; const char*comma = ""; diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index de786f3e2..358b2efa6 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -36,7 +36,7 @@ static const char*version_string = "Icarus Verilog STUB Code Generator " VERSION " (" VERSION_TAG ")\n\n" -"Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)\n\n" +"Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)\n\n" " This program is free software; you can redistribute it and/or modify\n" " it under the terms of the GNU General Public License as published by\n" " the Free Software Foundation; either version 2 of the License, or\n" @@ -175,6 +175,9 @@ const char*data_type_string(ivl_variable_type_t vtype) case IVL_VT_CLASS: vt = "class"; break; + case IVL_VT_QUEUE: + vt = "queue"; + break; } return vt; @@ -264,7 +267,7 @@ static void show_lpm_abs(ivl_lpm_t net) } if (width_of_nexus(nex) != width) { - fprintf(out, " ERROR: D width (%d) is wrong\n", + fprintf(out, " ERROR: D width (%u) is wrong\n", width_of_nexus(nex)); stub_errors += 1; } @@ -371,13 +374,31 @@ static void show_lpm_divide(ivl_lpm_t net) show_lpm_arithmetic_pins(net); } -/* IVL_LPM_CMP_EEQ/NEE +/* IVL_LPM_CMP_EEQ/EQX/EQZ/NEE * This LPM node supports two-input compare. The output width is * actually always 1, the lpm_width is the expected width of the inputs. */ static void show_lpm_cmp_eeq(ivl_lpm_t net) { - const char*str = (ivl_lpm_type(net) == IVL_LPM_CMP_EEQ)? "EEQ" : "NEE"; + const char*str; + switch (ivl_lpm_type(net)) { + case IVL_LPM_CMP_EEQ: + str = "EEQ"; + break; + case IVL_LPM_CMP_EQX: + str = "EQX"; + break; + case IVL_LPM_CMP_EQZ: + str = "EQZ"; + break; + case IVL_LPM_CMP_NEE: + str = "NEE"; + break; + default: + assert(0); + break; + } + unsigned width = ivl_lpm_width(net); fprintf(out, " LPM_CMP_%s %s: \n", str, @@ -499,8 +520,28 @@ static void show_lpm_ff(ivl_lpm_t net) } } + if (ivl_lpm_async_clr(net)) { + nex = ivl_lpm_async_clr(net); + fprintf(out, " Aclr: %p\n", nex); + if (width_of_nexus(nex) != 1) { + fprintf(out, " Aclr: ERROR: Nexus width is %u\n", + width_of_nexus(nex)); + stub_errors += 1; + } + } + + if (ivl_lpm_async_set(net)) { + nex = ivl_lpm_async_set(net); + fprintf(out, " Aset: %p\n", nex); + if (width_of_nexus(nex) != 1) { + fprintf(out, " Aset: ERROR: Nexus width is %u\n", + width_of_nexus(nex)); + stub_errors += 1; + } + } + nex = ivl_lpm_data(net,0); - fprintf(out, " D: %p\n", nex); + fprintf(out, " D: %p\n", nex); if (width_of_nexus(nex) != width) { fprintf(out, " D: ERROR: Nexus width is %u\n", width_of_nexus(nex)); @@ -508,7 +549,7 @@ static void show_lpm_ff(ivl_lpm_t net) } nex = ivl_lpm_q(net); - fprintf(out, " Q: %p\n", nex); + fprintf(out, " Q: %p\n", nex); if (width_of_nexus(nex) != width) { fprintf(out, " Q: ERROR: Nexus width is %u\n", width_of_nexus(nex)); @@ -822,6 +863,37 @@ static void show_lpm_sub(ivl_lpm_t net) show_lpm_arithmetic_pins(net); } +static void show_lpm_substitute(ivl_lpm_t net) +{ + unsigned width = ivl_lpm_width(net); + ivl_nexus_t nex_q = ivl_lpm_q(net); + ivl_nexus_t nex_a = ivl_lpm_data(net,0); + ivl_nexus_t nex_s = ivl_lpm_data(net,1); + + unsigned sbase = ivl_lpm_base(net); + unsigned swidth = width_of_nexus(nex_s); + + fprintf(out, " LPM_SUBSTITUTE %s: \n", + ivl_lpm_basename(net), width, sbase, swidth); + fprintf(out, " Q: %p\n", nex_q); + if (width != width_of_nexus(nex_q)) { + fprintf(out, " ERROR: Width of Q is %u, expecting %u\n", + width_of_nexus(nex_q), width); + stub_errors += 1; + } + fprintf(out, " A: %p\n", nex_a); + if (width != width_of_nexus(nex_a)) { + fprintf(out, " ERROR: Width of A is %u, expecting %u\n", + width_of_nexus(nex_a), width); + stub_errors += 1; + } + fprintf(out, " S: %p\n", nex_s); + if (sbase + swidth > width) { + fprintf(out, " ERROR: S part is out of bounds\n"); + stub_errors += 1; + } +} + static void show_lpm_sfunc(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); @@ -934,6 +1006,8 @@ static void show_lpm(ivl_lpm_t net) break; case IVL_LPM_CMP_EEQ: + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_NEE: show_lpm_cmp_eeq(net); break; @@ -984,6 +1058,10 @@ static void show_lpm(ivl_lpm_t net) show_lpm_sub(net); break; + case IVL_LPM_SUBSTITUTE: + show_lpm_substitute(net); + break; + case IVL_LPM_MOD: show_lpm_mod(net); break; @@ -1027,6 +1105,8 @@ static int show_process(ivl_process_t net, void*x) { unsigned idx; + (void)x; /* Parameter is not used. */ + switch (ivl_process_type(net)) { case IVL_PR_INITIAL: if (ivl_process_analog(net)) @@ -1551,6 +1631,8 @@ static int show_scope(ivl_scope_t net, void*x) unsigned idx; const char *is_auto; + (void)x; /* Parameter is not used. */ + fprintf(out, "scope: %s (%u parameters, %u signals, %u logic)", ivl_scope_name(net), ivl_scope_params(net), ivl_scope_sigs(net), ivl_scope_logs(net)); @@ -1577,7 +1659,7 @@ static int show_scope(ivl_scope_t net, void*x) fprintf(out, " class %s", ivl_scope_tname(net)); break; default: - fprintf(out, " type(%u) %s", ivl_scope_type(net), + fprintf(out, " type(%d) %s", ivl_scope_type(net), ivl_scope_tname(net)); break; } @@ -1715,6 +1797,12 @@ int target_design(ivl_design_t des) ivl_scope_t cur = root_scopes[idx]; switch (ivl_scope_type(cur)) { + case IVL_SCT_TASK: + fprintf(out, "task = %s\n", ivl_scope_name(cur)); + break; + case IVL_SCT_FUNCTION: + fprintf(out, "function = %s\n", ivl_scope_name(cur)); + break; case IVL_SCT_CLASS: fprintf(out, "class = %s\n", ivl_scope_name(cur)); break; diff --git a/tgt-stub/types.c b/tgt-stub/types.c index 7323f6729..38a6b38c6 100644 --- a/tgt-stub/types.c +++ b/tgt-stub/types.c @@ -30,6 +30,15 @@ static void show_net_type_darray(ivl_type_t net_type) show_net_type(element_type); } +static void show_net_type_queue(ivl_type_t net_type) +{ + /* Dynamic arrays have a single element type. */ + ivl_type_t element_type = ivl_type_element(net_type); + + fprintf(out, "queue 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); @@ -57,6 +66,9 @@ void show_net_type(ivl_type_t net_type) case IVL_VT_CLASS: fprintf(out, "class"); break; + case IVL_VT_QUEUE: + show_net_type_queue(net_type); + break; case IVL_VT_VOID: fprintf(out, "void"); break; @@ -112,6 +124,12 @@ void show_type_of_signal(ivl_signal_t net) fprintf(out, "ERROR-DARRAY"); stub_errors += 1; break; + case IVL_VT_QUEUE: + /* The QUEUE type MUST be described by an + ivl_signal_net_type object. */ + fprintf(out, "ERROR-QUEUE"); + stub_errors += 1; + break; case IVL_VT_VOID: fprintf(out, "void"); break; diff --git a/tgt-verilog/Makefile.in b/tgt-verilog/Makefile.in index 3fdcb205e..40d6c27d9 100644 --- a/tgt-verilog/Makefile.in +++ b/tgt-verilog/Makefile.in @@ -39,7 +39,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = @ident_support@ $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = verilog.o @@ -55,7 +55,8 @@ distclean: clean rm -f Makefile config.log cppcheck: $(O:.o=.c) - cppcheck --enable=all -f $(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=tgt-verilog/$@ diff --git a/tgt-verilog/cppcheck.sup b/tgt-verilog/cppcheck.sup new file mode 100644 index 000000000..f10e95e54 --- /dev/null +++ b/tgt-verilog/cppcheck.sup @@ -0,0 +1,5 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:verilog.c:408 diff --git a/tgt-verilog/verilog.c b/tgt-verilog/verilog.c index d9c6af93f..333277a59 100644 --- a/tgt-verilog/verilog.c +++ b/tgt-verilog/verilog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -232,7 +232,6 @@ static void show_expression(ivl_expr_t net) static void show_assign_lval(ivl_lval_t lval) { ivl_nexus_t nex; - ivl_nexus_ptr_t ptr; ivl_signal_t sig=NULL; unsigned idx; @@ -245,6 +244,7 @@ static void show_assign_lval(ivl_lval_t lval) for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) { unsigned pin; + ivl_nexus_ptr_t ptr; ptr = ivl_nexus_ptr(nex, idx); sig = ivl_nexus_ptr_sig(ptr); diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 5c1daf11e..b86c11a98 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -60,7 +60,8 @@ distclean: clean rm -f stamp-vhdl_config-h vhdl_config.h cppcheck: $(O:.o=.cc) - cppcheck --enable=all -f $(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=tgt-vhdl/$@ diff --git a/tgt-vhdl/cppcheck.sup b/tgt-vhdl/cppcheck.sup new file mode 100644 index 000000000..37a3b956f --- /dev/null +++ b/tgt-vhdl/cppcheck.sup @@ -0,0 +1,8 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:vhdl.cc:96 + +// target_query() +unusedFunction:vhdl.cc:137 diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index f6d03c373..098d4a9fe 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -1,7 +1,7 @@ /* * VHDL code generation for logic devices. * - * Copyright (C) 2008-2011 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008-2014 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -117,8 +117,7 @@ static void comb_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) ss << ivl_logic_basename(log) << "_Tmp"; int msb = ivl_udp_nin(udp) - 1; vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0); - vhdl_signal_decl *tmp_decl = - new vhdl_signal_decl(ss.str().c_str(), tmp_type); + vhdl_signal_decl *tmp_decl = new vhdl_signal_decl(ss.str(), tmp_type); arch->get_scope()->add_decl(tmp_decl); int nin = ivl_udp_nin(udp); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 5c867ab8d..28c5b0c5c 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -1,7 +1,7 @@ /* * VHDL code generation for scopes. * - * Copyright (C) 2008-2013 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008-2014 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -204,7 +204,7 @@ void draw_nexus(ivl_nexus_t nexus) ostringstream ss; ss << "LO" << ivl_logic_basename(log); - vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); + vhdl_scope->add_decl(new vhdl_signal_decl(ss.str(), type)); link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str()); } @@ -251,7 +251,7 @@ void draw_nexus(ivl_nexus_t nexus) ss << ivl_lpm_basename(lpm); if (!vhdl_scope->have_declared(ss.str())) - vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); + vhdl_scope->add_decl(new vhdl_signal_decl(ss.str(), type)); link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str()); } @@ -561,7 +561,7 @@ static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, vhdl_type *array_type = vhdl_type::array_of(base_type, type_name, msb, lsb); - vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type); + vhdl_decl *array_decl = new vhdl_type_decl(type_name, array_type); ent->get_arch()->get_scope()->add_decl(array_decl); sig_type = new vhdl_type(*array_type); @@ -578,7 +578,7 @@ static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, switch (mode) { case IVL_SIP_NONE: { - vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type); + vhdl_decl *decl = new vhdl_signal_decl(name, sig_type); ostringstream ss; if (ivl_signal_local(sig)) { @@ -612,11 +612,11 @@ static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, // which represents the register std::string newname(name); newname += "_Reg"; - rename_signal(sig, newname.c_str()); + rename_signal(sig, newname); vhdl_type *reg_type = new vhdl_type(*sig_type); ent->get_arch()->get_scope()->add_decl - (new vhdl_signal_decl(newname.c_str(), reg_type)); + (new vhdl_signal_decl(newname, reg_type)); // Create a concurrent assignment statement to // connect the register to the output @@ -892,7 +892,7 @@ static int draw_task(ivl_scope_t scope, ivl_scope_t parent) signame += taskname; } - vhdl_signal_decl *decl = new vhdl_signal_decl(signame.c_str(), sigtype); + vhdl_signal_decl *decl = new vhdl_signal_decl(signame, sigtype); ostringstream ss; ss << "Declared at " << ivl_signal_file(sig) << ":" diff --git a/tgt-vlog95/Makefile.in b/tgt-vlog95/Makefile.in index 19428f2e9..2bf721115 100644 --- a/tgt-vlog95/Makefile.in +++ b/tgt-vlog95/Makefile.in @@ -40,7 +40,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ O = vlog95.o event.o expr.o logic_lpm.o misc.o numbers.o scope.o stmt.o udp.o @@ -56,7 +56,8 @@ distclean: clean rm -f Makefile config.log cppcheck: $(O:.o=.c) - cppcheck --enable=all -f $(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=tgt-vlog95/$@ @@ -77,7 +78,7 @@ else endif vlog95.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O -lm $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl$(suffix)/vlog95.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/vlog95.conf $(libdir)/ivl$(suffix)/vlog95-s.conf diff --git a/tgt-vlog95/cppcheck.sup b/tgt-vlog95/cppcheck.sup new file mode 100644 index 000000000..f1a757bf9 --- /dev/null +++ b/tgt-vlog95/cppcheck.sup @@ -0,0 +1,8 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:vlog95.c:59 + +// target_query() +unusedFunction:vlog95.c:226 diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index e8f6810ad..f516a7a9e 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2014 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 @@ -293,6 +293,7 @@ static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr, unsigned expr_wid; ivl_expr_t lval = ivl_expr_oper1(expr); ivl_expr_t rval = ivl_expr_oper2(expr); + (void)wid; /* Parameter is not used. */ /* The L-value must be a number. */ if (ivl_expr_type(lval) != IVL_EX_NUMBER) return 0; /* The L-value must of the form 2^n. */ @@ -357,6 +358,7 @@ static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr, static void emit_expr_array(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { ivl_signal_t sig = ivl_expr_signal(expr); + (void)wid; /* Parameter is not used. */ emit_scope_call_path(scope, ivl_signal_scope(sig)); emit_id(ivl_signal_basename(sig)); } @@ -401,7 +403,7 @@ static unsigned calc_can_skip_unsigned(ivl_expr_t oper1, ivl_expr_t oper2) static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, unsigned is_full_prec) { - char *oper = ""; + const char *oper = ""; ivl_expr_t oper1 = ivl_expr_oper1(expr); ivl_expr_t oper2 = ivl_expr_oper2(expr); unsigned can_skip_unsigned = calc_can_skip_unsigned(oper1, oper2); @@ -559,6 +561,7 @@ static void emit_expr_concat(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) unsigned repeat = ivl_expr_repeat(expr); unsigned idx, count = ivl_expr_parms(expr); + (void)wid; /* Parameter is not used. */ if (repeat != 1) fprintf(vlog_out, "{%u", repeat); fprintf(vlog_out, "{"); count -= 1; @@ -573,6 +576,7 @@ static void emit_expr_concat(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_delay(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { + (void)wid; /* Parameter is not used. */ emit_scaled_delay(scope, ivl_expr_delay_val(expr)); } @@ -583,6 +587,7 @@ static void emit_expr_event(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { ivl_event_t event = ivl_expr_event(expr); ivl_scope_t ev_scope = ivl_event_scope(event); + (void)wid; /* Parameter is not used. */ assert(! ivl_event_nany(event)); assert(! ivl_event_npos(event)); assert(! ivl_event_nneg(event)); @@ -598,6 +603,7 @@ static void emit_expr_event(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_number(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { ivl_parameter_t param = ivl_expr_parameter(expr); + (void)wid; /* Parameter is not used. */ if (param && (param != emitting_param)) { emit_scope_call_path(scope, ivl_parameter_scope(param)); emit_id(ivl_parameter_basename(param)); @@ -612,6 +618,7 @@ static void emit_expr_real_number(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { ivl_parameter_t param = ivl_expr_parameter(expr); + (void)wid; /* Parameter is not used. */ if (param && (param != emitting_param)) { emit_scope_call_path(scope, ivl_parameter_scope(param)); emit_id(ivl_parameter_basename(param)); @@ -623,9 +630,10 @@ static void emit_expr_real_number(ivl_scope_t scope, ivl_expr_t expr, /* * Class properties are not supported in vlog95, but they can be translated. */ -void emit_class_property(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) +static void emit_class_property(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { ivl_signal_t sig = ivl_expr_signal(expr); + (void)wid; /* Parameter is not used. */ emit_scope_call_path(scope, ivl_signal_scope(sig)); emit_id(ivl_signal_basename(sig)); fprintf(vlog_out, ".%s", ivl_expr_name(expr)); @@ -644,6 +652,8 @@ static void emit_expr_scope_piece(ivl_scope_t scope) static void emit_expr_scope(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { + (void)scope; /* Parameter is not used. */ + (void)wid; /* Parameter is not used. */ emit_expr_scope_piece(ivl_expr_scope(expr)); } @@ -844,9 +854,12 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) ivl_expr_t sel_expr = ivl_expr_oper2(expr); ivl_expr_t sig_expr = ivl_expr_oper1(expr); ivl_select_type_t sel_type = ivl_expr_sel_type(expr); - /* If this is a dynamic array select, translate it differently. */ + (void)wid; /* Parameter is not used. */ + /* If this is a dynamic array or queue select, translate the + * select differently. */ if ((ivl_expr_type(sig_expr) == IVL_EX_SIGNAL) && - (ivl_signal_data_type(ivl_expr_signal(sig_expr)) == IVL_VT_DARRAY)) { + ((ivl_signal_data_type(ivl_expr_signal(sig_expr)) == IVL_VT_DARRAY) || + (ivl_signal_data_type(ivl_expr_signal(sig_expr)) == IVL_VT_QUEUE))) { assert(sel_expr); emit_select_name(scope, sig_expr); fprintf(vlog_out, "["); @@ -923,6 +936,7 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_func(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { unsigned count = ivl_expr_parms(expr); + (void)wid; /* Parameter is not used. */ if (count) { unsigned idx; fprintf(vlog_out, "("); @@ -945,6 +959,7 @@ static void emit_expr_func(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_signal(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { ivl_signal_t sig = ivl_expr_signal(expr); + (void)wid; /* Parameter is not used. */ emit_scope_call_path(scope, ivl_signal_scope(sig)); emit_id(ivl_signal_basename(sig)); if (ivl_signal_dimensions(sig)) { @@ -976,7 +991,7 @@ static void emit_expr_ternary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, unsigned is_full_prec) { - char *oper = "invalid"; + const char *oper = "invalid"; ivl_expr_t oper1 = ivl_expr_oper1(expr); switch (ivl_expr_opcode(expr)) { case '-': oper = "-"; break; diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index e7af3cf65..7e390d809 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2014 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 @@ -332,6 +332,8 @@ static ivl_nexus_t get_lpm_output(ivl_scope_t scope, ivl_lpm_t lpm) case IVL_LPM_CAST_REAL: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: @@ -358,6 +360,7 @@ static ivl_nexus_t get_lpm_output(ivl_scope_t scope, ivl_lpm_t lpm) case IVL_LPM_SHIFTR: case IVL_LPM_SIGN_EXT: case IVL_LPM_SUB: + case IVL_LPM_SUBSTITUTE: case IVL_LPM_UFUNC: /* If the output of this LPM is a local signal then something * else will request that this be emitted. */ @@ -736,6 +739,7 @@ static ivl_signal_t find_output_signal(ivl_scope_t scope, ivl_nexus_t nex, unsigned*array_word) { unsigned idx, count = ivl_nexus_ptrs(nex); + (void)array_word; /* Parameter is not used. */ for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); @@ -992,6 +996,30 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm, emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0); fprintf(vlog_out, ")"); break; + case IVL_LPM_CMP_EQX: +// HERE: Need to heck that this is not a real nexus. + fprintf(vlog_out, "("); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0); + fprintf(vlog_out, " ==? "); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0); + fprintf(vlog_out, ")"); + fprintf(stderr, "%s:%u: vlog95 error: Compare wildcard equal " + "operator is not supported.\n", + ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); + vlog_errors += 1; + break; + case IVL_LPM_CMP_EQZ: +// HERE: Need to heck that this is not a real nexus. + fprintf(vlog_out, "("); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0); + fprintf(vlog_out, " == "); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0); + fprintf(vlog_out, ")"); + fprintf(stderr, "%s:%u: vlog95 error: Compare equal Z (caseZ) " + "operator is not supported.\n", + ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); + vlog_errors += 1; + break; case IVL_LPM_CMP_GE: fprintf(vlog_out, "("); emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0, 0); @@ -1159,6 +1187,13 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm, emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0, 0); fprintf(vlog_out, ")"); break; + case IVL_LPM_SUBSTITUTE: + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 sorry: Substitute LPMs are " + "not currently translated.\n", + ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); + vlog_errors += 1; + break; case IVL_LPM_UFUNC: emit_scope_path(scope, ivl_lpm_define(lpm)); emit_lpm_func(scope, lpm); @@ -1175,7 +1210,7 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm, if (sign_type != NO_SIGN) fprintf(vlog_out, ")"); } -static void emit_posedge_dff_prim() +static void emit_posedge_dff_prim(void) { fprintf(vlog_out, "\n"); fprintf(vlog_out, "/* Icarus generated UDP to represent a synthesized " @@ -1459,7 +1494,7 @@ static void emit_lpm_part_pv(ivl_scope_t scope, ivl_lpm_t lpm) fprintf(vlog_out, "]"); } -unsigned output_is_module_instantiation_input(ivl_scope_t scope, +static unsigned output_is_module_instantiation_input(ivl_scope_t scope, ivl_nexus_t nex) { unsigned idx, count = ivl_nexus_ptrs(nex); @@ -1944,7 +1979,7 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) assert(! nlogic); assert(! sig); fprintf(stderr, "LPM: "); - fprintf(stderr, "{%s:%d} ", ivl_lpm_file(lpm), + fprintf(stderr, "{%s:%u} ", ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); if (scope != lpm_scope) fprintf(stderr, "(%s) ", ivl_scope_name(lpm_scope)); @@ -2003,7 +2038,7 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) ivl_logic_t logic_type = ivl_logic_type(nlogic); assert(! sig); fprintf(stderr, "Logic: "); - fprintf(stderr, "{%s:%d} ", ivl_logic_file(nlogic), + fprintf(stderr, "{%s:%u} ", ivl_logic_file(nlogic), ivl_logic_lineno(nlogic)); if (scope != logic_scope) { fprintf(stderr, "(%s) ", ivl_scope_name(logic_scope)); @@ -2065,7 +2100,7 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) fprintf(stderr, "\""); // HERE: Do we need to add support for an array word or is that an LPM. if (ivl_signal_local(sig)) fprintf(stderr, " {local}"); - else fprintf(stderr, " {%s:%d}", ivl_signal_file(sig), + else fprintf(stderr, " {%s:%u}", ivl_signal_file(sig), ivl_signal_lineno(sig)); switch (ivl_signal_port(sig)) { case IVL_SIP_INPUT: fprintf(stderr, " input"); break; @@ -2092,6 +2127,7 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) case IVL_VT_STRING: fprintf(stderr, " string"); break; case IVL_VT_DARRAY: fprintf(stderr, " dynamic array"); case IVL_VT_CLASS: fprintf(stderr, " class"); + case IVL_VT_QUEUE: fprintf(stderr, " queue"); break; } if (ivl_signal_signed(sig)) fprintf(stderr, " "); diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index 1ca096bec..8787c0302 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2014 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 @@ -369,6 +369,7 @@ void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr, unsigned width, int rtype; int64_t value = get_in_range_int64_from_number(expr, &rtype, "range value"); + (void)scope; /* Parameter is not used. */ if (rtype < 0) fprintf(vlog_out, "[1'bx:1'bx]"); if (rtype) return; @@ -689,6 +690,7 @@ static unsigned is_local_input(ivl_scope_t scope, ivl_nexus_t nex) ivl_signal_t sig = 0; unsigned idx, count = ivl_nexus_ptrs(nex); + (void)scope; /* Parameter is not used. */ for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); @@ -814,8 +816,12 @@ void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope) * references for variables, etc. */ void emit_scope_call_path(ivl_scope_t scope, ivl_scope_t call_scope) { - ivl_scope_t mod_scope = get_module_scope(scope); - ivl_scope_t call_mod_scope = get_module_scope(call_scope); + ivl_scope_t mod_scope, call_mod_scope; + + if (scope == call_scope) return; + + mod_scope = get_module_scope(scope); + call_mod_scope = get_module_scope(call_scope); if (mod_scope != call_mod_scope) { emit_scope_piece(mod_scope, call_mod_scope); @@ -862,8 +868,17 @@ static void emit_scope_path_piece(ivl_scope_t scope, ivl_scope_t call_scope) */ void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope) { - ivl_scope_t mod_scope = get_module_scope(scope); - ivl_scope_t call_mod_scope = get_module_scope(call_scope); + ivl_scope_t mod_scope, call_mod_scope; + + /* Check to see if this is a root scope task or function. */ + if (ivl_scope_parent(call_scope) == 0) { + fprintf(vlog_out, "ivl_root_scope."); + mod_scope = 0; + call_mod_scope = 0; + } else { + mod_scope = get_module_scope(scope); + call_mod_scope = get_module_scope(call_scope); + } if (mod_scope == call_mod_scope) { emit_id(ivl_scope_basename(call_scope)); diff --git a/tgt-vlog95/numbers.c b/tgt-vlog95/numbers.c index 3579f5018..08fea9add 100644 --- a/tgt-vlog95/numbers.c +++ b/tgt-vlog95/numbers.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2014 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 @@ -16,6 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +# include # include # include # include "config.h" @@ -75,11 +76,10 @@ static int32_t get_int32_from_bits(const char *bits, unsigned nbits, * otherwise emit them as a hex constant. */ static void emit_bits(const char *bits, unsigned nbits, unsigned is_signed) { - int idx; unsigned has_undef = 0; /* Check for an undefined bit. */ - for (idx = (int)nbits-1; idx >= 0; idx -= 1) { + for (int idx = (int)nbits-1; idx >= 0; idx -= 1) { if ((bits[idx] != '0') && (bits[idx] != '1')) { has_undef = 1; break; @@ -92,23 +92,23 @@ static void emit_bits(const char *bits, unsigned nbits, unsigned is_signed) /* Emit as a binary constant. */ if (has_undef || (nbits < 2)) { fprintf(vlog_out, "b"); - for (idx = (int)nbits-1; idx >= 0; idx -= 1) { + for (int idx = (int)nbits-1; idx >= 0; idx -= 1) { fprintf(vlog_out, "%c", bits[idx]); } /* Emit as a hex constant. */ } else { - int start = 4*(nbits/4); + unsigned start = 4*(nbits/4); unsigned result = 0; fprintf(vlog_out, "h"); /* The first digit may not be a full hex digit. */ if (start < nbits) { - for (idx = start; idx < nbits; idx += 1) { + for (unsigned idx = start; idx < nbits; idx += 1) { if (bits[idx] == '1') result |= 1U << (idx%4); } fprintf(vlog_out, "%1x", result); } /* Now print the full hex digits. */ - for (idx = start-1; idx >= 0; idx -= 4) { + for (int idx = start-1; idx >= 0; idx -= 4) { result = 0; if (bits[idx] == '1') result |= 0x8; if (bits[idx-1] == '1') result |= 0x4; @@ -169,18 +169,19 @@ void emit_number(const char *bits, unsigned nbits, unsigned is_signed, void emit_real_number(double value) { /* Check for NaN. */ - if (value != value) { + if (isnan(value)) { fprintf(vlog_out, "(0.0/0.0)"); return; } /* Check for the infinities. */ - if (value && value == 0.5*value) { - if (value > 0) fprintf(vlog_out, "(1.0/0.0)"); - else fprintf(vlog_out, "(-1.0/0.0)"); + if (isinf(value)) { + if (signbit(value)) fprintf(vlog_out, "(-1.0/0.0)"); + else fprintf(vlog_out, "(1.0/0.0)"); return; } + /* Check for +/- zero. */ if (value == 0.0) { - if (1.0/value < 0.0) fprintf(vlog_out, "-0.0"); + if (signbit(value)) fprintf(vlog_out, "-0.0"); else fprintf(vlog_out, "0.0"); } else { char buffer[32]; diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 59657e7b2..e5043fa77 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2014 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 @@ -24,7 +24,7 @@ const char *func_rtn_name = 0; -static char*get_time_const(int time_value) +static const char*get_time_const(int time_value) { switch (time_value) { case 2: return "100s"; @@ -51,7 +51,7 @@ static char*get_time_const(int time_value) } } -void emit_func_return(ivl_signal_t sig) +static void emit_func_return(ivl_signal_t sig) { if (ivl_signal_dimensions(sig) > 0) { fprintf(stderr, "%s:%u: vlog95 error: A function cannot return " @@ -86,7 +86,7 @@ static void emit_sig_id(ivl_signal_t sig) fprintf(vlog_out, "\n"); } -void emit_var_def(ivl_signal_t sig) +static void emit_var_def(ivl_signal_t sig) { if (ivl_signal_local(sig)) return; fprintf(vlog_out, "%*c", indent, ' '); @@ -125,6 +125,14 @@ void emit_var_def(ivl_signal_t sig) ivl_signal_file(sig), ivl_signal_lineno(sig), ivl_signal_basename(sig)); vlog_errors += 1; + } else if (ivl_signal_data_type(sig) == IVL_VT_QUEUE) { + fprintf(vlog_out, " "); + emit_sig_id(sig); + fprintf(stderr, "%s:%u: vlog95 error: SystemVerilog queues " + "(%s) are not supported.\n", + ivl_signal_file(sig), + ivl_signal_lineno(sig), ivl_signal_basename(sig)); + vlog_errors += 1; } else { int msb, lsb; get_sig_msb_lsb(sig, &msb, &lsb); @@ -199,7 +207,7 @@ 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) +static void emit_net_def(ivl_scope_t scope, ivl_signal_t sig) { int msb, lsb; get_sig_msb_lsb(sig, &msb, &lsb); @@ -414,7 +422,14 @@ static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex, static void emit_sig_type(ivl_signal_t sig) { ivl_signal_type_t type = ivl_signal_type(sig); - assert(ivl_signal_dimensions(sig) == 0); + if (ivl_signal_dimensions(sig) != 0) { + fprintf(stderr, "%s:%u: vlog95 error: Array ports (%s) are not " + "supported.\n", + ivl_signal_file(sig), + ivl_signal_lineno(sig), + ivl_signal_basename(sig)); + vlog_errors += 1; + } /* Check to see if we have a variable (reg) or a net. */ if (type == IVL_SIT_REG) { if (ivl_signal_integer(sig)) { @@ -718,6 +733,7 @@ static int find_tf_process(ivl_process_t proc, ivl_scope_t scope) static int emit_tf_process(ivl_scope_t scope, ivl_scope_t parent) { ivl_scope_type_t sc_type = ivl_scope_type(scope); + (void)parent; /* Parameter is not used. */ if ((sc_type == IVL_SCT_FUNCTION) || (sc_type == IVL_SCT_TASK)) { /* Output the initial/always blocks for this module. */ ivl_design_process(design, (ivl_process_f)find_tf_process, scope); @@ -1039,6 +1055,8 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) emit_module_ports(scope); break; case IVL_SCT_FUNCTION: + /* Root scope functions have already been emitted. */ + if (! parent) return 0; assert(indent != 0); fprintf(vlog_out, "\n%*cfunction", indent, ' '); if (ivl_scope_ports(scope) < 1) { @@ -1061,6 +1079,8 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) } break; case IVL_SCT_TASK: + /* Root scope tasks have already been emitted. */ + if (! parent) return 0; assert(indent != 0); fprintf(vlog_out, "\n%*ctask ", indent, ' '); emit_id(ivl_scope_tname(scope)); diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 530c9e471..a804b884e 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2014 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 @@ -23,7 +23,7 @@ static unsigned single_indent = 0; -static unsigned get_indent() +static unsigned get_indent(void) { if (single_indent) { single_indent = 0; @@ -408,7 +408,8 @@ static void emit_assign_and_opt_opcode(ivl_scope_t scope, ivl_statement_t stmt, unsigned allow_opcode) { unsigned wid; - char opcode, *opcode_str; + char opcode; + const char *opcode_str; assert (ivl_statement_type(stmt) == IVL_ST_ASSIGN); // HERE: Do we need to calculate the width? The compiler should have already @@ -941,7 +942,7 @@ static void emit_stmt_block_named(ivl_scope_t scope, ivl_statement_t stmt) static void emit_stmt_case(ivl_scope_t scope, ivl_statement_t stmt) { - char *case_type; + const char *case_type; unsigned idx, default_case, count = ivl_stmt_case_count(stmt); switch (ivl_statement_type(stmt)) { case IVL_ST_CASE: @@ -1383,14 +1384,16 @@ static void emit_stmt_stask(ivl_scope_t scope, ivl_statement_t stmt) fprintf(vlog_out, "%*c%s", get_indent(), ' ', ivl_stmt_name(stmt)); if (count != 0) { unsigned idx; + ivl_expr_t expr; fprintf(vlog_out, "("); count -= 1; for (idx = 0; idx < count; idx += 1) { - ivl_expr_t expr = ivl_stmt_parm(stmt, idx); + expr = ivl_stmt_parm(stmt, idx); if (expr) emit_expr(scope, expr, 0, 0, 0, 0); fprintf(vlog_out, ", "); } - emit_expr(scope, ivl_stmt_parm(stmt, count), 0, 0, 0, 0); + expr = ivl_stmt_parm(stmt, count); + if (expr) emit_expr(scope, expr, 0, 0, 0, 0); fprintf(vlog_out, ")"); } fprintf(vlog_out, ";"); @@ -1428,6 +1431,7 @@ static void emit_stmt_utask(ivl_scope_t scope, ivl_statement_t stmt) /* Look to see if this is a SystemVerilog wait fork statement. */ static unsigned is_wait_fork(ivl_scope_t scope, ivl_statement_t stmt) { + (void)scope; /* Parameter is not used. */ if (ivl_stmt_nevent(stmt) != 1) return 0; if (ivl_stmt_events(stmt, 0) != 0) return 0; assert(ivl_statement_type(ivl_stmt_sub_stmt(stmt)) == IVL_ST_NOOP); diff --git a/tgt-vlog95/vlog95.c b/tgt-vlog95/vlog95.c index dcd893570..1765b9468 100644 --- a/tgt-vlog95/vlog95.c +++ b/tgt-vlog95/vlog95.c @@ -60,6 +60,7 @@ int target_design(ivl_design_t des) { ivl_scope_t *roots; unsigned nroots, idx; + unsigned has_root_scope = 0; const char*path = ivl_design_flag(des, "-o"); /* Set the indent spacing with the -pspacing flag passed to iverilog * (e.g. -pspacing=4). The default is 2 spaces. */ @@ -184,6 +185,30 @@ int target_design(ivl_design_t des) /* Get all the root modules and then convert each one. */ ivl_design_roots(des, &roots, &nroots); + /* Emit any root scope tasks or functions first. */ + for (idx = 0; idx < nroots; idx += 1) { + switch(ivl_scope_type(roots[idx])) { + case IVL_SCT_FUNCTION: + case IVL_SCT_TASK: + if (! has_root_scope) { + fprintf(vlog_out, "module ivl_root_scope;\n"); + indent += indent_incr; + has_root_scope = 1; + } + /* Say this task/function has a parent so the + * definition is emitted correctly. */ + emit_scope(roots[idx], roots[idx]); + break; + default: + break; + } + } + if (has_root_scope) { + indent -= indent_incr; + assert(indent == 0); + fprintf(vlog_out, "endmodule /* ivl_root_scope */\n"); + } + /* Emit the rest of the scope objets. */ for (idx = 0; idx < nroots; idx += 1) emit_scope(roots[idx], 0); free_emitted_scope_list(); diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index af0fd9c92..fb632d95e 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -1,7 +1,7 @@ -#ifndef __vlog95_priv_H -#define __vlog95_priv_H +#ifndef IVL_vlog95_priv_H +#define IVL_vlog95_priv_H /* - * Copyright (C) 2010-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2014 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 @@ -106,10 +106,10 @@ extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex, extern void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex); extern void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t const_net); extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig); -extern void emit_icarus_generated_udps(); +extern void emit_icarus_generated_udps(void); extern void add_udp_to_list(ivl_udp_t udp); -extern void emit_udp_list(); +extern void emit_udp_list(void); extern void emit_sig_file_line(ivl_signal_t sig); extern void emit_id(const char *id); @@ -148,11 +148,11 @@ extern void get_sig_msb_lsb(ivl_signal_t sig, int *msb, int *lsb); /* * Cleanup functions. */ -extern void free_emitted_scope_list(); +extern void free_emitted_scope_list(void); /* * Debug routine to dump the various pieces of nexus information. */ extern void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex); -#endif /* __vlog95_priv_H */ +#endif /* IVL_vlog95_priv_H */ diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index 0a793a29c..f40e60285 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -44,10 +44,10 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -O = vvp.o draw_class.o draw_enum.o draw_mux.o draw_net_input.o \ +O = vvp.o draw_class.o draw_enum.o draw_mux.o draw_substitute.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 \ eval_vec4.o \ @@ -66,7 +66,8 @@ distclean: clean rm -f stamp-vvp_config-h vvp_config.h cppcheck: $(O:.o=.c) - cppcheck --enable=all -f $(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=tgt-vvp/$@ diff --git a/tgt-vvp/cppcheck.sup b/tgt-vvp/cppcheck.sup new file mode 100644 index 000000000..ec869c2a2 --- /dev/null +++ b/tgt-vvp/cppcheck.sup @@ -0,0 +1,8 @@ +// These are the global access functions called from the compiler so they +// are not used here. + +// target_design() +unusedFunction:vvp.c:89 + +// target_query() +unusedFunction:vvp.c:184 diff --git a/tgt-vvp/draw_class.c b/tgt-vvp/draw_class.c index c0e538831..afbc26d5c 100644 --- a/tgt-vvp/draw_class.c +++ b/tgt-vvp/draw_class.c @@ -30,7 +30,7 @@ static void show_prop_type_vector(ivl_type_t ptype) unsigned packed_dimensions = ivl_type_packed_dimensions(ptype); assert(packed_dimensions < 2); - char*signed_flag = ivl_type_signed(ptype)? "s" : ""; + const char*signed_flag = ivl_type_signed(ptype)? "s" : ""; char code = data_type==IVL_VT_BOOL? 'b' : 'L'; if (packed_dimensions == 0) { @@ -49,6 +49,7 @@ static void show_prop_type_vector(ivl_type_t ptype) static void show_prop_type(ivl_type_t ptype) { ivl_variable_type_t data_type = ivl_type_base(ptype); + unsigned packed_dimensions = ivl_type_packed_dimensions(ptype); switch (data_type) { case IVL_VT_REAL: @@ -64,6 +65,15 @@ static void show_prop_type(ivl_type_t ptype) case IVL_VT_DARRAY: case IVL_VT_CLASS: fprintf(vvp_out, "\"o\""); + if (packed_dimensions > 0) { + unsigned idx; + fprintf(vvp_out, " "); + for (idx = 0 ; idx < packed_dimensions ; idx += 1) { + fprintf(vvp_out, "[%d:%d]", + ivl_type_packed_msb(ptype,idx), + ivl_type_packed_lsb(ptype,idx)); + } + } break; default: fprintf(vvp_out, "\"\""); diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index 2e3585b35..4fb27270f 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -110,7 +110,7 @@ static void draw_lpm_mux_nest(ivl_lpm_t net, const char*muxz) unsigned swidth = ivl_lpm_selects(net); char*select_input; - assert(swidth < sizeof(unsigned)); + assert(swidth < 8*sizeof(unsigned)); assert(ivl_lpm_size(net) == (1U << swidth)); select_input = strdup(draw_net_input(ivl_lpm_select(net))); @@ -127,8 +127,8 @@ 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/%us .part %s, %u, 1;\n", - net, level, select_input, level); + fprintf(vvp_out, "L_%p/%us .part %s, %u, 1; Bit %u of the select\n", + net, level, select_input, level, level); for (idx = 0 ; idx < (ivl_lpm_size(net) >> level); idx += 2) { fprintf(vvp_out, "L_%p/%u/%d .functor %s %u", diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index 3ee73d36b..906be39a0 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -158,7 +158,7 @@ static char* draw_C8_to_string(ivl_net_const_t cptr, return result; } -static struct vvp_nexus_data*new_nexus_data() +static struct vvp_nexus_data*new_nexus_data(void) { struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data)); return data; @@ -230,7 +230,7 @@ static void str_repeat(char*buf, const char*str, unsigned rpt) * If the drive strength is strong we can draw a C4<> constant as the * pull value, otherwise we need to draw a C8<> constant. */ -static char* draw_net_pull(ivl_net_logic_t lptr, ivl_drive_t drive, char*level) +static char* draw_net_pull(ivl_net_logic_t lptr, ivl_drive_t drive, const char*level) { char*result; char tmp[32]; @@ -450,6 +450,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) case IVL_LPM_CONCATZ: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: @@ -474,6 +476,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) case IVL_LPM_PART_VP: case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */ case IVL_LPM_REPEAT: + case IVL_LPM_SUBSTITUTE: if (ivl_lpm_q(lpm) == nex) { char tmp[128]; snprintf(tmp, sizeof tmp, "L_%p", lpm); diff --git a/tgt-vvp/draw_substitute.c b/tgt-vvp/draw_substitute.c new file mode 100644 index 000000000..22d5c4223 --- /dev/null +++ b/tgt-vvp/draw_substitute.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 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 + +void draw_lpm_substitute(ivl_lpm_t net) +{ + unsigned swidth = width_of_nexus(ivl_lpm_data(net,1)); + fprintf(vvp_out, "L_%p .substitute %u, %u %u", + net, ivl_lpm_width(net), ivl_lpm_base(net), swidth); + fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,0))); + fprintf(vvp_out, ", %s;\n", draw_net_input(ivl_lpm_data(net,1))); +} diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 8c641d138..b19d2a225 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -521,7 +521,27 @@ static struct vector_info draw_binary_expr_eq_class(ivl_expr_t expr) } 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)); + ivl_signal_t sig = ivl_expr_signal(le); + + if (ivl_signal_dimensions(sig) == 0) { + fprintf(vvp_out, " %%test_nul v%p_0;\n", sig); + } else { + ivl_expr_t word_ex = ivl_expr_oper1(le); + int word_ix = allocate_word(); + draw_eval_expr_into_integer(word_ex, word_ix); + fprintf(vvp_out, " %%test_nul/a v%p, %d;\n", sig, word_ix); + clr_word(word_ix); + } + 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; + } + + if (ivl_expr_type(re) == IVL_EX_NULL && ivl_expr_value(le)==IVL_VT_CLASS) { + draw_eval_object(le); + fprintf(vvp_out, " %%test_nul/obj;\n"); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); 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); @@ -1794,6 +1814,8 @@ static struct vector_info draw_select_array(ivl_expr_t sube, struct vector_info shiv; struct vector_info res; + (void)bit_width; /* Parameter is not used. */ + shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO); draw_eval_expr_into_integer(ix, 3); label = local_count++; @@ -1841,9 +1863,10 @@ 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) { + /* Special case: the sub expression is a DARRAY or QUEUE + variable, so do a dynamic array word load. */ + if ((ivl_signal_data_type(sig) == IVL_VT_DARRAY) + || (ivl_signal_data_type(sig) == IVL_VT_QUEUE)) { res.base = allocate_vector(wid); res.wid = wid; draw_eval_expr_into_integer(bit_idx, 3); @@ -1933,6 +1956,8 @@ static void draw_select_signal_dest(ivl_expr_t expr, struct vector_info tmp; ivl_signal_t sig = ivl_expr_signal(sube); + (void)stuff_ok_flag; /* Parameter is not used. */ + /* Special case: If the operand is a signal (not an array) and the part select is coming from the LSB, and the part select is no larger than the signal itself, then we can load the @@ -1971,6 +1996,8 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr, ivl_expr_t sube = ivl_expr_oper1(expr); ivl_expr_t shift = ivl_expr_oper2(expr); + (void)stuff_ok_flag; /* Parameter is not used. */ + assert(!ivl_expr_sized(sube)); res.wid = wid; @@ -2429,6 +2456,29 @@ static struct vector_info draw_ternary_expr(ivl_expr_t expr, unsigned wid) return res; } +static struct vector_info draw_darray_pop(ivl_expr_t expr, unsigned wid) +{ + struct vector_info res; + ivl_expr_t arg; + const char*fb; + + if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_back")==0) + fb = "b"; + else + fb = "f"; + + res.base = allocate_vector(wid); + res.wid = wid; + + arg = ivl_expr_parm(expr, 0); + assert(ivl_expr_type(arg) == IVL_EX_SIGNAL); + + fprintf(vvp_out, " %%qpop/%s v%p_0, %u, %u;\n", fb, + ivl_expr_signal(arg), res.base, res.wid); + + return res; +} + static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid) { #if 0 @@ -2451,6 +2501,11 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid) } + if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_back")==0) + return draw_darray_pop(expr, wid); + if (strcmp(ivl_expr_name(expr),"$ivl_darray_method$pop_front")==0) + return draw_darray_pop(expr, wid); + res = draw_vpi_func_call(expr, wid); /* New basic block starts after VPI calls. */ @@ -2938,11 +2993,9 @@ struct vector_info draw_eval_expr_wid(ivl_expr_t expr, unsigned wid, default: case IVL_EX_NONE: fprintf(stderr, "%s:%u: vvp.tgt error: unhandled expr. type: " - "%u at %s:%d\n", ivl_expr_file(expr), ivl_expr_lineno(expr), + "%d at %s:%d\n", ivl_expr_file(expr), ivl_expr_lineno(expr), ivl_expr_type(expr), __FILE__, __LINE__); exit(1); - res.base = 0; - res.wid = 0; break; case IVL_EX_EVENT: fprintf(stderr, "%s:%u: vvp.tgt error: A named event is not " diff --git a/tgt-vvp/eval_object.c b/tgt-vvp/eval_object.c index 49821de04..b90afc9ee 100644 --- a/tgt-vvp/eval_object.c +++ b/tgt-vvp/eval_object.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 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 @@ -67,7 +67,7 @@ static int eval_darray_new(ivl_expr_t ex) } if (init_expr && ivl_expr_type(init_expr)==IVL_EX_ARRAY_PATTERN) { - int idx; + unsigned idx; switch (ivl_type_base(element_type)) { case IVL_VT_BOOL: for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) { @@ -157,6 +157,7 @@ static int eval_class_new(ivl_expr_t ex) static int eval_object_null(ivl_expr_t ex) { + (void)ex; /* Parameter is not used. */ fprintf(vvp_out, " %%null;\n"); return 0; } @@ -166,9 +167,22 @@ static int eval_object_property(ivl_expr_t expr) ivl_signal_t sig = ivl_expr_signal(expr); unsigned pidx = ivl_expr_property_idx(expr); + int idx = 0; + ivl_expr_t idx_expr = 0; + + /* If there is an array index expression, then this is an + array'ed property, and we need to calculate the index for + the expression. */ + if ( (idx_expr = ivl_expr_oper1(expr)) ) { + idx = allocate_word(); + draw_eval_expr_into_integer(idx_expr, idx); + } + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); - fprintf(vvp_out, " %%prop/obj %u;\n", pidx); + fprintf(vvp_out, " %%prop/obj %u, %d; eval_object_property\n", pidx, idx); fprintf(vvp_out, " %%pop/obj 1, 1;\n"); + + if (idx != 0) clr_word(idx); return 0; } @@ -189,10 +203,25 @@ static int eval_object_shallowcopy(ivl_expr_t ex) return 0; } -static int eval_object_signal(ivl_expr_t ex) +static int eval_object_signal(ivl_expr_t expr) { - ivl_signal_t sig = ivl_expr_signal(ex); - fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + ivl_signal_t sig = ivl_expr_signal(expr); + + /* Simple case: This is a simple variable. Generate a load + statement to load the string into the stack. */ + if (ivl_signal_dimensions(sig) == 0) { + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + return 0; + } + + /* There is a word select expression, so load the index into a + register and load from the array. */ + 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/obja v%p, %d;\n", sig, word_ix); + clr_word(word_ix); + return 0; } @@ -234,7 +263,7 @@ int draw_eval_object(ivl_expr_t ex) return eval_object_ufunc(ex); default: - fprintf(vvp_out, "; ERROR: draw_eval_object: Invalid expression type %u\n", ivl_expr_type(ex)); + fprintf(vvp_out, "; ERROR: draw_eval_object: Invalid expression type %d\n", ivl_expr_type(ex)); return 1; } diff --git a/tgt-vvp/eval_string.c b/tgt-vvp/eval_string.c index 723d1faee..f0e631324 100644 --- a/tgt-vvp/eval_string.c +++ b/tgt-vvp/eval_string.c @@ -104,7 +104,7 @@ static void string_ex_select(ivl_expr_t 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); + assert(ivl_signal_data_type(sig) == IVL_VT_DARRAY || ivl_signal_data_type(sig) == IVL_VT_QUEUE); draw_eval_expr_into_integer(shift, 3); fprintf(vvp_out, " %%load/dar/str v%p_0;\n", sig); @@ -150,6 +150,22 @@ static void string_ex_substr(ivl_expr_t expr) clr_word(arg2); } +static void string_ex_pop(ivl_expr_t expr) +{ + const char*fb; + ivl_expr_t arg; + + if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_back")==0) + fb = "b"; + else + fb = "f"; + + arg = ivl_expr_parm(expr, 0); + assert(ivl_expr_type(arg) == IVL_EX_SIGNAL); + + fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg)); +} + void draw_eval_string(ivl_expr_t expr) { @@ -177,6 +193,10 @@ void draw_eval_string(ivl_expr_t expr) case IVL_EX_SFUNC: if (strcmp(ivl_expr_name(expr), "$ivl_string_method$substr") == 0) string_ex_substr(expr); + else if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_back")==0) + string_ex_pop(expr); + else if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_front")==0) + string_ex_pop(expr); else fallback_eval(expr); break; diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index c4cb9538b..d729d8efc 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 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 @@ -314,7 +314,11 @@ static ivl_type_t draw_lval_expr(ivl_lval_t lval) } assert(ivl_type_base(sub_type) == IVL_VT_CLASS); - fprintf(vvp_out, " %%prop/obj %d;\n", ivl_lval_property_idx(lval)); + if (ivl_lval_idx(lval)) { + fprintf(vvp_out, " ; XXXX Don't know how to handle ivl_lval_idx values here.\n"); + } + + fprintf(vvp_out, " %%prop/obj %d, 0; draw_lval_expr\n", ivl_lval_property_idx(lval)); fprintf(vvp_out, " %%pop/obj 1, 1;\n"); return ivl_type_prop_type(sub_type, ivl_lval_property_idx(lval)); } @@ -401,7 +405,7 @@ static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid) fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); draw_eval_expr_into_integer(word_ix, 3); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); - fprintf(vvp_out, " %%ix/mov 1, %u;\n", part_off_reg); + fprintf(vvp_out, " %%ix/mov 1, %d;\n", part_off_reg); clr_word(part_off_reg); } else { draw_eval_expr_into_integer(part_off_ex, 1); @@ -981,6 +985,30 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net) return errors; } +static int show_stmt_assign_sig_queue(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 var= ivl_lval_sig(lval); + ivl_type_t var_type= ivl_signal_net_type(var); + assert(ivl_type_base(var_type) == IVL_VT_QUEUE); + + switch (ivl_expr_type(rval)) { + case IVL_EX_NULL: + errors += draw_eval_object(rval); + break; + default: + fprintf(stderr, "XXXX: I don't know how to handle expr_type=%d here\n", ivl_expr_type(rval)); + fprintf(vvp_out, " ; XXXX expr_type=%d\n", ivl_expr_type(rval)); + errors += 1; + break; + } + + 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; @@ -1040,22 +1068,33 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) } else if (ivl_type_base(prop_type) == IVL_VT_DARRAY) { + int idx = 0; + /* The property is a darray, and there is no mux expression to the assignment is of an entire array object. */ fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); draw_eval_object(rval); - fprintf(vvp_out, " %%store/prop/obj %d;\n", prop_idx); + fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY\n", prop_idx, idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_CLASS) { + int idx = 0; + ivl_expr_t idx_expr; + if ( (idx_expr = ivl_lval_idx(lval)) ) { + idx = allocate_word(); + } + /* The property is a class object. */ fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); draw_eval_object(rval); - fprintf(vvp_out, " %%store/prop/obj %d;\n", prop_idx); + if (idx_expr) draw_eval_expr_into_integer(idx_expr, idx); + fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_CLASS\n", prop_idx, idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + if (idx_expr) clr_word(idx); + } else { fprintf(vvp_out, " ; ERROR: ivl_type_base(prop_type) = %d\n", ivl_type_base(prop_type)); @@ -1067,7 +1106,19 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) 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); + + if (ivl_signal_array_count(sig) > 1) { + unsigned ix; + ivl_expr_t aidx = ivl_lval_idx(lval); + + draw_eval_expr_into_integer(aidx, (ix = allocate_word())); + fprintf(vvp_out, " %%store/obja v%p, %u;\n", sig, ix); + clr_word(ix); + + } else { + /* Not an array, so no index expression */ + fprintf(vvp_out, " %%store/obj v%p_0;\n", sig); + } } return errors; @@ -1095,6 +1146,10 @@ int show_stmt_assign(ivl_statement_t net) return show_stmt_assign_sig_darray(net); } + if (sig && (ivl_signal_data_type(sig) == IVL_VT_QUEUE)) { + return show_stmt_assign_sig_queue(net); + } + if (sig && (ivl_signal_data_type(sig) == IVL_VT_CLASS)) { return show_stmt_assign_sig_cobject(net); } diff --git a/tgt-vvp/vector.c b/tgt-vvp/vector.c index feba2d85f..05f186fe4 100644 --- a/tgt-vvp/vector.c +++ b/tgt-vvp/vector.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2014 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 @@ -33,7 +33,7 @@ static struct allocation_score_s { unsigned exp_bit : 24; unsigned sig_bit : 24; unsigned alloc : 8; -} allocation_map[MAX_VEC] = { {0} }; +} allocation_map[MAX_VEC] = { {0, 0, 0, 0, 0, 0} }; /* This is the largest bit to have lookaside values. */ static unsigned lookaside_top = 0; diff --git a/tgt-vvp/vvp_config.h.in b/tgt-vvp/vvp_config.h.in index 6f9f029cf..0644e7e74 100644 --- a/tgt-vvp/vvp_config.h.in +++ b/tgt-vvp/vvp_config.h.in @@ -1,7 +1,7 @@ -#ifndef __vvp_config_H -#define __vvp_config_H +#ifndef IVL_vvp_config_H +#define IVL_vvp_config_H /* - * Copyright (c) 2004-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2014 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 @@ -33,4 +33,4 @@ # undef _LARGEFILE_SOURCE # undef _LARGEFILE64_SOURCE -#endif /* __vvp_config_H */ +#endif /* IVL_vvp_config_H */ diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 0a86200b2..645ff6faf 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -1,7 +1,7 @@ -#ifndef __vvp_priv_H -#define __vvp_priv_H +#ifndef IVL_vvp_priv_H +#define IVL_vvp_priv_H /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -103,6 +103,7 @@ extern int draw_func_definition(ivl_scope_t scope); extern int draw_scope(ivl_scope_t scope, ivl_scope_t parent); extern void draw_lpm_mux(ivl_lpm_t net); +extern void draw_lpm_substitute(ivl_lpm_t net); extern void draw_ufunc_vec4(ivl_expr_t expr); extern void draw_ufunc_real(ivl_expr_t expr); @@ -177,7 +178,7 @@ struct vvp_nexus_data { * cache it. */ extern const char* draw_net_input(ivl_nexus_t nex); -void EOC_cleanup_drivers(); +void EOC_cleanup_drivers(void); /* * This is different from draw_net_input in that it is intended to be @@ -362,4 +363,4 @@ extern void clr_flag(int idx); extern unsigned local_count; extern unsigned thread_count; -#endif +#endif /* IVL_vvp_priv_H */ diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index a4d006de1..7f0b5bfa8 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -57,7 +57,7 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix, /* This code is common to all the different types of array delays. */ if (number_is_immediate(word_ix, IMM_WID, 0) && !number_is_unknown(word_ix)) { - fprintf(vvp_out, " %%ix/load %u, %lu, 0; address\n", + fprintf(vvp_out, " %%ix/load %d, %ld, 0; address\n", word_ix_reg, get_number_immediate(word_ix)); } else { /* Calculate array word index into index register 3 */ @@ -74,7 +74,7 @@ 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, " %%ix/mov 3, %u;\n", word_ix_reg); + fprintf(vvp_out, " %%ix/mov 3, %d;\n", word_ix_reg); fprintf(vvp_out, " %%assign/ar/d v%p, %d;\n", lsig, delay_index); clr_word(word_ix_reg); @@ -152,6 +152,7 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, fprintf(vvp_out, " %%flag_or %d, 4;\n", error_flag); } else if (part_off != 0) { + /* Store word part select into part_off_reg */ part_off_reg = allocate_word(); fprintf(vvp_out, " %%ix/load %d, %lu, 0; part off\n", @@ -169,6 +170,7 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, } fprintf(vvp_out, " %%assign/vec4/a/d v%p, %d, %d;\n", lsig, part_off_reg, delay_index); + clr_word(delay_index); } else if (nevents != 0) { @@ -411,7 +413,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 %u \"%s\";\n", + fprintf(vvp_out, " %%file_line %u %u \"%s\";\n", ivl_file_table_index(ivl_stmt_file(net)), lineno, desc); } } @@ -1367,6 +1369,8 @@ static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope) int rc = 0; ivl_scope_t target = ivl_stmt_call(net); + (void)sscope; /* Parameter is not used. */ + /* A normal disable statement. */ if (target) { show_stmt_file_line(net, "Disable statement."); @@ -1544,6 +1548,7 @@ static int show_stmt_free(ivl_statement_t net) */ static int show_stmt_noop(ivl_statement_t net) { + (void)net; /* Parameter is not used. */ return 0; } @@ -1791,6 +1796,54 @@ static int show_delete_method(ivl_statement_t net) return 0; } +static int show_push_frontback_method(ivl_statement_t net) +{ + const char*stmt_name = ivl_stmt_name(net); + + show_stmt_file_line(net, "queue: push_back"); + + const char*type_code = "?"; + if (strcmp(stmt_name,"$ivl_queue_method$push_front") == 0) + type_code = "qf"; + else if (strcmp(stmt_name,"$ivl_queue_method$push_back") == 0) + type_code = "qb"; + else + type_code = "??"; + + unsigned parm_count = ivl_stmt_parm_count(net); + if (parm_count != 2) + return 1; + + ivl_expr_t parm0 = ivl_stmt_parm(net,0); + assert(ivl_expr_type(parm0) == IVL_EX_SIGNAL); + ivl_signal_t var = ivl_expr_signal(parm0); + ivl_type_t var_type = ivl_signal_net_type(var); + assert(ivl_type_base(var_type)== IVL_VT_QUEUE); + + ivl_type_t element_type = ivl_type_element(var_type); + + ivl_expr_t parm1 = ivl_stmt_parm(net,1); + struct vector_info vec; + switch (ivl_type_base(element_type)) { + case IVL_VT_REAL: + draw_eval_real(parm1); + fprintf(vvp_out, " %%store/%s/r v%p_0;\n", type_code, var); + break; + case IVL_VT_STRING: + draw_eval_string(parm1); + fprintf(vvp_out, " %%store/%s/str v%p_0;\n", type_code, var); + break; + default: + vec = draw_eval_expr_wid(parm1, width_of_packed_type(element_type), STUFF_OK_RO); + fprintf(vvp_out, " %%set/%s v%p_0, %u, %u;\n", + type_code, var, vec.base, vec.wid); + if (vec.base >= 4) clr_vector(vec); + break; + } + + return 0; +} + static int show_system_task_call(ivl_statement_t net) { const char*stmt_name = ivl_stmt_name(net); @@ -1798,6 +1851,12 @@ static int show_system_task_call(ivl_statement_t net) if (strcmp(stmt_name,"$ivl_darray_method$delete") == 0) return show_delete_method(net); + if (strcmp(stmt_name,"$ivl_queue_method$push_front") == 0) + return show_push_frontback_method(net); + + if (strcmp(stmt_name,"$ivl_queue_method$push_back") == 0) + return show_push_frontback_method(net); + show_stmt_file_line(net, "System task call."); draw_vpi_task_call(net); @@ -1827,6 +1886,8 @@ static unsigned is_delayed_or_event_assign(ivl_scope_t scope, ivl_expr_t rval; ivl_signal_t lsig, rsig; + (void)scope; /* Parameter is not used. */ + /* We must have two block elements. */ if (ivl_stmt_block_count(stmt) != 2) return 0; /* The first must be an assign. */ @@ -1892,6 +1953,8 @@ static unsigned is_repeat_event_assign(ivl_scope_t scope, ivl_expr_t rval; ivl_signal_t lsig, rsig; + (void)scope; /* Parameter is not used. */ + /* We must have three block elements. */ if (ivl_stmt_block_count(stmt) != 3) return 0; /* The first must be an assign. */ @@ -1953,6 +2016,9 @@ static unsigned is_wait(ivl_scope_t scope, ivl_statement_t stmt) ivl_statement_t while_wait, wait_x, wait_stmt; ivl_expr_t while_expr, expr; const char *bits; + + (void)scope; /* Parameter is not used. */ + /* We must have two block elements. */ if (ivl_stmt_block_count(stmt) != 2) return 0; /* The first must be a while. */ @@ -2093,6 +2159,9 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope, unsigned lineno = ivl_stmt_lineno(stmt); ivl_scope_t task_scope = 0; port_expr_t port_exprs; + + (void)scope; /* Parameter is not used. */ + /* Check to see if the block is of the basic form first. */ for (idx = 0; idx < count; idx += 1) { ivl_statement_t tmp = ivl_stmt_block_stmt(stmt, idx); @@ -2324,6 +2393,8 @@ int draw_process(ivl_process_t net, void*x) int push_flag = 0; + (void)x; /* Parameter is not used. */ + for (idx = 0 ; idx < ivl_process_attr_cnt(net) ; idx += 1) { ivl_attribute_t attr = ivl_process_attr_val(net, idx); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 7a8632367..b2779f379 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -134,7 +134,7 @@ const char* vvp_signal_label(ivl_signal_t sig) return buf; } -ivl_signal_t signal_of_nexus(ivl_nexus_t nex, unsigned*word) +static ivl_signal_t signal_of_nexus(ivl_nexus_t nex, unsigned*word) { unsigned idx; for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) { @@ -180,7 +180,7 @@ ivl_variable_type_t data_type_of_nexus(ivl_nexus_t nex) } -ivl_nexus_ptr_t ivl_logic_pin_ptr(ivl_net_logic_t net, unsigned pin) +static ivl_nexus_ptr_t ivl_logic_pin_ptr(ivl_net_logic_t net, unsigned pin) { ivl_nexus_t nex = ivl_logic_pin(net, pin); unsigned idx; @@ -201,6 +201,7 @@ ivl_nexus_ptr_t ivl_logic_pin_ptr(ivl_net_logic_t net, unsigned pin) return 0; } +#if 0 const char*drive_string(ivl_drive_t drive) { switch (drive) { @@ -224,6 +225,7 @@ const char*drive_string(ivl_drive_t drive) return ""; } +#endif /* @@ -467,6 +469,10 @@ static void draw_reg_in_scope(ivl_signal_t sig) datatype_flag = "/str"; vector_dims = 0; break; + case IVL_VT_CLASS: + datatype_flag = "/obj"; + vector_dims = 0; + break; default: break; } @@ -501,6 +507,11 @@ static void draw_reg_in_scope(ivl_signal_t sig) vvp_mangle_name(ivl_signal_basename(sig)), ivl_signal_local(sig)? " Local signal" : ""); + } else if (ivl_signal_data_type(sig) == IVL_VT_QUEUE) { + fprintf(vvp_out, "v%p_0 .var/queue \"%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)), @@ -784,14 +795,14 @@ static void draw_udp_def(ivl_udp_t udp) if (ivl_udp_sequ(udp)) fprintf(vvp_out, - "UDP_%s .udp/sequ \"%s\", %d, %u", + "UDP_%s .udp/sequ \"%s\", %u, %u", vvp_mangle_id(ivl_udp_name(udp)), vvp_mangle_name(ivl_udp_name(udp)), ivl_udp_nin(udp), init ); else fprintf(vvp_out, - "UDP_%s .udp/comb \"%s\", %d", + "UDP_%s .udp/comb \"%s\", %u", vvp_mangle_id(ivl_udp_name(udp)), vvp_mangle_name(ivl_udp_name(udp)), ivl_udp_nin(udp)); @@ -1038,7 +1049,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) break; default: - fprintf(stderr, "vvp.tgt: error: Unhandled logic type: %u\n", + fprintf(stderr, "vvp.tgt: error: Unhandled logic type: %d\n", ivl_logic_type(lptr)); ltype = "?"; break; @@ -1280,6 +1291,8 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net, ivl_variable_type_t dt) switch (ivl_lpm_type(net)) { case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: @@ -1489,6 +1502,16 @@ static void draw_lpm_cmp(ivl_lpm_t net) type = "eq"; signed_string = ""; break; + case IVL_LPM_CMP_EQX: + assert(dtc != IVL_VT_REAL); + type = "eqx"; + signed_string = ""; + break; + case IVL_LPM_CMP_EQZ: + assert(dtc != IVL_VT_REAL); + type = "eqz"; + signed_string = ""; + break; case IVL_LPM_CMP_GE: if (dtc == IVL_VT_REAL) { type = "ge.r"; @@ -1712,10 +1735,16 @@ static void draw_lpm_ff(ivl_lpm_t net) * generator in V0.10 and later for how this might be done. */ assert(ivl_lpm_sync_clr(net) == 0); assert(ivl_lpm_sync_set(net) == 0); - assert(ivl_lpm_async_clr(net) == 0); - assert(ivl_lpm_async_set(net) == 0); - fprintf(vvp_out, "L_%p .dff ", net); + if (ivl_lpm_async_clr(net)) { + assert(! ivl_lpm_async_set(net)); + fprintf(vvp_out, "L_%p .dff/aclr ", net); + } else if (ivl_lpm_async_set(net)) { + assert(! ivl_lpm_async_clr(net)); + fprintf(vvp_out, "L_%p .dff/aset ", net); + } else { + fprintf(vvp_out, "L_%p .dff ", net); + } nex = ivl_lpm_data(net,0); assert(nex); @@ -1735,8 +1764,13 @@ static void draw_lpm_ff(ivl_lpm_t net) fprintf(vvp_out, ", C4<1>"); } - /* Stub asynchronous input for now. */ - fprintf(vvp_out, ", C4"); + if ( (nex = ivl_lpm_async_clr(net)) ) { + fprintf(vvp_out, ", %s", draw_net_input(nex)); + } + + if ( (nex = ivl_lpm_async_set(net)) ) { + fprintf(vvp_out, ", %s", draw_net_input(nex)); + } fprintf(vvp_out, ";\n"); } @@ -1768,7 +1802,7 @@ static void draw_type_string_of_nex(ivl_nexus_t nex) break; case IVL_VT_LOGIC: case IVL_VT_BOOL: - fprintf(vvp_out, "v%d", width_of_nexus(nex)); + fprintf(vvp_out, "v%u", width_of_nexus(nex)); break; default: assert(0); @@ -1804,7 +1838,7 @@ static int sfunc_has_modpath_output(ivl_lpm_t lptr) static void draw_sfunc_output_def(ivl_lpm_t net, char type) { ivl_nexus_t nex = ivl_lpm_q(net); - char *suf = (type == 'd') ? "/d" : ""; + const char *suf = (type == 'd') ? "/d" : ""; switch (data_type_of_nexus(nex)) { case IVL_VT_REAL: @@ -2060,6 +2094,8 @@ static void draw_lpm_in_scope(ivl_lpm_t net) case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: + case IVL_LPM_CMP_EQX: + case IVL_LPM_CMP_EQZ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: @@ -2107,6 +2143,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net) draw_lpm_sfunc(net); return; + case IVL_LPM_SUBSTITUTE: + draw_lpm_substitute(net); + return; + case IVL_LPM_UFUNC: draw_lpm_ufunc(net); return; @@ -2150,13 +2190,15 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) default: type = "?"; assert(0); } - fprintf(vvp_out, "S_%p .scope %s%s, \"%s\" \"%s\" %d %d", - net, prefix, type, vvp_mangle_name(ivl_scope_basename(net)), - ivl_scope_tname(net), ivl_file_table_index(ivl_scope_file(net)), + fprintf(vvp_out, "S_%p .scope %s%s, \"%s\" \"%s\" %u %u", + net, prefix, type, + vvp_mangle_name(ivl_scope_basename(net)), + vvp_mangle_name(ivl_scope_tname(net)), + ivl_file_table_index(ivl_scope_file(net)), ivl_scope_lineno(net)); if (parent) { - fprintf(vvp_out, ", %d %d %u, S_%p;\n", + fprintf(vvp_out, ", %u %u %u, S_%p;\n", ivl_file_table_index(ivl_scope_def_file(net)), ivl_scope_def_lineno(net), ivl_scope_is_cell(net), parent); } else { @@ -2177,7 +2219,8 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) if( name == 0 ) name = ""; fprintf( vvp_out, " .port_info %u %s %u \"%s\"\n", - idx, vvp_port_info_type_str(ptype), width, name ); + idx, vvp_port_info_type_str(ptype), width, + vvp_mangle_name(name) ); } } @@ -2186,16 +2229,16 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) 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 %d, \"%s\";\n", - par, ivl_parameter_basename(par), + fprintf(vvp_out, "P_%p .param/str \"%s\" %d %u %u, \"%s\";\n", + par, vvp_mangle_name(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 %d, %sC4<", - par, ivl_parameter_basename(par), + fprintf(vvp_out, "P_%p .param/l \"%s\" %d %u %u, %sC4<", + par, vvp_mangle_name(ivl_parameter_basename(par)), ivl_parameter_local(par), ivl_file_table_index(ivl_parameter_file(par)), ivl_parameter_lineno(par), @@ -2210,9 +2253,10 @@ 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 %d, %s; " - "value=%#g\n", par, ivl_parameter_basename(par), - ivl_parameter_local(par), + fprintf(vvp_out, "P_%p .param/real \"%s\" %d %u %u, %s; " + "value=%#g\n", par, + vvp_mangle_name(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)); diff --git a/util.h b/util.h index 4e66fc708..d94919af5 100644 --- a/util.h +++ b/util.h @@ -1,7 +1,7 @@ -#ifndef __util_H -#define __util_H +#ifndef IVL_util_H +#define IVL_util_H /* - * Copyright (c) 2000-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -47,4 +47,4 @@ extern attrib_list_t* evaluate_attributes(const map&att, unsigned&natt, Design*des, NetScope*scope); -#endif +#endif /* IVL_util_H */ diff --git a/verilog.spec b/verilog.spec index 21ef8d295..5e6cb89bb 100644 --- a/verilog.spec +++ b/verilog.spec @@ -1,6 +1,6 @@ #norootforbuild # -%define rev_date 20130827 +%define rev_date 20140801 # 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 diff --git a/verinum.h b/verinum.h index f6b3626c5..e7f311920 100644 --- a/verinum.h +++ b/verinum.h @@ -1,5 +1,5 @@ -#ifndef __verinum_H -#define __verinum_H +#ifndef IVL_verinum_H +#define IVL_verinum_H /* * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) * @@ -199,4 +199,4 @@ extern verinum concat(const verinum&left, const verinum&right); /* Bitwise not returns the ones complement. */ extern verinum operator ~ (const verinum&left); -#endif +#endif /* IVL_verinum_H */ diff --git a/verireal.h b/verireal.h index 1538add19..a7be1555f 100644 --- a/verireal.h +++ b/verireal.h @@ -1,7 +1,7 @@ -#ifndef __verireal_H -#define __verireal_H +#ifndef IVL_verireal_H +#define IVL_verireal_H /* - * Copyright (c) 1999-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -82,4 +82,4 @@ extern verireal operator% (const verireal&, const verinum&); extern verireal pow(const verireal&, const verireal&); extern verireal operator- (const verireal&); -#endif +#endif /* IVL_verireal_H */ diff --git a/veriuser.h b/veriuser.h index 6d08dceff..7e061c16f 100644 --- a/veriuser.h +++ b/veriuser.h @@ -1,7 +1,7 @@ -#ifndef __veriuser_H -#define __veriuser_H +#ifndef VERIUSER_H +#define VERIUSER_H /* - * Copyright (c) 2002-2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2014 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 @@ -354,4 +354,4 @@ extern void tf_warning(const char*, ...) EXTERN_C_END -#endif +#endif /* VERIUSER_H */ diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index da356cc13..e3622a7c3 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -51,7 +51,6 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../libmisc endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ @EXTRALIBS@ @@ -86,7 +85,11 @@ distclean: clean rm -f stamp-vhdlpp_config-h vhdlpp_config.h cppcheck: $(O:.o=.cc) - cppcheck --enable=all -f $(INCLUDE_PATH) $^ + cppcheck --enable=all -f \ + -UYY_USER_INIT \ + -UYYPARSE_PARAM -UYYPRINT -Ushort -Usize_t -Uyyoverflow \ + -UYYTYPE_INT8 -UYYTYPE_INT16 -UYYTYPE_UINT8 -UYYTYPE_UINT16 \ + $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in cd ..; ./config.status --file=vhdlpp/$@ diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 594f350eb..117038eab 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -1,7 +1,7 @@ -#ifndef __architec_H -#define __architec_H +#ifndef IVL_architec_H +#define IVL_architec_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 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 @@ -230,4 +230,4 @@ class ProcessStatement : public Architecture::Statement { }; -#endif +#endif /* IVL_architec_H */ diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 3ffc8c6da..c255df43a 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -41,6 +41,24 @@ int Architecture::elaborate(Entity*entity) cur->second->val->elaborate_expr(entity, this, cur->second->typ); } + // Elaborate initializer expressions for signals & variables + for (map::iterator cur = old_signals_.begin() + ; cur != old_signals_.end() ; ++cur) { + cur->second->elaborate_init_expr(entity, this); + } + for (map::iterator cur = new_signals_.begin() + ; cur != new_signals_.end() ; ++cur) { + cur->second->elaborate_init_expr(entity, this); + } + for (map::iterator cur = old_variables_.begin() + ; cur != old_variables_.end() ; ++cur) { + cur->second->elaborate_init_expr(entity, this); + } + for (map::iterator cur = new_variables_.begin() + ; cur != new_variables_.end() ; ++cur) { + cur->second->elaborate_init_expr(entity, this); + } + for (list::iterator cur = statements_.begin() ; cur != statements_.end() ; ++cur) { diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 21d65b7f2..ef17e370a 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -21,6 +21,7 @@ # include "entity.h" # include "expression.h" # include "sequential.h" +# include "subprogram.h" # include "vsignal.h" # include # include @@ -69,14 +70,17 @@ int Architecture::emit(ostream&out, Entity*entity) // of the full definition. typedef_context_t typedef_ctx; + for (map::iterator cur = use_types_.begin() + ; cur != use_types_.end() ; ++cur) { + + if(const VTypeDef*def = dynamic_cast(cur->second)) + errors += def->emit_typedef(out, typedef_ctx); + } for (map::iterator cur = cur_types_.begin() ; cur != cur_types_.end() ; ++cur) { - const VTypeDef*def = dynamic_cast(cur->second); - if (def == 0) - continue; - - errors += def->emit_typedef(out, typedef_ctx); + if(const VTypeDef*def = dynamic_cast(cur->second)) + errors += def->emit_typedef(out, typedef_ctx); } for (map::iterator cur = use_constants_.begin() diff --git a/vhdlpp/compiler.h b/vhdlpp/compiler.h index 380ca0f01..3cd1b820a 100644 --- a/vhdlpp/compiler.h +++ b/vhdlpp/compiler.h @@ -1,7 +1,7 @@ -#ifndef __compiler_H -#define __compiler_H +#ifndef IVL_compiler_H +#define IVL_compiler_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -34,8 +34,4 @@ extern StringHeapLex lex_strings; extern StringHeapLex filename_strings; -extern void library_set_work_path(const char*work_path); -extern void library_add_directory(const char*directory); -extern int emit_packages(void); - -#endif +#endif /* IVL_compiler_H */ diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index a6f9542b9..9a389d2ae 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2014 CERN / Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -22,6 +23,7 @@ # include "architec.h" # include "expression.h" # include "parse_types.h" +# include "subprogram.h" # include "sequential.h" # include "vsignal.h" # include "vtype.h" @@ -335,6 +337,12 @@ void ExpInteger::dump(ostream&out, int indent) const << " at " << get_fileline() << endl; } +void ExpReal::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Integer " << value_ + << " at " << get_fileline() << endl; +} + void ExpLogical::dump(ostream&out, int indent) const { const char*fun_name = "?"; @@ -460,6 +468,12 @@ ostream& ExpInteger::dump_inline(ostream&out) const return out; } +ostream& ExpReal::dump_inline(ostream&out) const +{ + out << value_; + return out; +} + void Subprogram::dump(ostream&fd) const { fd << " " << name_; diff --git a/vhdlpp/entity.cc b/vhdlpp/entity.cc index 4df745412..4d92f7ddc 100644 --- a/vhdlpp/entity.cc +++ b/vhdlpp/entity.cc @@ -47,9 +47,12 @@ void ComponentBase::set_interface(std::list*parms, parms->pop_front(); } } - while (! ports->empty()) { - ports_.push_back(ports->front()); - ports->pop_front(); + + if (ports) { + while (! ports->empty()) { + ports_.push_back(ports->front()); + ports->pop_front(); + } } } diff --git a/vhdlpp/entity.h b/vhdlpp/entity.h index 5e37bca4b..b93d6a369 100644 --- a/vhdlpp/entity.h +++ b/vhdlpp/entity.h @@ -1,7 +1,7 @@ -#ifndef __entity_H -#define __entity_H +#ifndef IVL_entity_H +#define IVL_entity_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 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 @@ -147,4 +147,4 @@ extern int emit_entities(void); */ extern void dump_design_entities(ostream&file); -#endif +#endif /* IVL_entity_H */ diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 74e143c63..feeddd88e 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -1,6 +1,7 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) - * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2014 / Stephen Williams (steve@icarus.com), + * Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -297,6 +298,15 @@ bool ExpInteger::evaluate(ScopeBase*, int64_t&val) const return true; } +ExpReal::ExpReal(double val) +: value_(val) +{ +} + +ExpReal::~ExpReal() +{ +} + ExpLogical::ExpLogical(ExpLogical::fun_t ty, Expression*op1, Expression*op2) : ExpBinary(op1, op2), fun_(ty) { diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index e5c143e3e..b791f9a21 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -1,8 +1,9 @@ -#ifndef __expression_H -#define __expression_H +#ifndef IVL_expression_H +#define IVL_expression_H /* - * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) - * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) + * Copyright CERN 2014 / Stephen Williams (steve@icarus.com), + * Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -282,7 +283,9 @@ class ExpAggregate : public Expression { private: int elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype); + int elaborate_expr_record_(Entity*ent, Architecture*arc, const VTypeRecord*ltype); int emit_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*ltype); + int emit_record_(ostream&out, Entity*ent, Architecture*arc, const VTypeRecord*ltype); private: // This is the elements as directly parsed. @@ -385,6 +388,7 @@ class ExpConcat : public Expression { ~ExpConcat(); 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); @@ -462,6 +466,7 @@ class ExpEdge : public ExpUnary { private: fun_t fun_; }; + class ExpFunc : public Expression { public: @@ -505,6 +510,25 @@ class ExpInteger : public Expression { int64_t value_; }; +class ExpReal : public Expression { + + public: + ExpReal(double val); + ~ExpReal(); + + 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); + int emit_package(std::ostream&out); + bool is_primary(void) const; + void dump(ostream&out, int indent = 0) const; + virtual ostream& dump_inline(ostream&out) const; + + private: + double value_; +}; + class ExpLogical : public ExpBinary { public: @@ -554,6 +578,7 @@ class ExpName : public Expression { bool symbolic_compare(const Expression*that) const; void dump(ostream&out, int indent = 0) const; const char* name() const; + inline perm_string peek_name() const { return name_; } void set_range(Expression*msb, Expression*lsb); @@ -617,6 +642,7 @@ class ExpString : public Expression { int emit(ostream&out, Entity*ent, Architecture*arc); bool is_primary(void) const; void dump(ostream&out, int indent = 0) const; + const std::vector& get_value() const { return value_; } private: int emit_as_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*arr); @@ -648,4 +674,4 @@ class ExpUNot : public ExpUnary { void dump(ostream&out, int indent = 0) const; }; -#endif +#endif /* IVL_expression_H */ diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index df0935d5d..b07ff6994 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -23,6 +23,8 @@ # include "architec.h" # include "entity.h" # include "vsignal.h" +# include "subprogram.h" +# include "library.h" # include # include # include "parse_types.h" @@ -56,6 +58,10 @@ const VType* Expression::fit_type(Entity*ent, Architecture*arc, const VTypeArray const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, Architecture*arc, const VType*type) { + // Unfold typedefs + while (const VTypeDef*tdef = dynamic_cast(type)) { + type = tdef->peek_definition(); + } if (const VTypeArray*array = dynamic_cast(type)) { if (index_ && !lsb_) { @@ -411,6 +417,9 @@ int ExpAggregate::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype if (const VTypeArray*larray = dynamic_cast(ltype)) { return elaborate_expr_array_(ent, arc, larray); } + else if(const VTypeRecord*lrecord = dynamic_cast(ltype)) { + return elaborate_expr_record_(ent, arc, lrecord); + } cerr << get_fileline() << ": internal error: I don't know how to elaborate aggregate expressions. type=" << typeid(*ltype).name() << endl; return 1; @@ -476,6 +485,46 @@ int ExpAggregate::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTyp return errors; } +int ExpAggregate::elaborate_expr_record_(Entity*ent, Architecture*arc, const VTypeRecord*ltype) +{ + int errors = 0; + + aggregate_.resize(elements_.size()); + choice_element tmp; + int idx; + + // Translate the elements_ array to the aggregate_ array. In + // the target array, each expression is attached to a single + // choice. + for (size_t edx = 0 ; edx < elements_.size() ; edx += 1) { + element_t*ecur = elements_[edx]; + + // it is invalid to have more than one choice in record assignment + ivl_assert(*this, ecur->count_choices() == 1); + + ecur->map_choices(&tmp); + choice_t*ch = tmp.choice; + + ivl_assert(*this, !ch->others()); + ivl_assert(*this, !tmp.alias_flag); + + // Get the appropriate type for a field + const ExpName*field = dynamic_cast(ch->simple_expression(false)); + ivl_assert(*this, field); + + perm_string field_name = field->peek_name(); + const VTypeRecord::element_t*el = ltype->element_by_name(field_name, &idx); + + aggregate_[idx] = tmp; + errors += aggregate_[idx].expr->elaborate_expr(ent, arc, el->peek_type()); + } + + // done with the obsolete elements_ vector. + elements_.clear(); + + return errors; +} + void ExpAggregate::element_t::map_choices(ExpAggregate::choice_element*dst) { for (size_t idx = 0 ; idx < fields_.size() ; idx += 1) { @@ -518,8 +567,8 @@ const VType* ExpAttribute::probe_type(Entity*ent, Architecture*arc) const { base_->probe_type(ent, arc); - if (name_ == "length") { - return primitive_INTEGER; + if (name_ == "length" || name_ == "left" || name_ == "right") { + return &primitive_INTEGER; } return 0; @@ -560,6 +609,39 @@ int ExpCharacter::elaborate_expr(Entity*, Architecture*, const VType*ltype) return 0; } +const VType*ExpConcat::fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const +{ + Expression*operands[2] = {operand1_, operand2_}; + const VType*types[2] = {NULL, NULL}; + Expression*sizes[2] = {NULL, NULL}; + + // determine the type and size of concatenated expressions + for(int i = 0; i < 2; ++i) { + types[i] = operands[i]->fit_type(ent, arc, atype); + + if(const VTypeArray*arr = dynamic_cast(types[i])) { + types[i] = arr->element_type(); + ivl_assert(*this, arr->dimensions() == 1); + const VTypeArray::range_t&dim = arr->dimension(0); + sizes[i] = new ExpArithmetic(ExpArithmetic::MINUS, dim.msb(), dim.lsb()); + } else { + sizes[i] = new ExpInteger(0); + } + } + + // the range of the concatenated expression is (size1 + size2 + 1):0 + // note that each of the sizes are already decreased by one, + // e.g. 3:0 <=> size == 3 even though there are 4 bits + Expression*size = new ExpArithmetic(ExpArithmetic::PLUS, + new ExpArithmetic(ExpArithmetic::PLUS, sizes[0], sizes[1]), + new ExpInteger(1)); + + std::list ranges; + ranges.push_front(new prange_t(size, new ExpInteger(0), true)); + const VType*array = new VTypeArray(types[1], &ranges); + + return array; +} /* * I don't know how to probe the type of a concatenation, quite yet. */ @@ -663,11 +745,16 @@ int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*) ivl_assert(*this, arc); Subprogram*prog = arc->find_subprogram(name_); + if(!prog) + prog = library_find_subprogram(name_); + ivl_assert(*this, def_==0); def_ = prog; for (size_t idx = 0 ; idx < argv_.size() ; idx += 1) { const VType*tmp = argv_[idx]->probe_type(ent, arc); + if(!tmp && prog) + tmp = prog->peek_param_type(idx); errors += argv_[idx]->elaborate_expr(ent, arc, tmp); } @@ -676,7 +763,7 @@ int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*) const VType* ExpInteger::probe_type(Entity*, Architecture*) const { - return primitive_INTEGER; + return &primitive_INTEGER; } int ExpInteger::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) @@ -692,6 +779,24 @@ int ExpInteger::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) return errors; } +const VType* ExpReal::probe_type(Entity*, Architecture*) const +{ + return &primitive_REAL; +} + +int ExpReal::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); + + return errors; +} + int ExpLogical::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) { int errors = 0; @@ -807,12 +912,9 @@ const VType* ExpNameALL::probe_type(Entity*, Architecture*) const return 0; } -const VType* ExpRelation::probe_type(Entity*ent, Architecture*arc) const +const VType* ExpRelation::probe_type(Entity*, Architecture*) const { - /* const VType*type1 = */ peek_operand1()->probe_type(ent, arc); - /* const VType*type2 = */ peek_operand2()->probe_type(ent, arc); - - return primitive_BOOLEAN; + return &primitive_BOOLEAN; } int ExpRelation::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index f6cd315d0..2c1e510e5 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -22,6 +22,7 @@ # include "vtype.h" # include "architec.h" # include "package.h" +# include "subprogram.h" # include "parse_types.h" # include # include @@ -95,6 +96,8 @@ int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc) if (const VTypeArray*atype = dynamic_cast (use_type)) return emit_array_(out, ent, arc, atype); + else if (const VTypeRecord*arecord = dynamic_cast (use_type)) + return emit_record_(out, ent, arc, arecord); out << "/* " << get_fileline() << ": internal error: " << "I don't know how to elab/emit aggregate in " << typeid(use_type).name() @@ -159,7 +162,8 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V ivl_assert(*this, rc); rc = rang.lsb()->evaluate(ent, arc, use_lsb); ivl_assert(*this, rc); - ivl_assert(*this, use_msb >= use_lsb); + if(use_msb < use_lsb) + swap(use_msb, use_lsb); map element_map; choice_element*element_other = 0; @@ -244,6 +248,10 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V // 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. + // TODO uncomment this once ivl supports assignments of '{} + /*if(!peek_type()->can_be_packed()) + out << "'";*/ + out << "{"; for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) { choice_element*cur = element_map[idx]; @@ -266,6 +274,34 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V return errors; } +int ExpAggregate::emit_record_(ostream&out, Entity*ent, Architecture*arc, const VTypeRecord*) +{ + int errors = 0; + + out << "{"; + + for (size_t idx = 0 ; idx < aggregate_.size() ; idx += 1) { + ivl_assert(*this, !aggregate_[idx].choice->others()); + ivl_assert(*this, !aggregate_[idx].choice->range_expressions()); + + //Expression*name = aggregate_[idx].choice->simple_expression(false); + //ivl_assert(*this, name); + Expression*val = aggregate_[idx].expr; + ivl_assert(*this, val); + + if(idx != 0) + out << ","; + + //errors += name->emit(out, ent, arc); + //out << ": "; + errors += val->emit(out, ent, arc); + } + + out << "}"; + + return errors; +} + int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; @@ -277,8 +313,8 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } - /* Special Case: The length attribute can be calculated all - the down to a literal integer at compile time, and all it + /* Special Case: The length,left & right attributes can be calculated + all the down to a literal integer at compile time, and all it needs is the type of the base expression. (The base expression doesn't even need to be evaluated.) */ if (name_=="length") { @@ -286,9 +322,13 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) errors += base_->emit(out, ent, arc); out << ")"; return errors; + } else if (name_=="left" || name_=="right") { + out << "$" << name_ << "("; + errors += base_->emit(out, ent, arc); + out << ")"; + return errors; } - out << "$ivl_attribute("; errors += base_->emit(out, ent, arc); out << ", \"" << name_ << "\")"; @@ -351,16 +391,6 @@ int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, Architecture*, switch (etype->type()) { case VTypePrimitive::BOOLEAN: case VTypePrimitive::BIT: - switch (value_) { - case '0': - case '1': - out << "1'b" << value_; - return 0; - default: - break; - } - break; - case VTypePrimitive::STDLOGIC: switch (value_) { case '0': @@ -531,6 +561,11 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) errors += argv_[0]->emit(out, ent, arc); out << ")"; + } else if (name_ == "integer" && argv_.size() == 1) { + // Simply skip the function name, SystemVerilog takes care of + // rounding real numbers + errors += argv_[0]->emit(out, ent, arc); + } else if (name_ == "std_logic_vector" && argv_.size() == 1) { // Special case: The std_logic_vector function casts its // argument to std_logic_vector. Internally, we don't @@ -605,6 +640,23 @@ bool ExpInteger::is_primary(void) const return true; } +int ExpReal::emit(ostream&out, Entity*, Architecture*) +{ + out << value_; + return 0; +} + +int ExpReal::emit_package(ostream&out) +{ + out << value_; + return 0; +} + +bool ExpReal::is_primary(void) const +{ + return true; +} + int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; @@ -745,7 +797,7 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA int errors = 0; assert(arr->dimensions() == 1); - const VTypePrimitive*etype = dynamic_cast (arr->element_type()); + const VTypePrimitive*etype = dynamic_cast (arr->basic_type()); assert(etype); // Detect the special case that this is an array of @@ -774,6 +826,10 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA assert(etype->type() == VTypePrimitive::STDLOGIC); out << "z"; break; + case '-': + assert(etype->type() == VTypePrimitive::STDLOGIC); + out << "x"; + break; default: cerr << get_fileline() << ": internal error: " << "Don't know how to handle bit " << value_[idx] diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 56b631006..2f506eb28 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -110,8 +110,32 @@ bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const return false; } -bool ExpAttribute::evaluate(Entity*, Architecture*arc, int64_t&val) const +bool ExpAttribute::evaluate(Entity*ent, Architecture*arc, int64_t&val) const { + if (name_ == "left" || name_ == "right") { + const VType*base_type = base_->peek_type(); + if (base_type == 0) + base_type = base_->probe_type(ent,arc); + + ivl_assert(*this, base_type); + + const VTypeArray*arr = dynamic_cast(base_type); + if (arr == 0) { + cerr << get_fileline() << ": error: " + << "Cannot apply the '" << name_ + << " attribute to non-array objects" << endl; + return false; + } + + ivl_assert(*this, arr->dimensions() == 1); + if(name_ == "left") + arr->dimension(0).msb()->evaluate(ent, arc, val); + else + arr->dimension(0).lsb()->evaluate(ent, arc, val); + + return true; + } + return evaluate(arc, val); } diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index b8da43179..103e210ae 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -29,6 +29,9 @@ void ExpAggregate::write_to_stream(ostream&fd) fd << "("; for (vector::const_iterator cur = elements_.begin() ; cur != elements_.end() ; ++cur) { + if(cur != elements_.begin()) + fd << ", "; + (*cur)->write_to_stream(fd); } fd << ")"; @@ -41,7 +44,8 @@ void ExpAggregate::element_t::write_to_stream(ostream&fd) const (*cur)->write_to_stream(fd); } - fd << "=>"; + if(!fields_.empty()) + fd << "=>"; val_->write_to_stream(fd); } @@ -107,14 +111,20 @@ void ExpArithmetic::write_to_stream(ostream&out) out << ")"; } -void ExpAttribute::write_to_stream(ostream&) +void ExpAttribute::write_to_stream(ostream&fd) { - ivl_assert(*this, !"Not supported"); + base_->write_to_stream(fd); + fd << "'" << name_; } -void ExpBitstring::write_to_stream(ostream&) +void ExpBitstring::write_to_stream(ostream&fd) { - ivl_assert(*this, !"Not supported"); + fd << "\""; + for(vector::const_iterator it = value_.begin(); + it != value_.end(); ++it) { + fd << *it; + } + fd << "\""; } void ExpCharacter::write_to_stream(ostream&fd) @@ -164,6 +174,11 @@ void ExpInteger::write_to_stream(ostream&fd) fd << value_; } +void ExpReal::write_to_stream(ostream&fd) +{ + fd << value_; +} + void ExpLogical::write_to_stream(ostream&) { ivl_assert(*this, !"Not supported"); @@ -193,9 +208,14 @@ void ExpRelation::write_to_stream(ostream&) ivl_assert(*this, !"Not supported"); } -void ExpString::write_to_stream(ostream&) +void ExpString::write_to_stream(ostream&fd) { - ivl_assert(*this, !"Not supported"); + fd << "\""; + for(vector::const_iterator it = value_.begin(); + it != value_.end(); ++it) { + fd << *it; + } + fd << "\""; } void ExpUAbs::write_to_stream(ostream&fd) diff --git a/vhdlpp/ivl_assert.h b/vhdlpp/ivl_assert.h index 6c4f9c0b9..72812c05f 100644 --- a/vhdlpp/ivl_assert.h +++ b/vhdlpp/ivl_assert.h @@ -1,5 +1,7 @@ +#ifndef IVL_ivl_assert_H +#define IVL_ivl_assert_H /* - * Copyright (c) 2007-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2014 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 @@ -17,9 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __ivl_assert_h -#define __ivl_assert_h - # include #define ivl_assert(tok, expression) \ @@ -32,4 +31,4 @@ } \ } while (0) -#endif +#endif /* IVL_ivl_assert_H */ diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index 2f3fd197b..c9dae5c51 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -409,6 +409,7 @@ static char*make_bitstring_bin(int width_prefix, bool sflag, bool, while (*src) { *rp++ = *src++; } + *rp = 0; return res; } diff --git a/vhdlpp/lexor_keyword.gperf b/vhdlpp/lexor_keyword.gperf index 7b739c80f..647798f27 100644 --- a/vhdlpp/lexor_keyword.gperf +++ b/vhdlpp/lexor_keyword.gperf @@ -96,6 +96,7 @@ rem, GN_KEYWORD_2008, K_rem report, GN_KEYWORD_2008, K_report restrict, GN_KEYWORD_2008, K_restrict return, GN_KEYWORD_2008, K_return +reverse_range, GN_KEYWORD_2008, K_reverse_range rol, GN_KEYWORD_2008, K_rol ror, GN_KEYWORD_2008, K_ror select, GN_KEYWORD_2008, K_select diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 681388647..52943156e 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -69,7 +69,25 @@ void library_add_directory(const char*directory) return; } - library_search_path .push_front(directory); + library_search_path.push_front(directory); +} + +Subprogram*library_find_subprogram(perm_string name) +{ + Subprogram*subp = NULL; + map::const_iterator lib_it; + + for(lib_it = libraries.begin(); lib_it != libraries.end(); ++lib_it) { + const struct library_contents&lib = lib_it->second; + map::const_iterator pack_it; + + for(pack_it = lib.packages.begin(); pack_it != lib.packages.end(); ++pack_it) { + if((subp = pack_it->second->find_subprogram(name))) + return subp; + } + } + + return NULL; } static void store_package_in_work(const Package*pack); @@ -280,7 +298,7 @@ static void import_ieee_use_std_logic_1164(ActiveScope*res, perm_string name) if (all_flag || name == "std_logic_vector") { vector dims (1); res->use_name(perm_string::literal("std_logic_vector"), - new VTypeArray(primitive_STDLOGIC, dims, false)); + new VTypeArray(&primitive_STDLOGIC, dims, false)); } } @@ -295,12 +313,12 @@ static void import_ieee_use_numeric_bit(ActiveScope*res, perm_string name) if (all_flag || name == "signed") { vector dims (1); res->use_name(perm_string::literal("signed"), - new VTypeArray(primitive_STDLOGIC, dims, true)); + new VTypeArray(&primitive_STDLOGIC, dims, true)); } if (all_flag || name == "unsigned") { vector dims (1); res->use_name(perm_string::literal("unsigned"), - new VTypeArray(primitive_BIT, dims, false)); + new VTypeArray(&primitive_BIT, dims, false)); } } @@ -311,12 +329,12 @@ static void import_ieee_use_numeric_std(ActiveScope*res, perm_string name) if (all_flag || name == "signed") { vector dims (1); res->use_name(perm_string::literal("signed"), - new VTypeArray(primitive_STDLOGIC, dims, true)); + new VTypeArray(&primitive_STDLOGIC, dims, true)); } if (all_flag || name == "unsigned") { vector dims (1); res->use_name(perm_string::literal("unsigned"), - new VTypeArray(primitive_STDLOGIC, dims, false)); + new VTypeArray(&primitive_STDLOGIC, dims, false)); } } @@ -343,28 +361,30 @@ static void import_ieee_use(ActiveScope*res, perm_string package, perm_string na } } -const VTypePrimitive* primitive_BOOLEAN = new VTypePrimitive(VTypePrimitive::BOOLEAN); -const VTypePrimitive* primitive_BIT = new VTypePrimitive(VTypePrimitive::BIT); -const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER); -const VTypePrimitive* primitive_STDLOGIC = new VTypePrimitive(VTypePrimitive::STDLOGIC); -const VTypePrimitive* primitive_CHARACTER= new VTypePrimitive(VTypePrimitive::CHARACTER); +const VTypePrimitive primitive_BOOLEAN(VTypePrimitive::BOOLEAN, true); +const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true); +const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER); +const VTypePrimitive primitive_REAL(VTypePrimitive::REAL); +const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true); +const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER); -const VTypeRange* primitive_NATURAL = new VTypeRange(primitive_INTEGER, INT64_MAX, 0); +const VTypeRange primitive_NATURAL(&primitive_INTEGER, INT64_MAX, 0); -static const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector (1)); -static const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector (1)); -static const VTypeArray* primitive_STRING = new VTypeArray(primitive_CHARACTER, vector (1)); +static const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector (1)); +static const VTypeArray primitive_BOOL_VECTOR(&primitive_BOOLEAN, vector (1)); +static const VTypeArray primitive_STRING(&primitive_CHARACTER, vector (1)); void generate_global_types(ActiveScope*res) { - res->use_name(perm_string::literal("boolean"), primitive_BOOLEAN); - res->use_name(perm_string::literal("bit"), primitive_BIT); - res->use_name(perm_string::literal("integer"), primitive_INTEGER); - res->use_name(perm_string::literal("std_logic"), primitive_STDLOGIC); - res->use_name(perm_string::literal("character"), primitive_CHARACTER); - res->use_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); - res->use_name(perm_string::literal("string"), primitive_STRING); - res->use_name(perm_string::literal("natural"), primitive_NATURAL); + res->use_name(perm_string::literal("boolean"), &primitive_BOOLEAN); + res->use_name(perm_string::literal("bit"), &primitive_BIT); + res->use_name(perm_string::literal("integer"), &primitive_INTEGER); + res->use_name(perm_string::literal("real"), &primitive_REAL); + res->use_name(perm_string::literal("std_logic"), &primitive_STDLOGIC); + res->use_name(perm_string::literal("character"), &primitive_CHARACTER); + res->use_name(perm_string::literal("bit_vector"),&primitive_BOOL_VECTOR); + res->use_name(perm_string::literal("string"), &primitive_STRING); + res->use_name(perm_string::literal("natural"), &primitive_NATURAL); } bool is_global_type(perm_string name) @@ -372,6 +392,7 @@ bool is_global_type(perm_string name) if (name == "boolean") return true; if (name == "bit") return true; if (name == "integer") return true; + if (name == "real") return true; if (name == "std_logic") return true; if (name == "character") return true; if (name == "bit_vector") return true; diff --git a/vhdlpp/library.h b/vhdlpp/library.h new file mode 100644 index 000000000..ab6464f45 --- /dev/null +++ b/vhdlpp/library.h @@ -0,0 +1,32 @@ +#ifndef IVL_library_H +#define IVL_library_H +/* + * Copyright (c) 2011-2014 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. + */ + +class Subprogram; + +extern void library_set_work_path(const char*work_path); +extern void library_add_directory(const char*directory); + +extern Subprogram*library_find_subprogram(perm_string name); + +extern int emit_packages(void); + +#endif /* IVL_library_H */ + diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index 45fb02e9d..b142d3845 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -75,6 +75,7 @@ const char NOTICE[] = ; # include "compiler.h" +# include "library.h" # include "parse_api.h" # include "vtype.h" # include @@ -82,6 +83,7 @@ const char NOTICE[] = # include # include # include +# include #if defined(HAVE_GETOPT_H) # include #endif @@ -178,6 +180,7 @@ int main(int argc, char*argv[]) } } + std::cout.precision(std::numeric_limits::digits10); library_set_work_path(work_path); preload_global_types(); diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index d3d4a8b06..9c0025f47 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -20,6 +20,7 @@ # include "package.h" # include "entity.h" +# include "subprogram.h" # include "parse_misc.h" # include "ivl_assert.h" @@ -66,21 +67,6 @@ void Package::write_to_stream(ostream&fd) const fd << "type " << cur->first << ";" << endl; } - for (map::const_iterator cur = cur_constants_.begin() - ; cur != cur_constants_.end() ; ++ cur) { - if (cur->second==0 || cur->second->typ==0) { - fd << "-- const " << cur->first - << " has errors." << endl; - continue; - } - - 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 = use_types_.begin() ; cur != use_types_.end() ; ++cur) { @@ -89,6 +75,10 @@ void Package::write_to_stream(ostream&fd) const continue; if (cur->first == "std_logic_vector") continue; + if (cur->first == "signed") + continue; + if (cur->first == "unsigned") + continue; fd << "type " << cur->first << " is "; cur->second->write_type_to_stream(fd); @@ -108,6 +98,21 @@ void Package::write_to_stream(ostream&fd) const fd << ";" << endl; } + for (map::const_iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++ cur) { + if (cur->second==0 || cur->second->typ==0) { + fd << "-- const " << cur->first + << " has errors." << endl; + continue; + } + + 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 = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++cur) { cur->second->write_to_stream(fd); diff --git a/vhdlpp/package.h b/vhdlpp/package.h index 046708c30..a8e303cd5 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -1,7 +1,7 @@ -#ifndef __package_H -#define __package_H +#ifndef IVL_package_H +#define IVL_package_H /* - * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -48,4 +48,4 @@ class Package : public Scope, public LineInfo { perm_string name_; }; -#endif +#endif /* IVL_package_H */ diff --git a/vhdlpp/package_emit.cc b/vhdlpp/package_emit.cc index 5792cd728..94a40c8c8 100644 --- a/vhdlpp/package_emit.cc +++ b/vhdlpp/package_emit.cc @@ -19,6 +19,7 @@ */ # include "package.h" +# include "subprogram.h" # include # include "ivl_assert.h" @@ -48,22 +49,22 @@ int Package::emit_package(ostream&fd) const for (map::const_iterator cur = cur_types_.begin() ; cur != cur_types_.end() ; ++ cur) { fd << "typedef "; - errors += cur->second->emit_def(fd); - fd << " \\" << cur->first << " ;" << endl; + errors += cur->second->emit_def(fd, cur->first); + fd << " ;" << endl; } - for (map::const_iterator cur = use_constants_.begin() - ; cur != use_constants_.end() ; ++cur) { - fd << "localparam \\" << cur->first << " = "; - errors += cur->second->val->emit_package(fd); - fd << ";" << endl; - } - for (map::const_iterator cur = cur_constants_.begin() - ; cur != cur_constants_.end() ; ++cur) { - fd << "localparam " << cur->first << " = "; - errors += cur->second->val->emit_package(fd); - fd << ";" << endl; - } + //for (map::const_iterator cur = use_constants_.begin() + //; cur != use_constants_.end() ; ++cur) { + //fd << "localparam \\" << cur->first << " = "; + //errors += cur->second->val->emit_package(fd); + //fd << ";" << endl; + //} + //for (map::const_iterator cur = cur_constants_.begin() + //; cur != cur_constants_.end() ; ++cur) { + //fd << "localparam " << cur->first << " = "; + //errors += cur->second->val->emit_package(fd); + //fd << ";" << endl; + //} for (map::const_iterator cur = cur_subprograms_.begin() ; cur != cur_subprograms_.end() ; ++ cur) { diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 453344930..ecde6b0b2 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -7,7 +7,8 @@ %{ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) - * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2014 / Stephen Williams (steve@icarus.com), + * Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -82,6 +83,11 @@ extern int yylex(union YYSTYPE*yylvalp,YYLTYPE*yyllocp,yyscan_t yyscanner); */ static ActiveScope*active_scope = new ActiveScope; static stack scope_stack; +static Subprogram*active_sub = NULL; + +// perm_strings for attributes +const static perm_string left_attr = perm_string::literal("left"); +const static perm_string right_attr = perm_string::literal("right"); /* * When a scope boundary starts, call the push_scope function to push @@ -105,6 +111,13 @@ static void pop_scope(void) scope_stack.pop(); } +static bool is_subprogram_param(perm_string name) +{ + if(!active_sub) + return false; + + return (active_sub->find_param(name) != NULL); +} void preload_global_types(void) { @@ -267,7 +280,7 @@ static void touchup_interface_for_functions(std::list*ports) %token K_package K_parameter K_port K_postponed K_procedure K_process %token K_property K_protected K_pure %token K_range K_record K_register K_reject K_release K_rem K_report -%token K_restrict K_restrict_guarantee K_return K_rol K_ror +%token K_restrict K_restrict_guarantee K_return K_reverse_range K_rol K_ror %token K_select K_sequence K_severity K_signal K_shared %token K_sla K_sll K_sra K_srl K_strong K_subtype %token K_then K_to K_transport K_type @@ -357,7 +370,7 @@ static void touchup_interface_for_functions(std::list*ports) %type else_when_waveform %type else_when_waveforms -%type function_specification subprogram_specification +%type function_specification subprogram_specification subprogram_body_start %% @@ -683,8 +696,8 @@ composite_type_definition /* unbounded_array_definition IEEE 1076-2008 P5.3.2.1 */ | K_array '(' index_subtype_definition_list ')' K_of subtype_indication - { sorrymsg(@1, "unbounded_array_definition not supported.\n"); - std::list r; + { std::list r; + r.push_back(new prange_t(NULL, NULL, true)); // NULL boundaries indicate unbounded array type VTypeArray*tmp = new VTypeArray($6, &r); $$ = tmp; } @@ -1542,7 +1555,7 @@ name /* IEEE 1076-2008 P8.1 */ | IDENTIFIER '(' expression_list ')' { perm_string name = lex_strings.make($1); delete[]$1; - if (active_scope->is_vector_name(name)) { + if (active_scope->is_vector_name(name) || is_subprogram_param(name)) { ExpName*tmp = new ExpName(name, $3); $$ = tmp; } else { @@ -1741,6 +1754,11 @@ primary FILE_NAME(tmp, @1); $$ = tmp; } + | REAL_LITERAL + { ExpReal*tmp = new ExpReal($1); + FILE_NAME(tmp, @1); + $$ = tmp; + } | STRING_LITERAL { ExpString*tmp = new ExpString($1); FILE_NAME(tmp,@1); @@ -1807,16 +1825,7 @@ procedure_call_statement ; process_declarative_item - : K_variable identifier_list ':' subtype_indication ';' - { /* Save the signal declaration in the block_signals map. */ - for (std::list::iterator cur = $2->begin() - ; cur != $2->end() ; ++cur) { - Variable*sig = new Variable(*cur, $4); - FILE_NAME(sig, @1); - active_scope->bind_name(*cur, sig); - } - delete $2; - } + : variable_declaration ; process_declarative_part @@ -1899,6 +1908,34 @@ range { prange_t* tmp = new prange_t($1, $3, $2); $$ = tmp; } + | name '\'' K_range + { + prange_t*tmp = NULL; + ExpName*name = NULL; + if((name = dynamic_cast($1))) { + ExpAttribute*left = new ExpAttribute(name, left_attr); + ExpAttribute*right = new ExpAttribute(name, right_attr); + tmp = new prange_t(left, right, true); + tmp->set_auto_dir(); + } else { + errormsg(@1, "'range attribute can be used with named expressions only"); + } + $$ = tmp; + } + | name '\'' K_reverse_range + { + prange_t*tmp = NULL; + ExpName*name = NULL; + if((name = dynamic_cast($1))) { + ExpAttribute*left = new ExpAttribute(name, left_attr); + ExpAttribute*right = new ExpAttribute(name, right_attr); + tmp = new prange_t(left, right, false); + tmp->set_auto_dir(); + } else { + errormsg(@1, "'reverse_range attribute can be used with named expressions only"); + } + $$ = tmp; + } ; range_list @@ -2164,12 +2201,18 @@ signal_assignment_statement } ; +subprogram_body_start + : subprogram_specification K_is + { assert(!active_sub); + active_sub = $1; + $$ = $1; } + ; + /* This is a function/task body. This may have a matching subprogram declaration, and if so it will be in the active scope. */ subprogram_body /* IEEE 1076-2008 P4.3 */ - : subprogram_specification K_is - subprogram_declarative_part + : subprogram_body_start subprogram_declarative_part K_begin subprogram_statement_part K_end subprogram_kind_opt identifier_opt ';' { Subprogram*prog = $1; @@ -2180,18 +2223,21 @@ subprogram_body /* IEEE 1076-2008 P4.3 */ } else if (tmp) { errormsg(@1, "Subprogram specification for %s doesn't match specification in package header.\n", prog->name().str()); } - prog->set_program_body($5); + prog->transfer_from(*active_scope); + prog->set_program_body($4); active_scope->bind_name(prog->name(), prog); + active_sub = NULL; } - | subprogram_specification K_is + | subprogram_body_start subprogram_declarative_part K_begin error K_end subprogram_kind_opt identifier_opt ';' { errormsg(@2, "Syntax errors in subprogram body.\n"); yyerrok; + active_sub = NULL; if ($1) delete $1; - if ($8) delete[]$8; + if ($7) delete[]$7; } ; @@ -2404,8 +2450,15 @@ variable_assignment_statement /* IEEE 1076-2008 P10.6.1 */ 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"); } - + { /* Save the signal declaration in the block_signals map. */ + for (std::list::iterator cur = $3->begin() + ; cur != $3->end() ; ++cur) { + Variable*sig = new Variable(*cur, $5); + FILE_NAME(sig, @2); + active_scope->bind_name(*cur, sig); + } + delete $3; + } | K_shared_opt K_variable error ';' { errormsg(@2, "Syntax error in variable declaration.\n"); yyerrok; diff --git a/vhdlpp/parse_api.h b/vhdlpp/parse_api.h index 0bfd6587a..96c384c53 100644 --- a/vhdlpp/parse_api.h +++ b/vhdlpp/parse_api.h @@ -1,7 +1,7 @@ -#ifndef __parse_api_H -#define __parse_api_H +#ifndef IVL_parse_api_H +#define IVL_parse_api_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 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 @@ -68,4 +68,4 @@ extern int yydebug; extern int parse_errors; extern int parse_sorrys; -#endif +#endif /* IVL_parse_api_H */ diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 0049388bf..734443d3e 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -70,7 +70,7 @@ void bind_architecture_to_entity(const char*ename, Architecture*arch) static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, ScopeBase* /* scope */, Expression*array_left, - bool /* downto*/ , + bool downto, Expression*array_right) { const VType*base_type = parse_type_by_name(lex_strings.make(base_name)); @@ -82,6 +82,13 @@ static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_n assert(array_left==0 || array_right!=0); + // unfold typedef, there might be VTypeArray inside + const VType*origin_type = base_type; + const VTypeDef*type_def = dynamic_cast (base_type); + if (type_def) { + base_type = type_def->peek_definition(); + } + const VTypeArray*base_array = dynamic_cast (base_type); if (base_array) { assert(array_left && array_right); @@ -91,9 +98,13 @@ static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_n // For now, I only know how to handle 1 dimension assert(base_array->dimensions() == 1); - range[0] = VTypeArray::range_t(array_left, array_right); + range[0] = VTypeArray::range_t(array_left, array_right, downto); - VTypeArray*subtype = new VTypeArray(base_array->element_type(), range, base_array->signed_vector()); + // use typedef as the element type if possible + const VType*element = type_def ? origin_type : base_array->element_type(); + + VTypeArray*subtype = new VTypeArray(element, range, + base_array->signed_vector()); return subtype; } diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index 1e4c27669..e4aa9e644 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -1,7 +1,7 @@ -#ifndef __parse_misc_H -#define __parse_misc_H +#ifndef IVL_parse_misc_H +#define IVL_parse_misc_H /* - * Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011,2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -67,4 +67,4 @@ extern void generate_global_types(ActiveScope*res); extern bool is_global_type(perm_string type_name); -#endif +#endif /* IVL_parse_misc_H */ diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 2773aead8..625312762 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -1,7 +1,7 @@ -#ifndef __parse_types_H -#define __parse_types_H +#ifndef IVL_parse_types_H +#define IVL_parse_types_H /* - * Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011,2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -71,7 +71,7 @@ class instant_list_t { class prange_t { public: prange_t(Expression* left, Expression* right, bool dir) - : left_(left), right_(right), direction_(dir) {} + : left_(left), right_(right), direction_(dir), auto_dir_(false) {} ~prange_t() { delete left_; delete right_; } void dump(ostream&out, int indent) const; @@ -79,12 +79,16 @@ class prange_t { inline Expression*lsb() { return direction_? right_: left_; } inline bool is_downto() const { return direction_; } + inline void set_auto_dir(bool enabled = true) { auto_dir_ = enabled; }; + inline bool is_auto_dir() const { return auto_dir_; } + inline Expression*expr_left() { return left_; } inline Expression*expr_right() { return right_; } private: Expression *left_, *right_; bool direction_; + bool auto_dir_; private: //not implemented prange_t(const prange_t&); @@ -96,4 +100,4 @@ struct adding_term { Expression*term; }; -#endif +#endif /* IVL_parse_types_H */ diff --git a/vhdlpp/parse_wrap.h b/vhdlpp/parse_wrap.h index ceca8439e..af20a4955 100644 --- a/vhdlpp/parse_wrap.h +++ b/vhdlpp/parse_wrap.h @@ -1,7 +1,7 @@ -#ifndef __parse_wrap_H -#define __parse_wrap_H +#ifndef IVL_parse_wrap_H +#define IVL_parse_wrap_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -38,4 +38,4 @@ class VType; # include "parse.h" -#endif +#endif /* IVL_parse_wrap_H */ diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index c6f783628..5182aee1a 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -20,6 +20,7 @@ # include "scope.h" # include "package.h" +# include "subprogram.h" # include # include # include @@ -34,10 +35,8 @@ using namespace std; * accumulate new scope values. */ ScopeBase::ScopeBase(const ActiveScope&ref) +: use_constants_(ref.use_constants_), cur_constants_(ref.cur_constants_) { - use_constants_ = ref.use_constants_; - cur_constants_ = ref.cur_constants_; - merge(ref.old_signals_.begin(), ref.old_signals_.end(), ref.new_signals_.begin(), ref.new_signals_.end(), insert_iterator >( @@ -204,6 +203,27 @@ void ScopeBase::do_use_from(const ScopeBase*that) } } +void ScopeBase::transfer_from(ScopeBase&ref) +{ + std::copy(ref.new_signals_.begin(), ref.new_signals_.end(), + insert_iterator >( + new_signals_, new_signals_.end()) + ); + ref.new_signals_.clear(); + + std::copy(ref.new_variables_.begin(), ref.new_variables_.end(), + insert_iterator >( + new_variables_, new_variables_.end()) + ); + ref.new_variables_.clear(); + + std::copy(ref.new_components_.begin(), ref.new_components_.end(), + insert_iterator >( + new_components_, new_components_.end()) + ); + ref.new_components_.clear(); +} + void ActiveScope::set_package_header(Package*pkg) { assert(package_header_ == 0); diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 790c709c9..2b0fdc5b3 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -1,7 +1,7 @@ -#ifndef __scope_H -#define __scope_H +#ifndef IVL_scope_H +#define IVL_scope_H /* - * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -26,7 +26,6 @@ # include "StringHeap.h" # include "entity.h" # include "expression.h" -# include "subprogram.h" # include "vsignal.h" class ActiveScope; @@ -58,6 +57,9 @@ class ScopeBase { Signal* find_signal(perm_string by_name) const; Variable* find_variable(perm_string by_name) const; Subprogram* find_subprogram(perm_string by_name) const; + // Moves all signals, variables and components from another scope to + // this one. After the transfer new_* maps are emptied in the another scope. + void transfer_from(ScopeBase&ref); protected: void cleanup(); @@ -92,7 +94,7 @@ class ScopeBase { std::map cur_types_; //current types // Constant declarations... struct const_t { - ~const_t() {delete typ; delete val;} + ~const_t() {delete val;} const_t(const VType*t, Expression* v) : typ(t), val(v) {}; const VType*typ; @@ -203,7 +205,7 @@ class ActiveScope : public ScopeBase { { map::iterator it; if((it = use_subprograms_.find(name)) != use_subprograms_.end() ) use_subprograms_.erase(it); - cur_subprograms_[name] = obj;; + cur_subprograms_[name] = obj; } void bind(Entity*ent) @@ -226,4 +228,4 @@ class ActiveScope : public ScopeBase { Entity*context_entity_; }; -#endif +#endif /* IVL_scope_H */ diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 5e12ec503..9271e4ed3 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -1,7 +1,7 @@ -#ifndef __sequential_H -#define __sequential_H +#ifndef IVL_sequential_H +#define IVL_sequential_H /* - * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -120,6 +120,8 @@ class ReturnStmt : public SequentialStmt { int emit(ostream&out, Entity*entity, Architecture*arc); void dump(ostream&out, int indent) const; + const Expression*peek_expr() const { return val_; }; + private: Expression*val_; }; @@ -241,4 +243,4 @@ class BasicLoopStatement : public LoopStatement { void dump(ostream&out, int indent) const; }; -#endif +#endif /* IVL_sequential_H */ diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index e3c0fab71..86a9a529c 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -212,24 +212,34 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) ivl_assert(*this, start_rc); ivl_assert(*this, finish_rc); - if (! range_->is_downto()) { + bool dir = range_->is_downto(); + + if (!dir) { int64_t tmp = start_val; start_val = finish_val; finish_val = tmp; } - if (range_->is_downto() && (start_val < finish_val)) { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " downto " << finish_val << " */ end" << endl; - return errors; + if (dir && (start_val < finish_val)) { + if(range_->is_auto_dir()) { + dir = false; + } else { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " downto " << finish_val << " */ end" << endl; + return errors; + } } - if (!range_->is_downto() && start_val > finish_val) { - out << "begin /* Degenerate loop at " << get_fileline() - << ": " << start_val - << " to " << finish_val << " */ end" << endl; - return errors; + else if (!dir && start_val > finish_val) { + if(range_->is_auto_dir()) { + dir = true; + } else { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " to " << finish_val << " */ end" << endl; + return errors; + } } perm_string scope_name = loop_name(); @@ -242,12 +252,12 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) out << "begin : " << scope_name << endl; out << "longint \\" << it_ << " ;" << endl; out << "for (\\" << it_ << " = " << start_val << " ; "; - if (range_->is_downto()) + if (dir) out << "\\" << it_ << " >= " << finish_val; else out << "\\" << it_ << " <= " << finish_val; out << "; \\" << it_ << " = \\" << it_; - if (range_->is_downto()) + if (dir) out << " - 1"; else out << " + 1"; diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 47641550c..5814bfdbf 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2013-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -21,6 +21,7 @@ # include "subprogram.h" # include "entity.h" # include "vtype.h" +# include "sequential.h" # include "ivl_assert.h" using namespace std; @@ -45,6 +46,7 @@ void Subprogram::set_program_body(list*stmt) { ivl_assert(*this, statements_==0); statements_ = stmt; + fix_return_type(); } bool Subprogram::compare_specification(Subprogram*that) const @@ -78,6 +80,57 @@ bool Subprogram::compare_specification(Subprogram*that) const return true; } +const InterfacePort*Subprogram::find_param(perm_string nam) const +{ + if(!ports_) + return NULL; + + for (std::list::const_iterator it = ports_->begin() + ; it != ports_->end(); ++it) { + if((*it)->name == nam) + return *it; + } + + return NULL; +} + +const VType*Subprogram::peek_param_type(int idx) const +{ + if(!ports_ || idx < 0 || (size_t)idx >= ports_->size()) + return NULL; + + std::list::const_iterator p = ports_->begin(); + std::advance(p, idx); + + return (*p)->type; +} + +void Subprogram::fix_return_type(void) +{ + if(!statements_) + return; + + const ReturnStmt*ret = NULL; + const VType*t = NULL; + + for (std::list::const_iterator s = statements_->begin() + ; s != statements_->end(); ++s) { + if((ret = dynamic_cast(*s))) { + const Expression*expr = ret->peek_expr(); + + if(const ExpName*n = dynamic_cast(expr)) { + if(Variable*v = find_variable(n->peek_name())) + t = v->peek_type(); + } else { + t = expr->peek_type(); + } + + if(t) + return_type_ = t; + } + } +} + void Subprogram::write_to_stream(ostream&fd) const { fd << " function " << name_ << "("; diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 304fa06cf..5b38f1223 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -1,7 +1,7 @@ -#ifndef __subprogram_H -#define __subprogram_H +#ifndef IVL_subprogram_H +#define IVL_subprogram_H /* - * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2013-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -22,15 +22,15 @@ # include "StringHeap.h" # include "LineInfo.h" +# include "scope.h" # include # include class InterfacePort; -class ScopeBase; class SequentialStmt; class VType; -class Subprogram : public LineInfo { +class Subprogram : public LineInfo, public ScopeBase { public: Subprogram(perm_string name, std::list*ports, @@ -48,6 +48,11 @@ class Subprogram : public LineInfo { // matches this subprogram and that subprogram. bool compare_specification(Subprogram*that) const; + const InterfacePort*find_param(perm_string nam) const; + const VType*peek_param_type(int idx) const; + + int emit(ostream&out, Entity*ent, Architecture*arc); + // Emit a definition as it would show up in a package. int emit_package(std::ostream&fd) const; @@ -55,6 +60,10 @@ class Subprogram : public LineInfo { void dump(std::ostream&fd) const; private: + // Determines appropriate return type. Un case of std_logic_vector + // VHDL requires skipping its size in contrary to Verilog + void fix_return_type(void); + perm_string name_; const ScopeBase*parent_; std::list*ports_; @@ -62,4 +71,4 @@ class Subprogram : public LineInfo { std::list*statements_; }; -#endif +#endif /* IVL_subprogram_H */ diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc index efd586bd0..6f1b37508 100644 --- a/vhdlpp/subprogram_emit.cc +++ b/vhdlpp/subprogram_emit.cc @@ -31,7 +31,7 @@ int Subprogram::emit_package(ostream&fd) const if (return_type_) { fd << "function "; - return_type_->emit_def(fd); + return_type_->emit_def(fd, empty_perm_string); fd << " " << name_; fd << "("; } else { @@ -55,16 +55,22 @@ int Subprogram::emit_package(ostream&fd) const break; } - errors += curp->type->emit_def(fd); - fd << " \\" << curp->name << " "; + errors += curp->type->emit_def(fd, curp->name); } fd << ");" << endl; + for (map::const_iterator cur = new_variables_.begin() + ; cur != new_variables_.end() ; ++cur) { + // Workaround to enable reg_flag for variables + cur->second->count_ref_sequ(); + errors += cur->second->emit(fd, NULL, NULL); + } + if (statements_) { for (list::const_iterator cur = statements_->begin() ; cur != statements_->end() ; ++cur) { - errors += (*cur)->emit(fd, 0, 0); + errors += (*cur)->emit(fd, NULL, NULL); } } else { fd << " begin /* empty body */ end" << endl; diff --git a/vhdlpp/vhdlint.h b/vhdlpp/vhdlint.h index 849a82485..885c79e46 100644 --- a/vhdlpp/vhdlint.h +++ b/vhdlpp/vhdlint.h @@ -1,7 +1,7 @@ -#ifndef __vhdlint_H -#define __vhdlint_H +#ifndef IVL_vhdlint_H +#define IVL_vhdlint_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -40,4 +40,4 @@ class vhdlint int64_t value_; }; -#endif +#endif /* IVL_vhdlint_H */ diff --git a/vhdlpp/vhdlnum.h b/vhdlpp/vhdlnum.h index 034760315..fe7d84f86 100644 --- a/vhdlpp/vhdlnum.h +++ b/vhdlpp/vhdlnum.h @@ -1,5 +1,5 @@ -#ifndef __vhdlnum_H -#define __vhdlnum_H +#ifndef IVL_vhdlnum_H +#define IVL_vhdlnum_H #include "config.h" @@ -10,4 +10,4 @@ class vhdlnum { vhdlnum(char* text) {} }; -#endif +#endif /* IVL_vhdlnum_H */ diff --git a/vhdlpp/vhdlpp_config.h.in b/vhdlpp/vhdlpp_config.h.in index 65120e08b..a736dc7d9 100644 --- a/vhdlpp/vhdlpp_config.h.in +++ b/vhdlpp/vhdlpp_config.h.in @@ -1,7 +1,7 @@ -#ifndef __vhdlpp_config_H /* -*- c++ -*- */ -#define __vhdlpp_config_H +#ifndef IVL_vhdlpp_config_H /* -*- c++ -*- */ +#define IVL_vhdlpp_config_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -37,4 +37,4 @@ # include #endif -#endif /* __config_H */ +#endif /* IVL_vhdlpp_config_H */ diff --git a/vhdlpp/vhdlreal.h b/vhdlpp/vhdlreal.h index 9753a6ad3..687068a77 100644 --- a/vhdlpp/vhdlreal.h +++ b/vhdlpp/vhdlreal.h @@ -1,7 +1,7 @@ -#ifndef __vhdlreal_h -#define __vhdlreal_h +#ifndef IVL_vhdlreal_h +#define IVL_vhdlreal_h /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 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 @@ -54,4 +54,4 @@ class vhdlreal double value_; }; -#endif +#endif /* IVL_vhdlreal_h */ diff --git a/vhdlpp/vsignal.cc b/vhdlpp/vsignal.cc index 29627f924..e8bc87a35 100644 --- a/vhdlpp/vsignal.cc +++ b/vhdlpp/vsignal.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright CERN 2014 / Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -33,6 +34,13 @@ SigVarBase::~SigVarBase() { } +void SigVarBase::elaborate_init_expr(Entity*ent, Architecture*arc) +{ + if(init_expr_) { + init_expr_->elaborate_expr(ent, arc, peek_type()); + } +} + void SigVarBase::type_elaborate_(VType::decl_t&decl) { decl.type = type_; @@ -44,7 +52,7 @@ int Signal::emit(ostream&out, Entity*ent, Architecture*arc) VType::decl_t decl; type_elaborate_(decl); - if (peek_refcnt_sequ_() > 0) + if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed()) decl.reg_flag = true; errors += decl.emit(out, peek_name_()); @@ -63,7 +71,7 @@ int Variable::emit(ostream&out, Entity*, Architecture*) VType::decl_t decl; type_elaborate_(decl); - if (peek_refcnt_sequ_() > 0) + if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed()) decl.reg_flag = true; errors += decl.emit(out, peek_name_()); out << ";" << endl; diff --git a/vhdlpp/vsignal.h b/vhdlpp/vsignal.h index 777daa80f..9d97e3b0f 100644 --- a/vhdlpp/vsignal.h +++ b/vhdlpp/vsignal.h @@ -1,7 +1,7 @@ -#ifndef __vsignal_H -#define __vsignal_H +#ifndef IVL_vsignal_H +#define IVL_vsignal_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -41,6 +41,9 @@ class SigVarBase : public LineInfo { void dump(ostream&out, int indent = 0) const; + // Elaborates initializer expressions if needed. + void elaborate_init_expr(Entity*ent, Architecture*arc); + protected: perm_string peek_name_() const { return name_; } unsigned peek_refcnt_sequ_() const { return refcnt_sequ_; } @@ -92,4 +95,4 @@ inline Variable::Variable(perm_string name, const VType*type) { } -#endif +#endif /* IVL_vsignal_H */ diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index 34787c6a0..a7f9233aa 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -35,8 +35,8 @@ void VType::show(ostream&out) const write_to_stream(out); } -VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt) -: type_(tt) +VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt, bool packed) +: type_(tt), packed_(packed) { } @@ -59,6 +59,9 @@ void VTypePrimitive::show(ostream&out) const case INTEGER: out << "INTEGER"; break; + case REAL: + out << "REAL"; + break; case STDLOGIC: out << "std_logic"; break; @@ -85,7 +88,8 @@ VTypeArray::VTypeArray(const VType*element, std::list*r, bool sv) r->pop_front(); Expression*msb = curp->msb(); Expression*lsb = curp->lsb(); - ranges_[idx] = range_t(msb, lsb); + bool dir = curp->is_downto(); + ranges_[idx] = range_t(msb, lsb, dir); } } @@ -94,14 +98,28 @@ VTypeArray::~VTypeArray() { } -size_t VTypeArray::dimensions() const +const VType* VTypeArray::basic_type(bool typedef_allowed) const { - return ranges_.size(); -} + const VType*t = etype_; + const VTypeDef*tdef = NULL; + bool progress = false; -const VType* VTypeArray::element_type() const -{ - return etype_; + do { + progress = false; + + if((tdef = dynamic_cast(t))) { + t = tdef->peek_definition(); + } + + if(const VTypeArray*arr = dynamic_cast(t)) { + t = arr->element_type(); + progress = true; + } else if(tdef) { // return the typedef if it does not define an array + t = typedef_allowed ? tdef : tdef->peek_definition(); + } + } while(progress); + + return t; } void VTypeArray::show(ostream&out) const @@ -187,13 +205,17 @@ void VTypeRecord::show(ostream&out) const write_to_stream(out); } -const VTypeRecord::element_t* VTypeRecord::element_by_name(perm_string name) const +const VTypeRecord::element_t* VTypeRecord::element_by_name(perm_string name, int*index) const { for (vector::const_iterator cur = elements_.begin() ; cur != elements_.end() ; ++cur) { element_t*curp = *cur; - if (curp->peek_name() == name) + if (curp->peek_name() == name) { + if (index) + *index = std::distance(elements_.begin(), cur); + return curp; + } } return 0; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index e18e9ecbd..580cf92b9 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -1,8 +1,9 @@ -#ifndef __vtype_H -#define __vtype_H +#ifndef IVL_vtype_H +#define IVL_vtype_H /* - * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) - * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) + * Copyright CERN 2014 / Stephen Williams (steve@icarus.com), + * Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -73,7 +74,7 @@ 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) const =0; + virtual int emit_def(std::ostream&out, perm_string name) const =0; // This virtual method causes VTypeDef types to emit typedefs // of themselves. The VTypeDef implementation of this method @@ -81,8 +82,11 @@ class VType { // all the types that it emits. virtual int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; + // Determines if a type can be used in Verilog packed array. + virtual bool can_be_packed() const { return false; } + private: - friend class decl_t; + friend struct 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; @@ -99,6 +103,12 @@ class VType { bool reg_flag; }; + protected: + inline void emit_name(std::ostream&out, perm_string name) const + { + if(name != empty_perm_string) + out << " \\" << name << " "; + } }; inline std::ostream&operator << (std::ostream&out, const VType&item) @@ -114,7 +124,7 @@ extern void preload_global_types(void); */ class VTypeERROR : public VType { public: - int emit_def(std::ostream&out) const; + int emit_def(std::ostream&out, perm_string name) const; }; /* @@ -124,10 +134,10 @@ class VTypeERROR : public VType { class VTypePrimitive : public VType { public: - enum type_t { BOOLEAN, BIT, INTEGER, STDLOGIC, CHARACTER }; + enum type_t { BOOLEAN, BIT, INTEGER, REAL, STDLOGIC, CHARACTER }; public: - VTypePrimitive(type_t); + VTypePrimitive(type_t tt, bool packed = false); ~VTypePrimitive(); void write_to_stream(std::ostream&fd) const; @@ -136,17 +146,21 @@ class VTypePrimitive : public VType { type_t type() const { return type_; } int emit_primitive_type(std::ostream&fd) const; - int emit_def(std::ostream&out) const; + int emit_def(std::ostream&out, perm_string name) const; + + bool can_be_packed() const { return packed_; } private: type_t type_; + bool packed_; }; -extern const VTypePrimitive* primitive_BOOLEAN; -extern const VTypePrimitive* primitive_BIT; -extern const VTypePrimitive* primitive_INTEGER; -extern const VTypePrimitive* primitive_STDLOGIC; -extern const VTypePrimitive* primitive_CHARACTER; +extern const VTypePrimitive primitive_BOOLEAN; +extern const VTypePrimitive primitive_BIT; +extern const VTypePrimitive primitive_INTEGER; +extern const VTypePrimitive primitive_REAL; +extern const VTypePrimitive primitive_STDLOGIC; +extern const VTypePrimitive primitive_CHARACTER; /* * An array is a compound N-dimensional array of element type. The @@ -159,17 +173,19 @@ class VTypeArray : public VType { public: class range_t { public: - range_t() : msb_(0), lsb_(0) { } - range_t(Expression*m, Expression*l) : msb_(m), lsb_(l) { } + range_t(Expression*m = NULL, Expression*l = NULL, bool dir = true) : + msb_(m), lsb_(l), direction_(dir) { } - bool is_box() const { return msb_==0 && lsb_==0; } + inline bool is_box() const { return msb_==0 && lsb_==0; } + inline bool is_downto() const { return direction_; } - Expression* msb() const { return msb_; } - Expression* lsb() const { return lsb_; } + inline Expression* msb() const { return msb_; } + inline Expression* lsb() const { return lsb_; } private: Expression* msb_; Expression* lsb_; + bool direction_; }; public: @@ -179,20 +195,32 @@ class VTypeArray : public VType { int elaborate(Entity*ent, Architecture*arc) const; void write_to_stream(std::ostream&fd) const; + void write_type_to_stream(std::ostream&fd) const; void show(std::ostream&) const; - size_t dimensions() const; + inline size_t dimensions() const { return ranges_.size(); }; const range_t&dimension(size_t idx) const { return ranges_[idx]; } - bool signed_vector() const { return signed_flag_; } + inline bool signed_vector() const { return signed_flag_; } - const VType* element_type() const; + // returns the type of element held in the array + inline const VType* element_type() const { return etype_; } - int emit_def(std::ostream&out) const; + // returns the basic type of element held in the array + // (unfolds typedefs and multidimensional arrays) + // typedef_allowed decides if VTypeDef can be returned or should + // it be unfolded + const VType* basic_type(bool typedef_allowed = true) const; + + int emit_def(std::ostream&out, perm_string name) const; int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; + int emit_dimensions(std::ostream&out) const; + + bool can_be_packed() const { return etype_->can_be_packed(); } private: + void write_range_to_stream_(std::ostream&fd) const; const VType*etype_; std::vector ranges_; @@ -210,7 +238,7 @@ class VTypeRange : public VType { public: // Virtual methods void write_to_stream(std::ostream&fd) const; - int emit_def(std::ostream&out) const; + int emit_def(std::ostream&out, perm_string name) const; private: const VType*base_; @@ -223,8 +251,9 @@ class VTypeEnum : public VType { VTypeEnum(const std::list*names); ~VTypeEnum(); + void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; - int emit_def(std::ostream&out) const; + int emit_def(std::ostream&out, perm_string name) const; private: std::vectornames_; @@ -257,9 +286,10 @@ class VTypeRecord : public VType { void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; - int emit_def(std::ostream&out) const; + int emit_def(std::ostream&out, perm_string name) const; - const element_t* element_by_name(perm_string name) const; + bool can_be_packed() const { return true; } + const element_t* element_by_name(perm_string name, int*index = NULL) const; private: std::vector elements_; @@ -283,10 +313,12 @@ class VTypeDef : public VType { 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; + void write_type_to_stream(std::ostream&fd) const; int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; - int emit_def(std::ostream&out) const; + int emit_def(std::ostream&out, perm_string name) const; + + bool can_be_packed() const { return type_->can_be_packed(); } private: int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const; @@ -295,4 +327,4 @@ class VTypeDef : public VType { const VType*type_; }; -#endif +#endif /* IVL_vtype_H */ diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index 7508ee8c4..aa24dd362 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2014 CERN / Maciej Suminski (maciej.suminski@cern.ch) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -32,7 +33,6 @@ int VType::decl_t::emit(ostream&out, perm_string name) const return type->emit_decl(out, name, reg_flag); } - int VType::emit_decl(ostream&out, perm_string name, bool reg_flag) const { int errors = 0; @@ -40,9 +40,8 @@ int VType::emit_decl(ostream&out, perm_string name, bool reg_flag) const if (!reg_flag) out << "wire "; - errors += emit_def(out); - - out << " \\" << name << " "; + errors += emit_def(out, name); + out << " "; return errors; } @@ -51,53 +50,36 @@ int VType::emit_typedef(std::ostream&, typedef_context_t&) const return 0; } -int VTypeERROR::emit_def(ostream&out) const +int VTypeERROR::emit_def(ostream&out, perm_string) const { out << "/* ERROR */"; return 1; } -int VTypeArray::emit_def(ostream&out) const +int VTypeArray::emit_def(ostream&out, perm_string name) 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 VType*raw_base = basic_type(); const VTypePrimitive*base = dynamic_cast (raw_base); if (base) { assert(dimensions() == 1); - base->emit_def(out); + base->emit_def(out, empty_perm_string); if (signed_flag_) out << " signed"; } else { - raw_base->emit_def(out); + raw_base->emit_def(out, empty_perm_string); } - dims.push_back(cur); - - while (! dims.empty()) { - cur = dims.front(); - dims.pop_front(); - out << "["; - if (cur->dimension(0).msb()) - errors += cur->dimension(0).msb()->emit(out, 0, 0); - else - out << "?error?"; - out << ":"; - if (cur->dimension(0).lsb()) - errors += cur->dimension(0).lsb()->emit(out, 0, 0); - else - out << "?error?"; - out << "]"; + if(raw_base->can_be_packed()) { + errors += emit_dimensions(out); + emit_name(out, name); + } else { + emit_name(out, name); + errors += emit_dimensions(out); } return errors; @@ -108,7 +90,36 @@ 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 VTypeArray::emit_dimensions(std::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; + } + dims.push_back(cur); + + while (! dims.empty()) { + cur = dims.front(); + dims.pop_front(); + + out << "["; + if (cur->dimension(0).msb() && cur->dimension(0).lsb()) { + // bounded array, unbounded arrays have msb() & lsb() nullified + 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 errors = 0; out << "enum {"; @@ -118,6 +129,7 @@ int VTypeEnum::emit_def(ostream&out) const out << ", \\" << names_[idx] << " "; out << "}"; + emit_name(out, name); return errors; } @@ -134,7 +146,10 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const out << "logic"; break; case INTEGER: - out << "bool [31:0]"; + out << "int"; + break; + case REAL: + out << "real"; break; case CHARACTER: out << "char"; @@ -146,22 +161,23 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const return errors; } -int VTypePrimitive::emit_def(ostream&out) const +int VTypePrimitive::emit_def(ostream&out, perm_string name) const { int errors = 0; errors += emit_primitive_type(out); + emit_name(out, name); return errors; } -int VTypeRange::emit_def(ostream&out) const +int VTypeRange::emit_def(ostream&out, perm_string name) const { int errors = 0; out << "/* Internal error: Don't know how to emit range */"; - errors += base_->emit_def(out); + errors += base_->emit_def(out, name); return errors; } -int VTypeRecord::emit_def(ostream&out) const +int VTypeRecord::emit_def(ostream&out, perm_string name) const { int errors = 0; out << "struct packed {"; @@ -170,11 +186,12 @@ int VTypeRecord::emit_def(ostream&out) const ; cur != elements_.end() ; ++cur) { perm_string element_name = (*cur)->peek_name(); const VType*element_type = (*cur)->peek_type(); - element_type->emit_def(out); + element_type->emit_def(out, empty_perm_string); out << " \\" << element_name << " ; "; } out << "}"; + emit_name(out, name); return errors; } @@ -183,10 +200,10 @@ int VTypeRecord::emit_def(ostream&out) const * 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 VTypeDef::emit_def(ostream&out, perm_string) const { int errors = 0; - out << "\\" << name_ << " "; + emit_name(out, name_); return errors; } @@ -198,8 +215,14 @@ int VTypeDef::emit_decl(ostream&out, perm_string name, bool reg_flag) const else out << "wire "; - errors += type_->emit_def(out); - out << " \\" << name << " "; + if(dynamic_cast(type_)) { + errors += type_->emit_def(out, name); + } else { + assert(name_ != empty_perm_string); + cout << "\\" << name_; + emit_name(out, name); + } + return errors; } @@ -225,8 +248,14 @@ int VTypeDef::emit_typedef(ostream&out, typedef_context_t&ctx) const int errors = type_->emit_typedef(out, ctx); flag = MARKED; + // Array types are used directly anyway and typedefs for unpacked + // arrays do not work currently + if(dynamic_cast(type_)) + out << "// "; + out << "typedef "; - errors += type_->emit_def(out); - out << " \\" << name_ << " ;" << endl; + errors += type_->emit_def(out, name_); + out << " ;" << endl; + return errors; } diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index ed21e5a99..3e4572049 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -39,53 +39,91 @@ void VType::write_type_to_stream(ostream&fd) const void VTypeArray::write_to_stream(ostream&fd) const { // Special case: std_logic_vector - if (etype_ == primitive_STDLOGIC) { + if (etype_ == &primitive_STDLOGIC) { fd << "std_logic_vector"; if (! ranges_.empty() && ! ranges_[0].is_box()) { - assert(ranges_.size() < 2); - 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 << ") "; + write_range_to_stream_(fd); } return; } - fd << "array "; + bool typedefed = false; + if(const VTypeDef*tdef = dynamic_cast(etype_)) { + tdef->write_to_stream(fd); + typedefed = true; + } else { + fd << "array "; + } + if (! ranges_.empty()) { assert(ranges_.size() < 2); 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 << ") "; + write_range_to_stream_(fd); + } + } + + if(!typedefed) { + fd << "of "; + etype_->write_to_stream(fd); + } +} + +void VTypeArray::write_range_to_stream_(std::ostream&fd) const +{ + assert(ranges_.size() < 2); + assert(ranges_[0].msb() && ranges_[0].lsb()); + + fd << "("; + if (ranges_[0].msb()) + ranges_[0].msb()->write_to_stream(fd); + else + fd << "<>"; + + fd << (ranges_[0].is_downto() ? " downto " : " to "); + + if (ranges_[0].lsb()) + ranges_[0].lsb()->write_to_stream(fd); + else + fd << "<>"; + fd << ") "; +} + +void VTypeArray::write_type_to_stream(ostream&fd) const +{ + // Special case: std_logic_vector + if (etype_ == &primitive_STDLOGIC) { + fd << "std_logic_vector"; + if (! ranges_.empty() && ! ranges_[0].is_box()) { + write_range_to_stream_(fd); + } + return; + } + + fd << "array "; + + if (! ranges_.empty()) { + assert(ranges_.size() < 2); + if (ranges_[0].is_box()) { + fd << "(INTEGER range <>) "; + } else { + write_range_to_stream_(fd); } } fd << "of "; - etype_->write_to_stream(fd); + + if(const VTypeDef*tdef = dynamic_cast(etype_)) { + tdef->write_to_stream(fd); + } else { + etype_->write_to_stream(fd); + } } void VTypeDef::write_type_to_stream(ostream&fd) const { - type_->write_to_stream(fd); + type_->write_type_to_stream(fd); } void VTypeDef::write_to_stream(ostream&fd) const @@ -102,9 +140,15 @@ void VTypePrimitive::write_to_stream(ostream&fd) const case INTEGER: fd << "integer"; break; + case REAL: + fd << "real"; + break; case STDLOGIC: fd << "std_logic"; break; + case CHARACTER: + fd << "character"; + break; case BOOLEAN: fd << "boolean"; break; @@ -145,3 +189,18 @@ void VTypeRecord::element_t::write_to_stream(ostream&fd) const fd << name_ << ": "; type_->write_to_stream(fd); } + +void VTypeEnum::write_to_stream(std::ostream&fd) const +{ + fd << "("; + for (vector::const_iterator it = names_.begin(); + it != names_.end(); ++it) { + if(it != names_.begin()) + fd << ","; + + fd << *it; + + } + fd << ")"; +} + diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 278be1f43..50e367d6a 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -46,7 +46,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @file64_support@ @CPPFLAGS@ @DEFS@ @PICFLAG@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ @@ -55,7 +55,7 @@ O = sys_table.o sys_convert.o sys_countdrivers.o sys_darray.o sys_deposit.o sys_ 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 \ + sys_priv.o sdf_parse.o sdf_lexor.o stringheap.o vams_simparam.o \ table_mod.o table_mod_lexor.o table_mod_parse.o OPP = vcd_priv2.o @@ -64,7 +64,7 @@ ifeq (@HAVE_LIBBZ2@,yes) O += sys_lxt.o lxt_write.o endif O += sys_lxt2.o lxt2_write.o -O += sys_fst.o fstapi.o fastlz.o +O += sys_fst.o fstapi.o fastlz.o lz4.o endif # Object files for v2005_math.vpi @@ -94,8 +94,13 @@ distclean: clean rm -f Makefile config.log rm -f vpi_config.h stamp-vpi_config-h +# The -U flag is used to skip checking paths that depend on that define having +# an explict value (i.e. the define is expected to be real code). cppcheck: $(O:.o=.c) $(OPP:.o=.cc) $(M:.o=.c) $(V:.o=.c) cppcheck --enable=all -f --suppressions-list=$(srcdir)/cppcheck.sup \ + -UYY_USER_INIT \ + -UYYPARSE_PARAM -UYYPRINT -Ushort -Uyyoverflow \ + -UYYTYPE_INT8 -UYYTYPE_INT16 -UYYTYPE_UINT8 -UYYTYPE_UINT16 \ --relative-paths=$(srcdir) $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in ../config.status diff --git a/vpi/cppcheck.sup b/vpi/cppcheck.sup index caf92d8d5..2ed297555 100644 --- a/vpi/cppcheck.sup +++ b/vpi/cppcheck.sup @@ -3,29 +3,144 @@ // problems will not be fixed. // fstapi.c from GTKWave -obsoleteFunctionsasctime:fstapi.c:672 -unreadVariable:fstapi.c:1317 -variableScope:fstapi.c:771 -variableScope:fstapi.c:1727 -variableScope:fstapi.c:2029 -variableScope:fstapi.c:2221 -variableScope:fstapi.c:2380 -variableScope:fstapi.c:2381 -variableScope:fstapi.c:2989 -variableScope:fstapi.c:3014 -variableScope:fstapi.c:3137 -variableScope:fstapi.c:3550 -variableScope:fstapi.c:3559 -variableScope:fstapi.c:4066 -variableScope:fstapi.c:4069 -variableScope:fstapi.c:4636 -variableScope:fstapi.c:4690 -variableScope:fstapi.c:4994 -variableScope:fstapi.c:4997 -variableScope:fstapi.c:5233 -variableScope:fstapi.c:5338 -variableScope:fstapi.c:5339 -variableScope:fstapi.c:5370 +obsoleteFunctionsasctime:fstapi.c:929 +obsoleteFunctionsalloca:fstapi.c:2303 +unreadVariable:fstapi.c:1647 +variableScope:fstapi.c:665 +variableScope:fstapi.c:1337 +variableScope:fstapi.c:1338 +variableScope:fstapi.c:1395 +variableScope:fstapi.c:1978 +variableScope:fstapi.c:2107 +variableScope:fstapi.c:2532 +variableScope:fstapi.c:2533 +variableScope:fstapi.c:2724 +variableScope:fstapi.c:2725 +variableScope:fstapi.c:2729 +variableScope:fstapi.c:2845 +variableScope:fstapi.c:2884 +variableScope:fstapi.c:2885 +variableScope:fstapi.c:3603 +variableScope:fstapi.c:3777 +variableScope:fstapi.c:3779 +variableScope:fstapi.c:4221 +variableScope:fstapi.c:4222 +variableScope:fstapi.c:4231 +variableScope:fstapi.c:4494 +variableScope:fstapi.c:4765 +variableScope:fstapi.c:4768 +variableScope:fstapi.c:5262 +variableScope:fstapi.c:5266 +variableScope:fstapi.c:5267 +variableScope:fstapi.c:5423 +variableScope:fstapi.c:5481 +variableScope:fstapi.c:5794 +variableScope:fstapi.c:5797 +variableScope:fstapi.c:6033 +variableScope:fstapi.c:6138 +variableScope:fstapi.c:6139 +variableScope:fstapi.c:6170 +variableScope:fstapi.c:6398 +// These functions are not used by Icarus +// fstReaderClrFacProcessMask() +unusedFunction:fstapi.c:3335 +// fstReaderClrFacProcessMaskAll() +unusedFunction:fstapi.c:3364 +// fstReaderGetAliasCount() +unusedFunction:fstapi.c:3427 +// fstReaderGetCurrentFlatScope() +unusedFunction:fstapi.c:3173 +// fstReaderGetAliasCount() +unusedFunction:fstapi.c:3270 +// fstReaderGetCurrentScopeUserInfo() +unusedFunction:fstapi.c:3187 +// fstReaderGetDateString() +unusedFunction:fstapi.c:3455 +// fstReaderGetDoubleEndianMatchState() +unusedFunction:fstapi.c:3441 +// fstReaderGetDumpActivityChangeTime() +unusedFunction:fstapi.c:3483 +// fstReaderGetDumpActivityChangeValue() +unusedFunction:fstapi.c:3498 +// fstReaderGetEndTime() +unusedFunction:fstapi.c:3392 +// fstReaderGetFacProcessMask() +unusedFunction:fstapi.c:3298 +// fstReaderGetFileType() +unusedFunction:fstapi.c:3462 +// fstReaderGetFseekFailed() +unusedFunction:fstapi.c:3283 +// fstReaderGetMaxHandle() +unusedFunction:fstapi.c:3420 +// fstReaderGetMemoryUsedByWriter() +unusedFunction:fstapi.c:3399 +// fstReaderGetNumberDumpActivityChanges() +unusedFunction:fstapi.c:3476 +// fstReaderGetScopeCount() +unusedFunction:fstapi.c:3406 +// fstReaderGetStartTime() +unusedFunction:fstapi.c:3385 +// fstReaderGetTimescale() +unusedFunction:fstapi.c:3378 +// fstReaderGetTimezero() +unusedFunction:fstapi.c:3469 +// fstReaderGetValueChangeSectionCount() +unusedFunction:fstapi.c:3434 +// fstReaderGetValueFromHandleAtTime() +unusedFunction:fstapi.c:5676 +// fstReaderGetVarCount() +unusedFunction:fstapi.c:3413 +// fstReaderGetVersionString() +unusedFunction:fstapi.c:3448 +// fstReaderIterBlocks() +unusedFunction:fstapi.c:4643 +// fstReaderIterBlocksSetNativeDoublesOnCallback() +unusedFunction:fstapi.c:3548 +// fstReaderIterateHier() +unusedFunction:fstapi.c:3773 +// fstReaderIterateHierRewind() +unusedFunction:fstapi.c:3753 +// fstReaderOpen() +unusedFunction:fstapi.c:4541 +// fstReaderOpenForUtilitiesOnly() +unusedFunction:fstapi.c:4533 +// fstReaderPushScope() +unusedFunction:fstapi.c:3235 +// fstReaderResetScope() +unusedFunction:fstapi.c:3224 +// fstReaderSetFacProcessMask() +unusedFunction:fstapi.c:3317 +// fstReaderSetFacProcessMaskAll() +unusedFunction:fstapi.c:3353 +// fstReaderSetLimitTimeRange() +unusedFunction:fstapi.c:3513 +// fstReaderSetUnlimitedTimeRange() +unusedFunction:fstapi.c:3526 +// fstReaderSetVcdExtensions() +unusedFunction:fstapi.c:3537 +// fstUtilityEscToBin() +unusedFunction:fstapi.c:6476 +// fstWriterCreateVar2() +unusedFunction:fstapi.c:2519 +// fstWriterEmitVariableLengthValueChange() +unusedFunction:fstapi.c:2838 +// fstWriterGetFseekFailed() +unusedFunction:fstapi.c:2502 +// fstWriterSetAttrEnd() +unusedFunction:fstapi.c:2705 +// fstWriterSetComment() +unusedFunction:fstapi.c:2357 +// fstWriterSetEnvVar() +unusedFunction:fstapi.c:2363 +// fstWriterSetFileType() +unusedFunction:fstapi.c:2234 +// fstWriterSetParallelMode() +unusedFunction:fstapi.c:2462 +// fstWriterSetTimezero() +unusedFunction:fstapi.c:2427 + +// These functions are not used by Icarus +//unusedFunction:fstapi.c:226 // lxt2_write.c from GTKWave obsoleteFunctionsalloca:lxt2_write.c:1813 @@ -41,6 +156,27 @@ variableScope:lxt2_write.c:587 variableScope:lxt2_write.c:1157 variableScope:lxt2_write.c:1613 variableScope:lxt2_write.c:2060 +// These functions are not used by Icarus +// lxt2_wr_emit_value_int() +unusedFunction:lxt2_write.c:1611 +// lxt2_wr_inc_time_by_delta() +unusedFunction:lxt2_write.c:997 +// lxt2_wr_inc_time_by_delta64() +unusedFunction:lxt2_write.c:1007 +// lxt2_wr_set_checkpoint_off() +unusedFunction:lxt2_write.c:835 +// lxt2_wr_set_checkpoint_on() +unusedFunction:lxt2_write.c:843 +// lxt2_wr_set_maxgranule() +unusedFunction:lxt2_write.c:1567 +// lxt2_wr_set_partial_preference() +unusedFunction:lxt2_write.c:812 +// lxt2_wr_set_timezero() +unusedFunction:lxt2_write.c:2198 +// lxt2_wr_symbol_bracket_stripping() +unusedFunction:lxt2_write.c:1581 +// lxt2_wr_symbol_find() +unusedFunction:lxt2_write.c:877 // lxt_write.c from GTKWave variableScope:lxt_write.c:31 @@ -66,6 +202,89 @@ variableScope:lxt_write.c:2595 variableScope:lxt_write.c:2596 variableScope:lxt_write.c:2597 variableScope:lxt_write.c:2598 +// These functions are not used by Icarus +// lt_emit_value_int() +unusedFunction:lxt_write.c:1661 +// lt_emit_value_string() +unusedFunction:lxt_write.c:2144 +// lt_inc_time_by_delta() +unusedFunction:lxt_write.c:1374 +// lt_inc_time_by_delta64() +unusedFunction:lxt_write.c:1384 +// lt_set_chg_compress() +unusedFunction:lxt_write.c:1457 +// lt_set_dict_compress() +unusedFunction:lxt_write.c:1474 +// lt_set_time() +unusedFunction:lxt_write.c:1379 +// lt_set_timezero() +unusedFunction:lxt_write.c:2820 +// lt_symbol_bracket_stripping() +unusedFunction:lxt_write.c:1585 +// lt_symbol_find() +unusedFunction:lxt_write.c:1277 + +// fastlz.c from GTKWave +// These functions are not used by Icarus +// fastlz_compress_level() +unusedFunction:fastlz.c:150 + +// lz4.c from GTKWave +// These functions are not used by Icarus +// LZ4_compress_continue() +unusedFunction:lz4.c:819 +// LZ4_compress_forceExtDict() +unusedFunction:lz4.c:831 +// LZ4_compress_limitedOutput() +unusedFunction:lz4.c:666 +// LZ4_compress_limitedOutput_continue() +unusedFunction:lz4.c:824 +// LZ4_compress_limitedOutput_withState() +unusedFunction:lz4.c:1246 +// LZ4_compress_withState() +unusedFunction:lz4.c:1235 +// LZ4_create() +unusedFunction:lz4.c:1215 +// LZ4_createStream() +unusedFunction:lz4.c:701 +// LZ4_createStreamDecode() +unusedFunction:lz4.c:1074 +// LZ4_decompress_fast_continue() +unusedFunction:lz4.c:1129 +// LZ4_decompress_fast_usingDict() +unusedFunction:lz4.c:1172 +// LZ4_decompress_fast_withPrefix64k() +unusedFunction:lz4.c:1264 +// LZ4_decompress_safe_continue() +unusedFunction:lz4.c:1109 +// LZ4_decompress_safe_forceExtDict() +unusedFunction:lz4.c:1179 +// LZ4_decompress_safe_usingDict() +unusedFunction:lz4.c:1166 +// LZ4_decompress_safe_withPrefix64k() +unusedFunction:lz4.c:1259 +// LZ4_freeStream() +unusedFunction:lz4.c:708 +// LZ4_freeStreamDecode() +unusedFunction:lz4.c:1081 +// LZ4_loadDict() +unusedFunction:lz4.c:715 +// LZ4_resetStreamState() +unusedFunction:lz4.c:1208 +// LZ4_setStreamDecode() +unusedFunction:lz4.c:1094 +// LZ4_sizeofState() +unusedFunction:lz4.c:1233 +// LZ4_sizeofStreamState() +unusedFunction:lz4.c:1200 +// LZ4_slideInputBuffer() +unusedFunction:lz4.c:1222 +// LZ4_uncompress() +unusedFunction:lz4.c:1194 +// LZ4_uncompress_unknownOutputSize() +unusedFunction:lz4.c:1195 +// LZ4_versionNumber() +unusedFunction:lz4.c:372 // 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/fastlz.c b/vpi/fastlz.c index 8e14ecfc0..50bf56a46 100644 --- a/vpi/fastlz.c +++ b/vpi/fastlz.c @@ -1,4 +1,4 @@ -/* +/* FastLZ - lightning-fast lossless compression library Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) @@ -53,7 +53,7 @@ #define FASTLZ_INLINE inline #elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) #define FASTLZ_INLINE __inline -#else +#else #define FASTLZ_INLINE #endif @@ -87,7 +87,7 @@ int fastlz_decompress(const void* input, int length, void* output, int maxout); #define MAX_DISTANCE 8192 #if !defined(FASTLZ_STRICT_ALIGN) -#define FASTLZ_READU16(p) *((const flzuint16*)(p)) +#define FASTLZ_READU16(p) *((const flzuint16*)(p)) #else #define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) #endif @@ -215,7 +215,7 @@ static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) { distance = 1; - ip += 3; + /* ip += 3; */ /* scan-build, never used */ ref = anchor - 1 + 3; goto match; } @@ -233,7 +233,7 @@ static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* *hslot = anchor; /* is this a match? check the first 3 bytes */ - if(distance==0 || + if(distance==0 || #if FASTLZ_LEVEL==1 (distance >= MAX_DISTANCE) || #else @@ -246,11 +246,11 @@ static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* /* far, needs at least 5-byte match */ if(distance >= MAX_DISTANCE) { - if(*ip++ != *ref++ || *ip++!= *ref++) + if(*ip++ != *ref++ || *ip++!= *ref++) goto literal; len += 2; } - + match: #endif @@ -346,7 +346,7 @@ static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* while(len > MAX_LEN-2) { *op++ = (7 << 5) + (distance >> 8); - *op++ = MAX_LEN - 2 - 7 -2; + *op++ = MAX_LEN - 2 - 7 -2; *op++ = (distance & 255); len -= MAX_LEN-2; } @@ -457,7 +457,7 @@ static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void ref = op - ofs - MAX_DISTANCE; } #endif - + #ifdef FASTLZ_SAFE if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) return 0; @@ -530,7 +530,7 @@ static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void return 0; #endif - *op++ = *ip++; + *op++ = *ip++; for(--ctrl; ctrl; ctrl--) *op++ = *ip++; diff --git a/vpi/fastlz.h b/vpi/fastlz.h index e0512c190..8b4eac2e8 100644 --- a/vpi/fastlz.h +++ b/vpi/fastlz.h @@ -1,4 +1,4 @@ -/* +/* FastLZ - lightning-fast lossless compression library Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) @@ -47,11 +47,11 @@ extern "C" { #endif /** - Compress a block of data in the input buffer and returns the size of - compressed block. The size of input buffer is specified by length. The + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The minimum input buffer size is 16. - The output buffer must be at least 5% larger than the input buffer + The output buffer must be at least 5% larger than the input buffer and can not be smaller than 66 bytes. If the input is not compressible, the return value might be larger than @@ -63,9 +63,9 @@ extern "C" { int fastlz_compress(const void* input, int length, void* output); /** - Decompress a block of compressed data and returns the size of the - decompressed block. If error occurs, e.g. the compressed data is - corrupted or the output buffer is not large enough, then 0 (zero) + Decompress a block of compressed data and returns the size of the + decompressed block. If error occurs, e.g. the compressed data is + corrupted or the output buffer is not large enough, then 0 (zero) will be returned instead. The input buffer and the output buffer can not overlap. @@ -74,14 +74,14 @@ int fastlz_compress(const void* input, int length, void* output); more than what is specified in maxout. */ -int fastlz_decompress(const void* input, int length, void* output, int maxout); +int fastlz_decompress(const void* input, int length, void* output, int maxout); /** - Compress a block of data in the input buffer and returns the size of - compressed block. The size of input buffer is specified by length. The + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The minimum input buffer size is 16. - The output buffer must be at least 5% larger than the input buffer + The output buffer must be at least 5% larger than the input buffer and can not be smaller than 66 bytes. If the input is not compressible, the return value might be larger than @@ -89,14 +89,14 @@ int fastlz_decompress(const void* input, int length, void* output, int maxout); The input buffer and the output buffer can not overlap. - Compression level can be specified in parameter level. At the moment, + Compression level can be specified in parameter level. At the moment, only level 1 and level 2 are supported. Level 1 is the fastest compression and generally useful for short data. Level 2 is slightly slower but it gives better compression ratio. Note that the compressed data, regardless of the level, can always be decompressed using the function fastlz_decompress above. -*/ +*/ int fastlz_compress_level(int level, const void* input, int length, void* output); diff --git a/vpi/fstapi.c b/vpi/fstapi.c index a2d00454b..b0d7dfc40 100644 --- a/vpi/fstapi.c +++ b/vpi/fstapi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2013 Tony Bybell. + * Copyright (c) 2009-2014 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,10 +20,28 @@ * DEALINGS IN THE SOFTWARE. */ +/* + * possible disables: + * + * FST_DYNAMIC_ALIAS_DISABLE : dynamic aliases are not processed + * FST_DYNAMIC_ALIAS2_DISABLE : new encoding for dynamic aliases is not generated + * FST_WRITEX_DISABLE : fast write I/O routines are disabled + * + * possible enables: + * + * FST_DEBUG : not for production use, only enable for development + * FST_REMOVE_DUPLICATE_VC : glitch removal (has writer performance impact) + * HAVE_LIBPTHREAD -> FST_WRITER_PARALLEL : enables inclusion of parallel writer code + * FST_DO_MISALIGNED_OPS (defined automatically for x86 and some others) : CPU architecture can handle misaligned loads/stores + * _WAVE_HAVE_JUDY : use Judy arrays instead of Jenkins (undefine if LGPL is not acceptable) + * + */ + #include #include "fstapi.h" #include "fastlz.h" +#include "lz4.h" #ifndef HAVE_LIBPTHREAD #undef FST_WRITER_PARALLEL @@ -33,7 +51,11 @@ #include #endif -#if HAVE_ALLOCA_H +#ifdef __MINGW32__ +#include +#endif + +#ifdef HAVE_ALLOCA_H #include #elif defined(__GNUC__) #ifndef __MINGW32__ @@ -59,7 +81,7 @@ #include #else /* should be more than enough for fstWriterSetSourceStem() */ -#define FST_PATH_HASHMASK ((1UL << 16) - 1) +#define FST_PATH_HASHMASK ((1UL << 16) - 1) typedef const void *Pcvoid_t; typedef void *Pvoid_t; typedef void **PPvoid_t; @@ -69,30 +91,41 @@ void JenkinsFree(void *base_i, uint32_t hashmask); void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask); #endif -#undef FST_DEBUG -#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) +#ifndef FST_WRITEX_DISABLE +#define FST_WRITEX_MAX (64 * 1024) +#else +#define fstWritex(a,b,c) fstFwrite((b), (c), 1, fv) +#endif -#define FST_WRITER_STR "fstWriter" -#define FST_ID_NAM_SIZ (512) -#define FST_ID_NAM_ATTR_SIZ (65536+4096) -#define FST_DOUBLE_ENDTEST (2.7182818284590452354) -#define FST_HDR_SIM_VERSION_SIZE (128) -#define FST_HDR_DATE_SIZE (119) -#define FST_HDR_FILETYPE_SIZE (1) -#define FST_HDR_TIMEZERO_SIZE (8) -#define FST_GZIO_LEN (32768) + +/* these defines have a large impact on writer speed when a model has a */ +/* huge number of symbols. as a default, use 128MB and increment when */ +/* every 1M signals are defined. */ +#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 (1000000) +#define FST_ACTIVATE_HUGE_INC (1000000) + +#define FST_WRITER_STR "fstWriter" +#define FST_ID_NAM_SIZ (512) +#define FST_ID_NAM_ATTR_SIZ (65536+4096) +#define FST_DOUBLE_ENDTEST (2.7182818284590452354) +#define FST_HDR_SIM_VERSION_SIZE (128) +#define FST_HDR_DATE_SIZE (119) +#define FST_HDR_FILETYPE_SIZE (1) +#define FST_HDR_TIMEZERO_SIZE (8) +#define FST_GZIO_LEN (32768) +#define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024) #if defined(__i386__) || defined(__x86_64__) || defined(_AIX) #define FST_DO_MISALIGNED_OPS #endif #if defined(__APPLE__) && defined(__MACH__) -#define FST_MACOSX +#define FST_MACOSX +#include #endif @@ -110,8 +143,14 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3 #endif #endif - -/* the recoded "extra" values... */ +/* + * the recoded "extra" values... + * note that FST_RCV_Q is currently unused and is for future expansion. + * its intended use is as another level of escape such that any arbitrary + * value can be stored as the value: { time_delta, 8 bits, FST_RCV_Q }. + * this is currently not implemented so that the branchless decode is: + * uint32_t shcnt = 2 << (vli & 1); tdelta = vli >> shcnt; + */ #define FST_RCV_X (1 | (0<<1)) #define FST_RCV_Z (1 | (1<<1)) #define FST_RCV_H (1 | (2<<1)) @@ -119,6 +158,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3 #define FST_RCV_W (1 | (4<<1)) #define FST_RCV_L (1 | (5<<1)) #define FST_RCV_D (1 | (6<<1)) +#define FST_RCV_Q (1 | (7<<1)) #define FST_RCV_STR "xzhuwl-?" /* 01234567 */ @@ -134,7 +174,86 @@ return(fopen(nam, mode)); } -/* +/* + * system-specific temp file handling + */ +#ifdef __MINGW32__ + +static FILE* tmpfile_open(char **nam) +{ +char *fname = NULL; +TCHAR szTempFileName[MAX_PATH]; +TCHAR lpTempPathBuffer[MAX_PATH]; +DWORD dwRetVal = 0; +UINT uRetVal = 0; +FILE *fh = NULL; + +if(nam) /* cppcheck warning fix: nam is always defined, so this is not needed */ + { + dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); + if((dwRetVal > MAX_PATH) || (dwRetVal == 0)) + { + fprintf(stderr, "GetTempPath() failed in "__FILE__" line %d, exiting.\n", __LINE__); + exit(255); + } + else + { + uRetVal = GetTempFileName(lpTempPathBuffer, TEXT("FSTW"), 0, szTempFileName); + if (uRetVal == 0) + { + fprintf(stderr, "GetTempFileName() failed in "__FILE__" line %d, exiting.\n", __LINE__); + exit(255); + } + else + { + fname = strdup(szTempFileName); + } + } + + if(fname) + { + *nam = fname; + fh = unlink_fopen(fname, "w+b"); + } + } + +return(fh); +} + +#else + +static FILE* tmpfile_open(char **nam) +{ +FILE *f = tmpfile(); /* replace with mkstemp() + fopen(), etc if this is not good enough */ +if(nam) { *nam = NULL; } +return(f); +} + +#endif + + +static void tmpfile_close(FILE **f, char **nam) +{ +if(f) + { + if(*f) { fclose(*f); *f = NULL; } + } + +if(nam) + { + if(*nam) + { + unlink(*nam); + free(*nam); + *nam = NULL; + } + } +} + +/*****************************************/ + + +/* * to remove warn_unused_result compile time messages * (in the future there needs to be results checking) */ @@ -157,7 +276,7 @@ return(ftruncate(fd, length)); /* * realpath compatibility */ -static char *fstRealpath(const char *path, char *resolved_path) +static char *fstRealpath(const char *path, char *resolved_path) { #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH @@ -167,7 +286,7 @@ if(!resolved_path) resolved_path = malloc(PATH_MAX+1); /* fixes bug on Leopard when resolved_path == NULL */ } #endif - + return(realpath(path, resolved_path)); #else @@ -190,19 +309,21 @@ return(NULL); #if defined __CYGWIN__ || defined __MINGW32__ #include #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off)) -#define fstMunmap(__addr,__len) free(__addr) +#define fstMunmap(__addr,__len) free(__addr) static void *fstMmap2(size_t __len, int __fd, off_t __off) { +(void)__off; + unsigned char *pnt = malloc(__len); off_t cur_offs = lseek(__fd, 0, SEEK_CUR); size_t i; lseek(__fd, 0, SEEK_SET); for(i=0;i<__len;i+=SSIZE_MAX) - { - read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); - } + { + read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); + } lseek(__fd, cur_offs, SEEK_SET); return(pnt); } @@ -214,7 +335,7 @@ return(pnt); #define FST_CADDR_T_CAST #endif #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) (void*)mmap(FST_CADDR_T_CAST (__addr),(__len),(__prot),(__flags),(__fd),(__off)) -#define fstMunmap(__addr,__len) { if(__addr) munmap(FST_CADDR_T_CAST (__addr),(__len)); } +#define fstMunmap(__addr,__len) { if(__addr) munmap(FST_CADDR_T_CAST (__addr),(__len)); } #endif @@ -245,10 +366,10 @@ unsigned char buf[8]; int i; for(i=7;i>=0;i--) - { - buf[i] = v & 0xff; - v >>= 8; - } + { + buf[i] = v & 0xff; + v >>= 8; + } fstFwrite(buf, 8, 1, handle); return(8); @@ -259,14 +380,14 @@ static uint64_t fstReaderUint64(FILE *f) { uint64_t val = 0; unsigned char buf[sizeof(uint64_t)]; -int i; +unsigned int i; fstFread(buf, sizeof(uint64_t), 1, f); for(i=0;i>7)) +while((nxt = nxt>>7)) /* determine len to avoid temp buffer copying to cut down on load-hit-store */ { - *(spnt++) = (v&0x7f) | 0x80; + cnt++; + } + +pnt -= cnt; +spnt = pnt; +cnt--; + +for(i=0;i>7; + *(spnt++) = ((unsigned char)v) | 0x80; v = nxt; } -*(spnt++) = (v&0x7f); - -do { - *(--pnt) = *(--spnt); - } while(spnt != buf); +*spnt = (unsigned char)v; return(pnt); } @@ -361,14 +489,14 @@ uint64_t nxt; while((nxt = v>>7)) { - *(pnt++) = (v&0x7f) | 0x80; + *(pnt++) = ((unsigned char)v) | 0x80; v = nxt; } -*(pnt++) = (v&0x7f); +*(pnt++) = (unsigned char)v; return(pnt); } - + static uint64_t fstGetVarint64(unsigned char *mem, int *skiplen) { @@ -390,8 +518,8 @@ for(;;) } mem--; } - -return(rc); + +return(rc); } @@ -403,10 +531,10 @@ uint32_t rc = 0; int ch; do - { - ch = fgetc(f); - *(mem++) = ch; - } while(ch & 0x80); + { + ch = fgetc(f); + *(mem++) = ch; + } while(ch & 0x80); mem--; for(;;) @@ -419,8 +547,8 @@ for(;;) } mem--; } - -return(rc); + +return(rc); } @@ -432,10 +560,10 @@ uint32_t rc = 0; int ch; do - { - ch = fgetc(f); - *(mem++) = ch; - } while(ch & 0x80); + { + ch = fgetc(f); + *(mem++) = ch; + } while(ch & 0x80); *skiplen = mem - buf; mem--; @@ -449,8 +577,8 @@ for(;;) } mem--; } - -return(rc); + +return(rc); } @@ -462,10 +590,10 @@ uint64_t rc = 0; int ch; do - { - ch = fgetc(f); - *(mem++) = ch; - } while(ch & 0x80); + { + ch = fgetc(f); + *(mem++) = ch; + } while(ch & 0x80); mem--; for(;;) @@ -478,8 +606,8 @@ for(;;) } mem--; } - -return(rc); + +return(rc); } @@ -492,10 +620,65 @@ int len; while((nxt = v>>7)) { - *(pnt++) = (v&0x7f) | 0x80; + *(pnt++) = ((unsigned char)v) | 0x80; v = nxt; } -*(pnt++) = (v&0x7f); +*(pnt++) = (unsigned char)v; + +len = pnt-buf; +fstFwrite(buf, len, 1, handle); +return(len); +} + + +/* signed integer read/write routines are currently unused */ +static int64_t fstGetSVarint64(unsigned char *mem, int *skiplen) +{ +unsigned char *mem_orig = mem; +int64_t rc = 0; +const int64_t one = 1; +const int siz = sizeof(int64_t) * 8; +int shift = 0; +unsigned char byt; + +do { + byt = *(mem++); + rc |= ((int64_t)(byt & 0x7f)) << shift; + shift += 7; + + } while(byt & 0x80); + +if((shift>= 7; + + if (((!v) && (!(byt & 0x40))) || ((v == -1) && (byt & 0x40))) + { + more = 0; + byt &= 0x7f; + } + + *(pnt++) = byt; + } while(more); len = pnt-buf; fstFwrite(buf, len, 1, handle); @@ -544,6 +727,7 @@ uint32_t maxvalpos; unsigned vc_emitted : 1; unsigned is_initial_time : 1; +unsigned fourpack : 1; unsigned fastpack : 1; int64_t timezero; @@ -602,6 +786,11 @@ Pvoid_t path_array; uint32_t path_array_count; unsigned fseek_failed : 1; + +char *geom_handle_nam; +char *valpos_handle_nam; +char *curval_handle_nam; +char *tchn_handle_nam; }; @@ -610,13 +799,13 @@ static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, off_t offs int rc = fseeko(stream, offset, whence); if(rc<0) - { - xc->fseek_failed = 1; + { + xc->fseek_failed = 1; #ifdef FST_DEBUG - fprintf(stderr, "Seek to #%"PRId64" (whence = %d) failed!\n", offset, whence); - perror("Why"); + fprintf(stderr, "Seek to #%"PRId64" (whence = %d) failed!\n", offset, whence); + perror("Why"); #endif - } + } return(rc); } @@ -638,10 +827,10 @@ pnt += 4; while((nxt = v>>7)) { - *(pnt++) = (v&0x7f) | 0x80; + *(pnt++) = ((unsigned char)v) | 0x80; v = nxt; } -*(pnt++) = (v&0x7f); +*(pnt++) = (unsigned char)v; memcpy(pnt, dbuf, siz); len = pnt-buf + siz; @@ -665,18 +854,18 @@ pnt += 4; while((nxt = v>>7)) { - *(pnt++) = (v&0x7f) | 0x80; + *(pnt++) = ((unsigned char)v) | 0x80; v = nxt; } -*(pnt++) = (v&0x7f); +*(pnt++) = (unsigned char)v; v = siz; while((nxt = v>>7)) { - *(pnt++) = (v&0x7f) | 0x80; + *(pnt++) = ((unsigned char)v) | 0x80; v = nxt; } -*(pnt++) = (v&0x7f); +*(pnt++) = (unsigned char)v; memcpy(pnt, dbuf, siz); @@ -696,60 +885,60 @@ char dbuf[FST_HDR_DATE_SIZE]; double endtest = FST_DOUBLE_ENDTEST; time_t walltime; -#define FST_HDR_OFFS_TAG (0) -fputc(FST_BL_HDR, xc->handle); /* +0 tag */ +#define FST_HDR_OFFS_TAG (0) +fputc(FST_BL_HDR, xc->handle); /* +0 tag */ -#define FST_HDR_OFFS_SECLEN (FST_HDR_OFFS_TAG + 1) -fstWriterUint64(xc->handle, 329); /* +1 section length */ +#define FST_HDR_OFFS_SECLEN (FST_HDR_OFFS_TAG + 1) +fstWriterUint64(xc->handle, 329); /* +1 section length */ -#define FST_HDR_OFFS_START_TIME (FST_HDR_OFFS_SECLEN + 8) -fstWriterUint64(xc->handle, 0); /* +9 start time */ +#define FST_HDR_OFFS_START_TIME (FST_HDR_OFFS_SECLEN + 8) +fstWriterUint64(xc->handle, 0); /* +9 start time */ -#define FST_HDR_OFFS_END_TIME (FST_HDR_OFFS_START_TIME + 8) -fstWriterUint64(xc->handle, 0); /* +17 end time */ +#define FST_HDR_OFFS_END_TIME (FST_HDR_OFFS_START_TIME + 8) +fstWriterUint64(xc->handle, 0); /* +17 end time */ -#define FST_HDR_OFFS_ENDIAN_TEST (FST_HDR_OFFS_END_TIME + 8) -fstFwrite(&endtest, 8, 1, xc->handle); /* +25 endian test for reals */ +#define FST_HDR_OFFS_ENDIAN_TEST (FST_HDR_OFFS_END_TIME + 8) +fstFwrite(&endtest, 8, 1, xc->handle); /* +25 endian test for reals */ -#define FST_HDR_OFFS_MEM_USED (FST_HDR_OFFS_ENDIAN_TEST + 8) +#define FST_HDR_OFFS_MEM_USED (FST_HDR_OFFS_ENDIAN_TEST + 8) 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 */ +#define FST_HDR_OFFS_NUM_SCOPES (FST_HDR_OFFS_MEM_USED + 8) +fstWriterUint64(xc->handle, 0); /* +41 scope creation count */ -#define FST_HDR_OFFS_NUM_VARS (FST_HDR_OFFS_NUM_SCOPES + 8) -fstWriterUint64(xc->handle, 0); /* +49 var creation count */ +#define FST_HDR_OFFS_NUM_VARS (FST_HDR_OFFS_NUM_SCOPES + 8) +fstWriterUint64(xc->handle, 0); /* +49 var creation count */ -#define FST_HDR_OFFS_MAXHANDLE (FST_HDR_OFFS_NUM_VARS + 8) -fstWriterUint64(xc->handle, 0); /* +57 max var idcode */ +#define FST_HDR_OFFS_MAXHANDLE (FST_HDR_OFFS_NUM_VARS + 8) +fstWriterUint64(xc->handle, 0); /* +57 max var idcode */ -#define FST_HDR_OFFS_SECTION_CNT (FST_HDR_OFFS_MAXHANDLE + 8) -fstWriterUint64(xc->handle, 0); /* +65 vc section count */ +#define FST_HDR_OFFS_SECTION_CNT (FST_HDR_OFFS_MAXHANDLE + 8) +fstWriterUint64(xc->handle, 0); /* +65 vc section count */ -#define FST_HDR_OFFS_TIMESCALE (FST_HDR_OFFS_SECTION_CNT + 8) -fputc((-9)&255, xc->handle); /* +73 timescale 1ns */ +#define FST_HDR_OFFS_TIMESCALE (FST_HDR_OFFS_SECTION_CNT + 8) +fputc((-9)&255, xc->handle); /* +73 timescale 1ns */ -#define FST_HDR_OFFS_SIM_VERSION (FST_HDR_OFFS_TIMESCALE + 1) +#define FST_HDR_OFFS_SIM_VERSION (FST_HDR_OFFS_TIMESCALE + 1) memset(vbuf, 0, FST_HDR_SIM_VERSION_SIZE); strcpy(vbuf, FST_WRITER_STR); fstFwrite(vbuf, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); /* +74 version */ -#define FST_HDR_OFFS_DATE (FST_HDR_OFFS_SIM_VERSION + FST_HDR_SIM_VERSION_SIZE) +#define FST_HDR_OFFS_DATE (FST_HDR_OFFS_SIM_VERSION + FST_HDR_SIM_VERSION_SIZE) memset(dbuf, 0, FST_HDR_DATE_SIZE); time(&walltime); strcpy(dbuf, asctime(localtime(&walltime))); -fstFwrite(dbuf, FST_HDR_DATE_SIZE, 1, xc->handle); /* +202 date */ +fstFwrite(dbuf, FST_HDR_DATE_SIZE, 1, xc->handle); /* +202 date */ /* date size is deliberately overspecified at 119 bytes (originally 128) in order to provide backfill for new args */ -#define FST_HDR_OFFS_FILETYPE (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE) -fputc(xc->filetype, xc->handle); /* +321 filetype */ +#define FST_HDR_OFFS_FILETYPE (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE) +fputc(xc->filetype, xc->handle); /* +321 filetype */ -#define FST_HDR_OFFS_TIMEZERO (FST_HDR_OFFS_FILETYPE + FST_HDR_FILETYPE_SIZE) -fstWriterUint64(xc->handle, xc->timezero); /* +322 timezero */ +#define FST_HDR_OFFS_TIMEZERO (FST_HDR_OFFS_FILETYPE + FST_HDR_FILETYPE_SIZE) +fstWriterUint64(xc->handle, xc->timezero); /* +322 timezero */ -#define FST_HDR_LENGTH (FST_HDR_OFFS_TIMEZERO + FST_HDR_TIMEZERO_SIZE) - /* +330 next section starts here */ +#define FST_HDR_LENGTH (FST_HDR_OFFS_TIMEZERO + FST_HDR_TIMEZERO_SIZE) + /* +330 next section starts here */ fflush(xc->handle); } @@ -777,42 +966,44 @@ fflush(xc->handle); /* do mappings */ if(!xc->valpos_mem) - { - fflush(xc->valpos_handle); - xc->valpos_mem = fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->valpos_handle), 0); - } + { + fflush(xc->valpos_handle); + xc->valpos_mem = fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->valpos_handle), 0); + } if(!xc->curval_mem) - { - fflush(xc->curval_handle); - xc->curval_mem = fstMmap(NULL, xc->maxvalpos, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->curval_handle), 0); - } + { + fflush(xc->curval_handle); + xc->curval_mem = fstMmap(NULL, xc->maxvalpos, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->curval_handle), 0); + } } static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing) { +(void)is_closing; + fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); xc->valpos_mem = NULL; #if defined __CYGWIN__ || defined __MINGW32__ if(xc->curval_mem) - { - if(!is_closing) /* need to flush out for next emulated mmap() read */ - { - unsigned char *pnt = xc->curval_mem; - int __fd = fileno(xc->curval_handle); - off_t cur_offs = lseek(__fd, 0, SEEK_CUR); - size_t i; - size_t __len = xc->maxvalpos; + { + if(!is_closing) /* need to flush out for next emulated mmap() read */ + { + unsigned char *pnt = xc->curval_mem; + int __fd = fileno(xc->curval_handle); + off_t cur_offs = lseek(__fd, 0, SEEK_CUR); + size_t i; + size_t __len = xc->maxvalpos; - lseek(__fd, 0, SEEK_SET); - for(i=0;i<__len;i+=SSIZE_MAX) - { - write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); - } - lseek(__fd, cur_offs, SEEK_SET); - } - } + lseek(__fd, 0, SEEK_SET); + for(i=0;i<__len;i+=SSIZE_MAX) + { + write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); + } + lseek(__fd, cur_offs, SEEK_SET); + } + } #endif fstMunmap(xc->curval_mem, xc->maxvalpos); @@ -827,65 +1018,80 @@ xc->curval_mem = NULL; static void fstDetermineBreakSize(struct fstWriterContext *xc) { #if defined(__linux__) || defined(FST_MACOSX) +int was_set = 0; #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 + { + char buf[257]; + char *s; + while(!feof(f)) + { + buf[0] = 0; + s = fgets(buf, 256, f); + if(s && *s) + { + if(!strncmp(s, "MemTotal:", 9)) + { + size_t v = atol(s+10); + v *= 1024; /* convert to bytes */ + 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; + } - 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; + } + } + } + } - xc->fst_huge_break_size = v; - was_set = 1; - break; - } - } - } - } - -#ifdef __linux__ - fclose(f); -#else - pclose(f); -#endif - } + fclose(f); + } if(!was_set) + { + xc->fst_huge_break_size = FST_BREAK_SIZE; + } +#else +int mib[2]; +int64_t v; +size_t length; + +mib[0] = CTL_HW; +mib[1] = HW_MEMSIZE; +length = sizeof(int64_t); +if(!sysctl(mib, 2, &v, &length, NULL, 0)) + { + v /= 8; + + if(v > (int64_t)FST_BREAK_SIZE) + { + if(v > (int64_t)FST_BREAK_SIZE_MAX) + { + v = FST_BREAK_SIZE_MAX; + } + + xc->fst_huge_break_size = v; + was_set = 1; + } + } + +if(!was_set) + { + xc->fst_huge_break_size = FST_BREAK_SIZE; + } +#endif +#else +xc->fst_huge_break_size = FST_BREAK_SIZE; #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; @@ -903,53 +1109,56 @@ 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")))) +if((!nam)|| + (!(xc->handle=unlink_fopen(nam, "w+b")))) { free(xc); xc=NULL; } else { - int flen = strlen(nam); - char *hf = calloc(1, flen + 6); + int flen = strlen(nam); + char *hf = calloc(1, flen + 6); - memcpy(hf, nam, flen); - strcpy(hf + flen, ".hier"); - xc->hier_handle = unlink_fopen(hf, "w+b"); + memcpy(hf, nam, flen); + strcpy(hf + flen, ".hier"); + xc->hier_handle = unlink_fopen(hf, "w+b"); - xc->geom_handle = tmpfile(); /* .geom */ - xc->valpos_handle = tmpfile(); /* .offs */ - xc->curval_handle = tmpfile(); /* .bits */ - xc->tchn_handle = tmpfile(); /* .tchn */ - xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; - xc->vchg_mem = malloc(xc->vchg_alloc_siz); + xc->geom_handle = tmpfile_open(&xc->geom_handle_nam); /* .geom */ + xc->valpos_handle = tmpfile_open(&xc->valpos_handle_nam); /* .offs */ + xc->curval_handle = tmpfile_open(&xc->curval_handle_nam); /* .bits */ + xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* .tchn */ + xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; + xc->vchg_mem = malloc(xc->vchg_alloc_siz); - free(hf); - if(xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchg_mem && xc->tchn_handle) - { - xc->filename = strdup(nam); - xc->is_initial_time = 1; + if(xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchg_mem && xc->tchn_handle) + { + xc->filename = strdup(nam); + xc->is_initial_time = 1; - fstWriterEmitHdrBytes(xc); - xc->nan = strtod("NaN", NULL); + 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); + pthread_mutex_init(&xc->mutex, NULL); + pthread_attr_init(&xc->thread_attr); + pthread_attr_setdetachstate(&xc->thread_attr, PTHREAD_CREATE_DETACHED); #endif - } - else - { - if(xc->hier_handle) fclose(xc->hier_handle); - if(xc->geom_handle) fclose(xc->geom_handle); - if(xc->valpos_handle) fclose(xc->valpos_handle); - if(xc->curval_handle) fclose(xc->curval_handle); - if(xc->tchn_handle) fclose(xc->tchn_handle); - free(xc->vchg_mem); - free(xc); - xc=NULL; - } - } + } + else + { + fclose(xc->handle); + if(xc->hier_handle) { fclose(xc->hier_handle); unlink(hf); } + tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam); + tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam); + tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam); + tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); + free(xc->vchg_mem); + free(xc); + xc=NULL; + } + + free(hf); + } return(xc); } @@ -963,48 +1172,48 @@ static void fstWriterEmitSectionHeader(void *ctx) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) - { - unsigned long destlen; - unsigned char *dmem; + { + unsigned long destlen; + unsigned char *dmem; int rc; - destlen = xc->maxvalpos; - dmem = malloc(destlen); - rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, 9); + destlen = xc->maxvalpos; + dmem = malloc(compressBound(destlen)); + rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, 4); /* was 9...which caused performance drag on traces with many signals */ - fputc(FST_BL_SKIP, xc->handle); /* temporarily tag the section, use FST_BL_VCDATA on finalize */ - xc->section_start = ftello(xc->handle); + 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; + 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 */ - fstWriterUint64(xc->handle, xc->curtime); /* end time of section (placeholder) */ - fstWriterUint64(xc->handle, 0); /* placeholder = amount of buffer memory required in reader for full vc traversal */ - fstWriterVarint(xc->handle, xc->maxvalpos); /* maxvalpos = length of uncompressed data */ + 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 */ + fstWriterUint64(xc->handle, xc->curtime); /* end time of section (placeholder) */ + fstWriterUint64(xc->handle, 0); /* placeholder = amount of buffer memory required in reader for full vc traversal */ + fstWriterVarint(xc->handle, xc->maxvalpos); /* maxvalpos = length of uncompressed data */ - if((rc == Z_OK) && (destlen < xc->maxvalpos)) - { - fstWriterVarint(xc->handle, destlen); /* length of compressed data */ - } - else - { - fstWriterVarint(xc->handle, xc->maxvalpos); /* length of (unable to be) compressed data */ - } - fstWriterVarint(xc->handle, xc->maxhandle); /* max handle associated with this data (in case of dynamic facility adds) */ + if((rc == Z_OK) && (destlen < xc->maxvalpos)) + { + fstWriterVarint(xc->handle, destlen); /* length of compressed data */ + } + else + { + fstWriterVarint(xc->handle, xc->maxvalpos); /* length of (unable to be) compressed data */ + } + fstWriterVarint(xc->handle, xc->maxhandle); /* max handle associated with this data (in case of dynamic facility adds) */ - if((rc == Z_OK) && (destlen < xc->maxvalpos)) - { - fstFwrite(dmem, destlen, 1, xc->handle); - } - else /* comparison between compressed / decompressed len tells if compressed */ - { - fstFwrite(xc->curval_mem, xc->maxvalpos, 1, xc->handle); - } + if((rc == Z_OK) && (destlen < xc->maxvalpos)) + { + fstFwrite(dmem, destlen, 1, xc->handle); + } + else /* comparison between compressed / decompressed len tells if compressed */ + { + fstFwrite(xc->curval_mem, xc->maxvalpos, 1, xc->handle); + } - free(dmem); - } + free(dmem); + } } @@ -1021,7 +1230,7 @@ static void fstWriterFlushContextPrivate(void *ctx) #ifdef FST_DEBUG int cnt = 0; #endif -int i; +unsigned int i; unsigned char *vchg_mem; FILE *f; off_t fpos, indxpos, endpos; @@ -1054,7 +1263,7 @@ hashmask |= hashmask >> 16; #endif #endif -if((!xc)||(xc->vchg_siz <= 1)||(xc->already_in_flush)) return; +if((xc->vchg_siz <= 1)||(xc->already_in_flush)) return; xc->already_in_flush = 1; /* should really do this with a semaphore */ xc->section_header_only = 0; @@ -1063,296 +1272,301 @@ scratchpad = malloc(xc->vchg_siz); vchg_mem = xc->vchg_mem; f = xc->handle; -fstWriterVarint(f, xc->maxhandle); /* emit current number of handles */ -fputc(xc->fastpack ? 'F' : 'Z', f); +fstWriterVarint(f, xc->maxhandle); /* emit current number of handles */ +fputc(xc->fourpack ? '4' : (xc->fastpack ? 'F' : 'Z'), f); fpos = 1; -packmemlen = 1024; /* maintain a running "longest" allocation to */ -packmem = malloc(packmemlen); /* prevent continual malloc...free every loop iter */ +packmemlen = 1024; /* maintain a running "longest" allocation to */ +packmem = malloc(packmemlen); /* prevent continual malloc...free every loop iter */ for(i=0;imaxhandle;i++) - { - vm4ip = &(xc->valpos_mem[4*i]); + { + vm4ip = &(xc->valpos_mem[4*i]); - if(vm4ip[2]) - { - uint32_t offs = vm4ip[2]; - uint32_t next_offs; - int wrlen; + if(vm4ip[2]) + { + uint32_t offs = vm4ip[2]; + uint32_t next_offs; + unsigned int wrlen; - vm4ip[2] = fpos; + vm4ip[2] = fpos; - scratchpnt = scratchpad + xc->vchg_siz; /* build this buffer backwards */ - if(vm4ip[1] <= 1) - { - if(vm4ip[1] == 1) - { - wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ + scratchpnt = scratchpad + xc->vchg_siz; /* build this buffer backwards */ + if(vm4ip[1] <= 1) + { + 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 */ + xc->curval_mem[vm4ip[0]] = vchg_mem[offs + 4 + wrlen]; /* checkpoint variable */ #endif - while(offs) - { - unsigned char val; - uint32_t time_delta, rcv; - next_offs = fstGetUint32(vchg_mem + offs); - offs += 4; - - time_delta = fstGetVarint32(vchg_mem + offs, &wrlen); - val = vchg_mem[offs+wrlen]; - offs = next_offs; + while(offs) + { + unsigned char val; + uint32_t time_delta, rcv; + next_offs = fstGetUint32(vchg_mem + offs); + offs += 4; - switch(val) - { - case '0': - case '1': rcv = ((val&1)<<1) | (time_delta<<2); - break; /* pack more delta bits in for 0/1 vchs */ - - case 'x': case 'X': rcv = FST_RCV_X | (time_delta<<4); break; - case 'z': case 'Z': rcv = FST_RCV_Z | (time_delta<<4); break; - case 'h': case 'H': rcv = FST_RCV_H | (time_delta<<4); break; - case 'u': case 'U': rcv = FST_RCV_U | (time_delta<<4); break; - case 'w': case 'W': rcv = FST_RCV_W | (time_delta<<4); break; - case 'l': case 'L': rcv = FST_RCV_L | (time_delta<<4); break; - default: rcv = FST_RCV_D | (time_delta<<4); break; - } - - scratchpnt = fstCopyVarint32ToLeft(scratchpnt, rcv); - } - } - else - { - /* variable length */ - /* fstGetUint32 (next_offs) + fstGetVarint32 (time_delta) + fstGetVarint32 (len) + payload */ - unsigned char *pnt; - uint32_t record_len; - uint32_t time_delta; + time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen); + val = vchg_mem[offs+wrlen]; + offs = next_offs; - while(offs) - { - next_offs = fstGetUint32(vchg_mem + offs); - offs += 4; - pnt = vchg_mem + offs; - offs = next_offs; - time_delta = fstGetVarint32(pnt, &wrlen); - pnt += wrlen; - record_len = fstGetVarint32(pnt, &wrlen); - pnt += wrlen; + switch(val) + { + case '0': + case '1': rcv = ((val&1)<<1) | (time_delta<<2); + break; /* pack more delta bits in for 0/1 vchs */ - scratchpnt -= record_len; - memcpy(scratchpnt, pnt, record_len); + case 'x': case 'X': rcv = FST_RCV_X | (time_delta<<4); break; + case 'z': case 'Z': rcv = FST_RCV_Z | (time_delta<<4); break; + case 'h': case 'H': rcv = FST_RCV_H | (time_delta<<4); break; + case 'u': case 'U': rcv = FST_RCV_U | (time_delta<<4); break; + case 'w': case 'W': rcv = FST_RCV_W | (time_delta<<4); break; + case 'l': case 'L': rcv = FST_RCV_L | (time_delta<<4); break; + default: rcv = FST_RCV_D | (time_delta<<4); break; + } - scratchpnt = fstCopyVarint32ToLeft(scratchpnt, record_len); - scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); /* reserve | 1 case for future expansion */ - } - } - } - else - { - wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ + scratchpnt = fstCopyVarint32ToLeft(scratchpnt, rcv); + } + } + else + { + /* variable length */ + /* fstGetUint32 (next_offs) + fstGetVarint32 (time_delta) + fstGetVarint32 (len) + payload */ + unsigned char *pnt; + uint32_t record_len; + uint32_t time_delta; + + while(offs) + { + next_offs = fstGetUint32(vchg_mem + offs); + offs += 4; + pnt = vchg_mem + offs; + offs = next_offs; + time_delta = fstGetVarint32(pnt, (int *)&wrlen); + pnt += wrlen; + record_len = fstGetVarint32(pnt, (int *)&wrlen); + pnt += wrlen; + + scratchpnt -= record_len; + memcpy(scratchpnt, pnt, record_len); + + scratchpnt = fstCopyVarint32ToLeft(scratchpnt, record_len); + scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); /* reserve | 1 case for future expansion */ + } + } + } + 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 */ + memcpy(xc->curval_mem + vm4ip[0], vchg_mem + offs + 4 + wrlen, vm4ip[1]); /* checkpoint variable */ #endif - while(offs) - { - int idx; - char is_binary = 1; - unsigned char *pnt; - uint32_t time_delta; + while(offs) + { + unsigned int idx; + char is_binary = 1; + unsigned char *pnt; + uint32_t time_delta; - next_offs = fstGetUint32(vchg_mem + offs); - offs += 4; + next_offs = fstGetUint32(vchg_mem + offs); + offs += 4; - time_delta = fstGetVarint32(vchg_mem + offs, &wrlen); + time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen); - pnt = vchg_mem+offs+wrlen; - offs = next_offs; + pnt = vchg_mem+offs+wrlen; + offs = next_offs; - for(idx=0;idx=0;idx--) - { - acc |= (pnt[idx] & 1) << shift; - shift++; - if(shift == 8) - { - *(--scratchpnt) = acc; - shift = 0; - acc = 0; - } - } + if(is_binary) + { + unsigned char acc = 0; + /* new algorithm */ + idx = ((vm4ip[1]+7) & ~7); + switch(vm4ip[1] & 7) + { + case 0: do { acc = (pnt[idx+7-8] & 1) << 0; + case 7: acc |= (pnt[idx+6-8] & 1) << 1; + case 6: acc |= (pnt[idx+5-8] & 1) << 2; + case 5: acc |= (pnt[idx+4-8] & 1) << 3; + case 4: acc |= (pnt[idx+3-8] & 1) << 4; + case 3: acc |= (pnt[idx+2-8] & 1) << 5; + case 2: acc |= (pnt[idx+1-8] & 1) << 6; + case 1: acc |= (pnt[idx+0-8] & 1) << 7; + *(--scratchpnt) = acc; + idx -= 8; + } while(idx); + } - scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); - } - else - { - scratchpnt -= vm4ip[1]; - memcpy(scratchpnt, pnt, vm4ip[1]); + scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); + } + else + { + scratchpnt -= vm4ip[1]; + memcpy(scratchpnt, pnt, vm4ip[1]); - scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1) | 1); - } - } - } + scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1) | 1); + } + } + } - wrlen = scratchpad + xc->vchg_siz - scratchpnt; - unc_memreq += wrlen; - if(wrlen > 32) - { - unsigned long destlen = wrlen; - unsigned char *dmem; - int rc; + wrlen = scratchpad + xc->vchg_siz - scratchpnt; + unc_memreq += wrlen; + if(wrlen > 32) + { + unsigned long destlen = wrlen; + unsigned char *dmem; + unsigned int rc; - if(!xc->fastpack) - { - if(wrlen <= packmemlen) - { - dmem = packmem; - } - else - { - free(packmem); - dmem = packmem = malloc(packmemlen = wrlen); - } + if(!xc->fastpack) + { + if(wrlen <= packmemlen) + { + dmem = packmem; + } + else + { + free(packmem); + dmem = packmem = malloc(compressBound(packmemlen = wrlen)); + } - rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4); - if(rc == Z_OK) - { + rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4); + if(rc == Z_OK) + { #ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, destlen, NULL); - if(*pv) - { - uint32_t pvi = (long)(*pv); - vm4ip[2] = -pvi; - } - else - { - *pv = (void *)(long)(i+1); + PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, destlen, NULL); + if(*pv) + { + uint32_t pvi = (long)(*pv); + vm4ip[2] = -pvi; + } + else + { + *pv = (void *)(long)(i+1); #endif - fpos += fstWriterVarint(f, wrlen); - fpos += destlen; - fstFwrite(dmem, destlen, 1, f); + fpos += fstWriterVarint(f, wrlen); + fpos += destlen; + fstFwrite(dmem, destlen, 1, f); #ifndef FST_DYNAMIC_ALIAS_DISABLE - } + } #endif - } - else - { + } + else + { #ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); - if(*pv) - { - uint32_t pvi = (long)(*pv); - vm4ip[2] = -pvi; - } - else - { - *pv = (void *)(long)(i+1); + PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); + if(*pv) + { + uint32_t pvi = (long)(*pv); + vm4ip[2] = -pvi; + } + else + { + *pv = (void *)(long)(i+1); #endif - fpos += fstWriterVarint(f, 0); - fpos += wrlen; - fstFwrite(scratchpnt, wrlen, 1, f); + fpos += fstWriterVarint(f, 0); + fpos += wrlen; + fstFwrite(scratchpnt, wrlen, 1, f); #ifndef FST_DYNAMIC_ALIAS_DISABLE - } + } #endif - } - } - else - { - if(((wrlen * 2) + 2) <= packmemlen) - { - dmem = packmem; - } - else - { - free(packmem); - dmem = packmem = malloc(packmemlen = (wrlen * 2) + 2); - } + } + } + else + { + /* this is extremely conservative: fastlz needs +5% for worst case, lz4 needs siz+(siz/255)+16 */ + if(((wrlen * 2) + 2) <= packmemlen) + { + dmem = packmem; + } + else + { + free(packmem); + dmem = packmem = malloc(packmemlen = (wrlen * 2) + 2); + } - rc = fastlz_compress(scratchpnt, wrlen, dmem); - if(rc < destlen) - { + rc = (xc->fourpack) ? LZ4_compress((char *)scratchpnt, (char *)dmem, wrlen) : fastlz_compress(scratchpnt, wrlen, dmem); + if(rc < destlen) + { #ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, rc, NULL); - if(*pv) - { - uint32_t pvi = (long)(*pv); - vm4ip[2] = -pvi; - } - else - { - *pv = (void *)(long)(i+1); + PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, rc, NULL); + if(*pv) + { + uint32_t pvi = (long)(*pv); + vm4ip[2] = -pvi; + } + else + { + *pv = (void *)(long)(i+1); #endif - fpos += fstWriterVarint(f, wrlen); - fpos += rc; - fstFwrite(dmem, rc, 1, f); + fpos += fstWriterVarint(f, wrlen); + fpos += rc; + fstFwrite(dmem, rc, 1, f); #ifndef FST_DYNAMIC_ALIAS_DISABLE - } + } #endif - } - else - { + } + else + { #ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); - if(*pv) - { - uint32_t pvi = (long)(*pv); - vm4ip[2] = -pvi; - } - else - { - *pv = (void *)(long)(i+1); + PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); + if(*pv) + { + uint32_t pvi = (long)(*pv); + vm4ip[2] = -pvi; + } + else + { + *pv = (void *)(long)(i+1); #endif - fpos += fstWriterVarint(f, 0); - fpos += wrlen; - fstFwrite(scratchpnt, wrlen, 1, f); + fpos += fstWriterVarint(f, 0); + fpos += wrlen; + fstFwrite(scratchpnt, wrlen, 1, f); #ifndef FST_DYNAMIC_ALIAS_DISABLE - } + } #endif - } - } - } - else - { + } + } + } + else + { #ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); - if(*pv) - { - uint32_t pvi = (long)(*pv); - vm4ip[2] = -pvi; - } - else - { - *pv = (void *)(long)(i+1); + PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); + if(*pv) + { + uint32_t pvi = (long)(*pv); + vm4ip[2] = -pvi; + } + else + { + *pv = (void *)(long)(i+1); #endif - fpos += fstWriterVarint(f, 0); - fpos += wrlen; - fstFwrite(scratchpnt, wrlen, 1, f); + fpos += fstWriterVarint(f, 0); + fpos += wrlen; + fstFwrite(scratchpnt, wrlen, 1, f); #ifndef FST_DYNAMIC_ALIAS_DISABLE - } + } #endif - } + } - /* vm4ip[3] = 0; ...redundant with clearing below */ + /* vm4ip[3] = 0; ...redundant with clearing below */ #ifdef FST_DEBUG - cnt++; + cnt++; #endif - } - } + } + } #ifndef FST_DYNAMIC_ALIAS_DISABLE JudyHSFreeArray(&PJHSArray, NULL); @@ -1366,49 +1580,96 @@ free(scratchpad); scratchpad = NULL; indxpos = ftello(f); xc->secnum++; -for(i=0;imaxhandle;i++) - { - vm4ip = &(xc->valpos_mem[4*i]); +#ifndef FST_DYNAMIC_ALIAS2_DISABLE +if(1) + { + uint32_t prev_alias = 0; - if(vm4ip[2]) - { - if(zerocnt) - { - fpos += fstWriterVarint(f, (zerocnt << 1)); - zerocnt = 0; - } + for(i=0;imaxhandle;i++) + { + vm4ip = &(xc->valpos_mem[4*i]); + + if(vm4ip[2]) + { + if(zerocnt) + { + fpos += fstWriterVarint(f, (zerocnt << 1)); + zerocnt = 0; + } + + if(vm4ip[2] & 0x80000000) + { + if(vm4ip[2] != prev_alias) + { + fpos += fstWriterSVarint(f, (((int64_t)((int32_t)(prev_alias = vm4ip[2]))) << 1) | 1); + } + else + { + fpos += fstWriterSVarint(f, (0 << 1) | 1); + } + } + else + { + fpos += fstWriterSVarint(f, ((vm4ip[2] - prevpos) << 1) | 1); + prevpos = vm4ip[2]; + } + vm4ip[2] = 0; + vm4ip[3] = 0; /* clear out tchn idx */ + } + else + { + zerocnt++; + } + } + } + else +#endif + { + for(i=0;imaxhandle;i++) + { + vm4ip = &(xc->valpos_mem[4*i]); + + if(vm4ip[2]) + { + if(zerocnt) + { + fpos += fstWriterVarint(f, (zerocnt << 1)); + zerocnt = 0; + } + + if(vm4ip[2] & 0x80000000) + { + fpos += fstWriterVarint(f, 0); /* signal, note that using a *signed* varint would be more efficient than this byte escape! */ + fpos += fstWriterVarint(f, (-(int32_t)vm4ip[2])); + } + else + { + fpos += fstWriterVarint(f, ((vm4ip[2] - prevpos) << 1) | 1); + prevpos = vm4ip[2]; + } + vm4ip[2] = 0; + vm4ip[3] = 0; /* clear out tchn idx */ + } + else + { + zerocnt++; + } + } + } - if(vm4ip[2] & 0x80000000) - { - fpos += fstWriterVarint(f, 0); /* signal */ - fpos += fstWriterVarint(f, (-(int32_t)vm4ip[2])); - } - else - { - fpos += fstWriterVarint(f, ((vm4ip[2] - prevpos) << 1) | 1); - prevpos = vm4ip[2]; - } - vm4ip[2] = 0; - vm4ip[3] = 0; /* clear out tchn idx */ - } - else - { - zerocnt++; - } - } if(zerocnt) - { - /* fpos += */ fstWriterVarint(f, (zerocnt << 1)); /* scan-build */ - } + { + /* fpos += */ fstWriterVarint(f, (zerocnt << 1)); /* scan-build */ + } #ifdef FST_DEBUG -printf("value chains: %d\n", cnt); +fprintf(stderr, "value chains: %d\n", cnt); #endif xc->vchg_mem[0] = '!'; xc->vchg_siz = 1; endpos = ftello(xc->handle); -fstWriterUint64(xc->handle, endpos-indxpos); /* write delta index position at very end of block */ +fstWriterUint64(xc->handle, endpos-indxpos); /* write delta index position at very end of block */ /*emit time changes for block */ fflush(xc->tchn_handle); @@ -1417,26 +1678,26 @@ fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->tchn_handle), 0); if(tmem) - { - unsigned long destlen = tlen; - unsigned char *dmem = malloc(destlen); + { + unsigned long destlen = tlen; + unsigned char *dmem = malloc(compressBound(destlen)); int rc = compress2(dmem, &destlen, tmem, tlen, 9); - if((rc == Z_OK) && (destlen < tlen)) - { - fstFwrite(dmem, destlen, 1, xc->handle); - } - else /* comparison between compressed / decompressed len tells if compressed */ - { - fstFwrite(tmem, tlen, 1, xc->handle); - destlen = tlen; - } - free(dmem); - fstMunmap(tmem, tlen); - fstWriterUint64(xc->handle, tlen); /* uncompressed */ - fstWriterUint64(xc->handle, destlen); /* compressed */ - fstWriterUint64(xc->handle, xc->tchn_cnt); /* number of time items */ - } + if((rc == Z_OK) && (((off_t)destlen) < tlen)) + { + fstFwrite(dmem, destlen, 1, xc->handle); + } + else /* comparison between compressed / decompressed len tells if compressed */ + { + fstFwrite(tmem, tlen, 1, xc->handle); + destlen = tlen; + } + free(dmem); + fstMunmap(tmem, tlen); + fstWriterUint64(xc->handle, tlen); /* uncompressed */ + fstWriterUint64(xc->handle, destlen); /* compressed */ + fstWriterUint64(xc->handle, xc->tchn_cnt); /* number of time items */ + } xc->tchn_cnt = xc->tchn_idx = 0; fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); @@ -1445,42 +1706,46 @@ fstFtruncate(fileno(xc->tchn_handle), 0); /* write block trailer */ endpos = ftello(xc->handle); fstWriterFseeko(xc, xc->handle, xc->section_start, SEEK_SET); -fstWriterUint64(xc->handle, endpos - xc->section_start); /* write block length */ -fstWriterFseeko(xc, xc->handle, 8, SEEK_CUR); /* skip begin time */ -fstWriterUint64(xc->handle, xc->curtime); /* write end time for section */ -fstWriterUint64(xc->handle, unc_memreq); /* amount of buffer memory required in reader for full traversal */ +fstWriterUint64(xc->handle, endpos - xc->section_start); /* write block length */ +fstWriterFseeko(xc, xc->handle, 8, SEEK_CUR); /* skip begin time */ +fstWriterUint64(xc->handle, xc->curtime); /* write end time for section */ +fstWriterUint64(xc->handle, unc_memreq); /* amount of buffer memory required in reader for full traversal */ fflush(xc->handle); -fstWriterFseeko(xc, xc->handle, xc->section_start-1, SEEK_SET); /* write out FST_BL_VCDATA over FST_BL_SKIP */ +fstWriterFseeko(xc, xc->handle, xc->section_start-1, SEEK_SET); /* write out FST_BL_VCDATA over FST_BL_SKIP */ #ifndef FST_DYNAMIC_ALIAS_DISABLE +#ifndef FST_DYNAMIC_ALIAS2_DISABLE +fputc(FST_BL_VCDATA_DYN_ALIAS2, xc->handle); +#else fputc(FST_BL_VCDATA_DYN_ALIAS, xc->handle); +#endif #else fputc(FST_BL_VCDATA, xc->handle); #endif fflush(xc->handle); -fstWriterFseeko(xc, xc->handle, endpos, SEEK_SET); /* seek to end of file */ +fstWriterFseeko(xc, xc->handle, endpos, SEEK_SET); /* seek to end of file */ -xc2->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) - { - xc2->skip_writing_section_hdr = 1; - xc2->size_limit_locked = 1; - xc2->is_initial_time = 1; /* to trick emit value and emit time change */ + { + if(endpos >= ((off_t)xc->dump_size_limit)) + { + 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"); + fprintf(stderr, "<< dump file size limit reached, stopping dumping >>\n"); #endif - } - } + } + } if(!xc2->skip_writing_section_hdr) - { - fstWriterEmitSectionHeader(xc); /* emit next section header */ - } + { + fstWriterEmitSectionHeader(xc); /* emit next section header */ + } fflush(xc->handle); xc->already_in_flush = 0; @@ -1501,7 +1766,7 @@ free(xc->curval_mem); #endif free(xc->valpos_mem); free(xc->vchg_mem); -fclose(xc->tchn_handle); +tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); free(xc); return(NULL); @@ -1513,59 +1778,59 @@ static void fstWriterFlushContextPrivate(void *ctx) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc->parallel_enabled) - { - struct fstWriterContext *xc2 = malloc(sizeof(struct fstWriterContext)); - int i; + { + struct fstWriterContext *xc2 = malloc(sizeof(struct fstWriterContext)); + unsigned int i; - pthread_mutex_lock(&xc->mutex); - pthread_mutex_unlock(&xc->mutex); + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); - xc->xc_parent = xc; - memcpy(xc2, xc, sizeof(struct fstWriterContext)); + 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)); + 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 */ + /* 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); + 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; + 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 */ - } + 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(); - fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); - fstFtruncate(fileno(xc->tchn_handle), 0); + xc->tchn_cnt = xc->tchn_idx = 0; + xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* child thread will deallocate file/name */ + fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); + fstFtruncate(fileno(xc->tchn_handle), 0); - xc->section_header_only = 0; - xc->secnum++; + xc->section_header_only = 0; + xc->secnum++; - pthread_mutex_lock(&xc->mutex); + 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); - } + 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); - } + xc->xc_parent = xc; + fstWriterFlushContextPrivate2(xc); + } } #endif @@ -1578,11 +1843,11 @@ void fstWriterFlushContext(void *ctx) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - if(xc->tchn_idx > 1) - { - xc->flush_context_pending = 1; - } - } + if(xc->tchn_idx > 1) + { + xc->flush_context_pending = 1; + } + } } @@ -1595,289 +1860,333 @@ struct fstWriterContext *xc = (struct fstWriterContext *)ctx; #ifdef FST_WRITER_PARALLEL if(xc) - { - pthread_mutex_lock(&xc->mutex); - pthread_mutex_unlock(&xc->mutex); - } + { + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); + } #endif if(xc && !xc->already_in_close && !xc->already_in_flush) - { - unsigned char *tmem; - off_t fixup_offs, tlen, hlen; + { + unsigned char *tmem; + off_t fixup_offs, tlen, hlen; - xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */ + xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */ - if(xc->section_header_only && xc->section_header_truncpos && (xc->vchg_siz <= 1) && (!xc->is_initial_time)) - { - fstFtruncate(fileno(xc->handle), xc->section_header_truncpos); - fstWriterFseeko(xc, xc->handle, xc->section_header_truncpos, SEEK_SET); - xc->section_header_only = 0; - } - else - { - xc->skip_writing_section_hdr = 1; - if(!xc->size_limit_locked) - { - if(xc->is_initial_time) /* simulation time never advanced so mock up the changes as time zero ones */ - { - fstHandle dupe_idx; - - fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */ - for(dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */ - { - fstWriterEmitValueChange(xc, dupe_idx+1, xc->curval_mem + xc->valpos_mem[4*dupe_idx]); - } - } - fstWriterFlushContextPrivate(xc); + if(xc->section_header_only && xc->section_header_truncpos && (xc->vchg_siz <= 1) && (!xc->is_initial_time)) + { + fstFtruncate(fileno(xc->handle), xc->section_header_truncpos); + fstWriterFseeko(xc, xc->handle, xc->section_header_truncpos, SEEK_SET); + xc->section_header_only = 0; + } + else + { + xc->skip_writing_section_hdr = 1; + if(!xc->size_limit_locked) + { + if(xc->is_initial_time) /* simulation time never advanced so mock up the changes as time zero ones */ + { + fstHandle dupe_idx; + + fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */ + for(dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */ + { + fstWriterEmitValueChange(xc, dupe_idx+1, xc->curval_mem + xc->valpos_mem[4*dupe_idx]); + } + } + fstWriterFlushContextPrivate(xc); #ifdef FST_WRITER_PARALLEL - pthread_mutex_lock(&xc->mutex); - pthread_mutex_unlock(&xc->mutex); + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); #endif - } - } - fstDestroyMmaps(xc, 1); + } + } + fstDestroyMmaps(xc, 1); - /* write out geom section */ - fflush(xc->geom_handle); - tlen = ftello(xc->geom_handle); - tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0); - if(tmem) - { - unsigned long destlen = tlen; - unsigned char *dmem = malloc(destlen); - int rc = compress2(dmem, &destlen, tmem, tlen, 9); + /* write out geom section */ + fflush(xc->geom_handle); + tlen = ftello(xc->geom_handle); + tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0); + if(tmem) + { + unsigned long destlen = tlen; + unsigned char *dmem = malloc(compressBound(destlen)); + int rc = compress2(dmem, &destlen, tmem, tlen, 9); - if((rc != Z_OK) || (destlen > tlen)) - { - destlen = tlen; - } + if((rc != Z_OK) || (((off_t)destlen) > tlen)) + { + destlen = tlen; + } - fixup_offs = ftello(xc->handle); - fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ - fstWriterUint64(xc->handle, destlen + 24); /* section length */ - fstWriterUint64(xc->handle, tlen); /* uncompressed */ - /* compressed len is section length - 24 */ - fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */ - fstFwrite((destlen != tlen) ? dmem : tmem, destlen, 1, xc->handle); - fflush(xc->handle); + fixup_offs = ftello(xc->handle); + fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ + fstWriterUint64(xc->handle, destlen + 24); /* section length */ + fstWriterUint64(xc->handle, tlen); /* uncompressed */ + /* compressed len is section length - 24 */ + fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */ + fstFwrite((((off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle); + fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); - fputc(FST_BL_GEOM, xc->handle); /* actual tag */ + fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); + fputc(FST_BL_GEOM, xc->handle); /* actual tag */ - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ - fflush(xc->handle); + fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ + fflush(xc->handle); - free(dmem); - fstMunmap(tmem, tlen); - } + free(dmem); + fstMunmap(tmem, tlen); + } - if(xc->num_blackouts) - { - uint64_t cur_bl = 0; - off_t bpos, eos; - uint32_t i; + if(xc->num_blackouts) + { + uint64_t cur_bl = 0; + off_t bpos, eos; + uint32_t i; - fixup_offs = ftello(xc->handle); - fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ - bpos = fixup_offs + 1; - fstWriterUint64(xc->handle, 0); /* section length */ - fstWriterVarint(xc->handle, xc->num_blackouts); + fixup_offs = ftello(xc->handle); + fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ + bpos = fixup_offs + 1; + fstWriterUint64(xc->handle, 0); /* section length */ + fstWriterVarint(xc->handle, xc->num_blackouts); - for(i=0;inum_blackouts;i++) - { - fputc(xc->blackout_head->active, xc->handle); - fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl); - cur_bl = xc->blackout_head->tim; - xc->blackout_curr = xc->blackout_head->next; - free(xc->blackout_head); - xc->blackout_head = xc->blackout_curr; - } + for(i=0;inum_blackouts;i++) + { + fputc(xc->blackout_head->active, xc->handle); + fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl); + cur_bl = xc->blackout_head->tim; + xc->blackout_curr = xc->blackout_head->next; + free(xc->blackout_head); + xc->blackout_head = xc->blackout_curr; + } - eos = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, bpos, SEEK_SET); - fstWriterUint64(xc->handle, eos - bpos); - fflush(xc->handle); + eos = ftello(xc->handle); + fstWriterFseeko(xc, xc->handle, bpos, SEEK_SET); + fstWriterUint64(xc->handle, eos - bpos); + fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); - fputc(FST_BL_BLACKOUT, xc->handle); /* actual tag */ + fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); + fputc(FST_BL_BLACKOUT, xc->handle); /* actual tag */ - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ - fflush(xc->handle); - } + fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ + fflush(xc->handle); + } - if(xc->compress_hier) - { - unsigned char *mem = malloc(FST_GZIO_LEN); - off_t hl, eos; - gzFile zhandle; - int zfd; + if(xc->compress_hier) + { + off_t hl, eos; + gzFile zhandle; + int zfd; + int fourpack_duo = 0; #ifndef __MINGW32__ - char *fnam = malloc(strlen(xc->filename) + 5 + 1); + char *fnam = malloc(strlen(xc->filename) + 5 + 1); #endif - fixup_offs = ftello(xc->handle); - fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ - hlen = ftello(xc->handle); - fstWriterUint64(xc->handle, 0); /* section length */ - fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */ - - fflush(xc->handle); - zfd = dup(fileno(xc->handle)); - zhandle = gzdopen(zfd, "wb4"); - if(zhandle) - { - fstWriterFseeko(xc, xc->hier_handle, 0, SEEK_SET); - for(hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN) - { - unsigned len = ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl); - fstFread(mem, len, 1, xc->hier_handle); - gzwrite(zhandle, mem, len); - } - gzclose(zhandle); - } - else - { - close(zfd); - } - free(mem); + fixup_offs = ftello(xc->handle); + fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ + hlen = ftello(xc->handle); + fstWriterUint64(xc->handle, 0); /* section length */ + fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */ - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); - eos = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, hlen, SEEK_SET); - fstWriterUint64(xc->handle, eos - hlen); - fflush(xc->handle); + if(!xc->fourpack) + { + unsigned char *mem = malloc(FST_GZIO_LEN); + zfd = dup(fileno(xc->handle)); + fflush(xc->handle); + zhandle = gzdopen(zfd, "wb4"); + if(zhandle) + { + fstWriterFseeko(xc, xc->hier_handle, 0, SEEK_SET); + for(hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN) + { + unsigned len = ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl); + fstFread(mem, len, 1, xc->hier_handle); + gzwrite(zhandle, mem, len); + } + gzclose(zhandle); + } + else + { + close(zfd); + } + free(mem); + } + else + { + int lz4_maxlen; + unsigned char *mem; + unsigned char *hmem; + int packed_len; - fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); - fputc(FST_BL_HIER, xc->handle); /* actual tag */ + fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ - fflush(xc->handle); + lz4_maxlen = LZ4_compressBound(xc->hier_file_len); + mem = malloc(lz4_maxlen); + hmem = fstMmap(NULL, xc->hier_file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->hier_handle), 0); + packed_len = LZ4_compress((char *)hmem, (char *)mem, xc->hier_file_len); + fstMunmap(hmem, xc->hier_file_len); + + fourpack_duo = (!xc->repack_on_close) && (xc->hier_file_len > FST_HDR_FOURPACK_DUO_SIZE); /* double pack when hierarchy is large */ + + if(fourpack_duo) /* double packing with LZ4 is faster than gzip */ + { + unsigned char *mem_duo; + int lz4_maxlen_duo; + int packed_len_duo; + + lz4_maxlen_duo = LZ4_compressBound(packed_len); + mem_duo = malloc(lz4_maxlen_duo); + packed_len_duo = LZ4_compress((char *)mem, (char *)mem_duo, packed_len); + + fstWriterVarint(xc->handle, packed_len); /* 1st round compressed length */ + fstFwrite(mem_duo, packed_len_duo, 1, xc->handle); + free(mem_duo); + } + else + { + fstFwrite(mem, packed_len, 1, xc->handle); + } + + free(mem); + } + + fstWriterFseeko(xc, xc->handle, 0, SEEK_END); + eos = ftello(xc->handle); + fstWriterFseeko(xc, xc->handle, hlen, SEEK_SET); + fstWriterUint64(xc->handle, eos - hlen); + fflush(xc->handle); + + fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); + fputc(xc->fourpack ? + ( fourpack_duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4) : + FST_BL_HIER, xc->handle); /* actual tag now also == compression type */ + + fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ + fflush(xc->handle); #ifndef __MINGW32__ - sprintf(fnam, "%s.hier", xc->filename); - unlink(fnam); - free(fnam); + sprintf(fnam, "%s.hier", xc->filename); + unlink(fnam); + free(fnam); #endif - } + } - /* finalize out header */ - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); - fstWriterUint64(xc->handle, xc->firsttime); - fstWriterUint64(xc->handle, xc->curtime); - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET); - fstWriterUint64(xc->handle, xc->numscopes); - fstWriterUint64(xc->handle, xc->numsigs); - fstWriterUint64(xc->handle, xc->maxhandle); - fstWriterUint64(xc->handle, xc->secnum); - fflush(xc->handle); - - if(xc->tchn_handle) { fclose(xc->tchn_handle); xc->tchn_handle = NULL; } - free(xc->vchg_mem); xc->vchg_mem = NULL; - if(xc->curval_handle) { fclose(xc->curval_handle); xc->curval_handle = NULL; } - if(xc->valpos_handle) { fclose(xc->valpos_handle); xc->valpos_handle = NULL; } - if(xc->geom_handle) { fclose(xc->geom_handle); xc->geom_handle = NULL; } - if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; } - if(xc->handle) - { - if(xc->repack_on_close) - { - FILE *fp; - off_t offpnt, uclen; - int flen = strlen(xc->filename); - char *hf = calloc(1, flen + 5); + /* finalize out header */ + fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); + fstWriterUint64(xc->handle, xc->firsttime); + fstWriterUint64(xc->handle, xc->curtime); + fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET); + fstWriterUint64(xc->handle, xc->numscopes); + fstWriterUint64(xc->handle, xc->numsigs); + fstWriterUint64(xc->handle, xc->maxhandle); + fstWriterUint64(xc->handle, xc->secnum); + fflush(xc->handle); - strcpy(hf, xc->filename); - strcpy(hf+flen, ".pak"); - fp = fopen(hf, "wb"); + tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); + free(xc->vchg_mem); xc->vchg_mem = NULL; + tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam); + tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam); + tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam); + if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; } + if(xc->handle) + { + if(xc->repack_on_close) + { + FILE *fp; + off_t offpnt, uclen; + int flen = strlen(xc->filename); + char *hf = calloc(1, flen + 5); - if(fp) - { - void *dsth; - int zfd; - char gz_membuf[FST_GZIO_LEN]; + strcpy(hf, xc->filename); + strcpy(hf+flen, ".pak"); + fp = fopen(hf, "wb"); - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); - uclen = ftello(xc->handle); + if(fp) + { + void *dsth; + int zfd; + char gz_membuf[FST_GZIO_LEN]; - fputc(FST_BL_ZWRAPPER, fp); - fstWriterUint64(fp, 0); - fstWriterUint64(fp, uclen); - fflush(fp); + fstWriterFseeko(xc, xc->handle, 0, SEEK_END); + uclen = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, 0, SEEK_SET); - zfd = dup(fileno(fp)); - dsth = gzdopen(zfd, "wb4"); - if(dsth) - { - for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) - { - size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); - fstFread(gz_membuf, this_len, 1, xc->handle); - gzwrite(dsth, gz_membuf, this_len); - } - gzclose(dsth); - } - else - { - close(zfd); - } - fstWriterFseeko(xc, fp, 0, SEEK_END); - offpnt = ftello(fp); - fstWriterFseeko(xc, fp, 1, SEEK_SET); - fstWriterUint64(fp, offpnt - 1); - fclose(fp); - fclose(xc->handle); xc->handle = NULL; + fputc(FST_BL_ZWRAPPER, fp); + fstWriterUint64(fp, 0); + fstWriterUint64(fp, uclen); + fflush(fp); - unlink(xc->filename); - rename(hf, xc->filename); - } - else - { - xc->repack_on_close = 0; - fclose(xc->handle); xc->handle = NULL; - } + fstWriterFseeko(xc, xc->handle, 0, SEEK_SET); + zfd = dup(fileno(fp)); + dsth = gzdopen(zfd, "wb4"); + if(dsth) + { + for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) + { + size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); + fstFread(gz_membuf, this_len, 1, xc->handle); + gzwrite(dsth, gz_membuf, this_len); + } + gzclose(dsth); + } + else + { + close(zfd); + } + fstWriterFseeko(xc, fp, 0, SEEK_END); + offpnt = ftello(fp); + fstWriterFseeko(xc, fp, 1, SEEK_SET); + fstWriterUint64(fp, offpnt - 1); + fclose(fp); + fclose(xc->handle); xc->handle = NULL; - free(hf); - } - else - { - fclose(xc->handle); xc->handle = NULL; - } - } + unlink(xc->filename); + rename(hf, xc->filename); + } + else + { + xc->repack_on_close = 0; + fclose(xc->handle); xc->handle = NULL; + } -#ifdef __MINGW32__ - { - int flen = strlen(xc->filename); - char *hf = calloc(1, flen + 6); - strcpy(hf, xc->filename); + free(hf); + } + else + { + fclose(xc->handle); xc->handle = NULL; + } + } - if(xc->compress_hier) - { - strcpy(hf + flen, ".hier"); - unlink(hf); /* no longer needed as a section now exists for this */ - } +#ifdef __MINGW32__ + { + int flen = strlen(xc->filename); + char *hf = calloc(1, flen + 6); + strcpy(hf, xc->filename); - free(hf); - } + if(xc->compress_hier) + { + strcpy(hf + flen, ".hier"); + unlink(hf); /* no longer needed as a section now exists for this */ + } + + free(hf); + } #endif #ifdef FST_WRITER_PARALLEL - pthread_mutex_destroy(&xc->mutex); - pthread_attr_destroy(&xc->thread_attr); + pthread_mutex_destroy(&xc->mutex); + pthread_attr_destroy(&xc->thread_attr); #endif - if(xc->path_array) - { + if(xc->path_array) + { #ifndef _WAVE_HAVE_JUDY - const uint32_t hashmask = FST_PATH_HASHMASK; + const uint32_t hashmask = FST_PATH_HASHMASK; #endif - JudyHSFreeArray(&(xc->path_array), NULL); - } + JudyHSFreeArray(&(xc->path_array), NULL); + } - free(xc->filename); xc->filename = NULL; - free(xc); - } + free(xc->filename); xc->filename = NULL; + free(xc); + } } @@ -1889,17 +2198,17 @@ void fstWriterSetDate(void *ctx, const char *dat) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - char s[FST_HDR_DATE_SIZE]; - off_t fpos = ftello(xc->handle); - int len = strlen(dat); + char s[FST_HDR_DATE_SIZE]; + off_t fpos = ftello(xc->handle); + int len = strlen(dat); - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_DATE, SEEK_SET); - memset(s, 0, FST_HDR_DATE_SIZE); - memcpy(s, dat, (len < FST_HDR_DATE_SIZE) ? len : FST_HDR_DATE_SIZE); - fstFwrite(s, FST_HDR_DATE_SIZE, 1, xc->handle); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } + fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_DATE, SEEK_SET); + memset(s, 0, FST_HDR_DATE_SIZE); + memcpy(s, dat, (len < FST_HDR_DATE_SIZE) ? len : FST_HDR_DATE_SIZE); + fstFwrite(s, FST_HDR_DATE_SIZE, 1, xc->handle); + fflush(xc->handle); + fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); + } } @@ -1908,17 +2217,17 @@ void fstWriterSetVersion(void *ctx, const char *vers) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc && vers) { - char s[FST_HDR_SIM_VERSION_SIZE]; - off_t fpos = ftello(xc->handle); - int len = strlen(vers); + char s[FST_HDR_SIM_VERSION_SIZE]; + off_t fpos = ftello(xc->handle); + int len = strlen(vers); - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET); - memset(s, 0, FST_HDR_SIM_VERSION_SIZE); - memcpy(s, vers, (len < FST_HDR_SIM_VERSION_SIZE) ? len : FST_HDR_SIM_VERSION_SIZE); - fstFwrite(s, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } + fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET); + memset(s, 0, FST_HDR_SIM_VERSION_SIZE); + memcpy(s, vers, (len < FST_HDR_SIM_VERSION_SIZE) ? len : FST_HDR_SIM_VERSION_SIZE); + fstFwrite(s, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); + fflush(xc->handle); + fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); + } } @@ -1927,18 +2236,18 @@ void fstWriterSetFileType(void *ctx, enum fstFileType filetype) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - if((filetype >= FST_FT_MIN) && (filetype <= FST_FT_MAX)) - { - off_t fpos = ftello(xc->handle); + if(/*(filetype >= FST_FT_MIN) &&*/ (filetype <= FST_FT_MAX)) + { + off_t fpos = ftello(xc->handle); - xc->filetype = filetype; + xc->filetype = filetype; - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_FILETYPE, SEEK_SET); - fputc(xc->filetype, xc->handle); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } - } + fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_FILETYPE, SEEK_SET); + fputc(xc->filetype, xc->handle); + fflush(xc->handle); + fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); + } + } } @@ -1947,15 +2256,15 @@ static void fstWriterSetAttrDoubleArgGeneric(void *ctx, int typ, uint64_t arg1, struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - unsigned char buf[11]; /* ceil(64/7) = 10 + null term */ - unsigned char *pnt = fstCopyVarint64ToRight(buf, arg1); - if(arg1) - { - *pnt = 0; /* this converts any *nonzero* arg1 when made a varint into a null-term string */ - } + unsigned char buf[11]; /* ceil(64/7) = 10 + null term */ + unsigned char *pnt = fstCopyVarint64ToRight(buf, arg1); + if(arg1) + { + *pnt = 0; /* this converts any *nonzero* arg1 when made a varint into a null-term string */ + } - fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, (char *)buf, arg2); - } + fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, (char *)buf, arg2); + } } @@ -1964,18 +2273,18 @@ static void fstWriterSetAttrGeneric(void *ctx, const char *comm, int typ, uint64 struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc && comm) { - char *s = strdup(comm); - char *sf = s; + char *s = strdup(comm); + char *sf = s; - while(*s) - { - if((*s == '\n') || (*s == '\r')) *s = ' '; - s++; - } + while(*s) + { + if((*s == '\n') || (*s == '\r')) *s = ' '; + s++; + } - fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, sf, arg); - free(sf); - } + fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, sf, arg); + free(sf); + } } @@ -1984,52 +2293,52 @@ static void fstWriterSetSourceStem_2(void *ctx, const char *path, unsigned int l struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc && path && path[0]) - { - uint64_t sidx = 0; - int slen = strlen(path); + { + uint64_t sidx = 0; + int slen = strlen(path); #ifndef _WAVE_HAVE_JUDY - const uint32_t hashmask = FST_PATH_HASHMASK; - const unsigned char *path2 = (const unsigned char *)path; + const uint32_t hashmask = FST_PATH_HASHMASK; + const unsigned char *path2 = (const unsigned char *)path; #else - char *path2 = alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */ - strcpy(path2, path); + char *path2 = alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */ + strcpy(path2, path); #endif - PPvoid_t pv = JudyHSIns(&(xc->path_array), path2, slen, NULL); + PPvoid_t pv = JudyHSIns(&(xc->path_array), path2, slen, NULL); if(*pv) - { + { sidx = (long)(*pv); } else - { - char *rp = NULL; + { + char *rp = NULL; - sidx = ++xc->path_array_count; - *pv = (void *)(long)(xc->path_array_count); + sidx = ++xc->path_array_count; + *pv = (void *)(long)(xc->path_array_count); - if(use_realpath) - { - rp = fstRealpath( + if(use_realpath) + { + rp = fstRealpath( #ifndef _WAVE_HAVE_JUDY - (const char *) + (const char *) #endif - path2, NULL); - } - - fstWriterSetAttrGeneric(xc, rp ? rp : + path2, NULL); + } + + fstWriterSetAttrGeneric(xc, rp ? rp : #ifndef _WAVE_HAVE_JUDY - (const char *) + (const char *) #endif - path2, FST_MT_PATHNAME, sidx); + path2, FST_MT_PATHNAME, sidx); - if(rp) - { - free(rp); - } - } + if(rp) + { + free(rp); + } + } - fstWriterSetAttrDoubleArgGeneric(xc, typ, sidx, line); - } + fstWriterSetAttrDoubleArgGeneric(xc, typ, sidx, line); + } } @@ -2062,12 +2371,12 @@ void fstWriterSetTimescale(void *ctx, int ts) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - off_t fpos = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET); - fputc(ts & 255, xc->handle); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } + off_t fpos = ftello(xc->handle); + fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET); + fputc(ts & 255, xc->handle); + fflush(xc->handle); + fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); + } } @@ -2077,14 +2386,14 @@ struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc && s) { int mat = 0; - int seconds_exp = -9; - int tv = atoi(s); - const char *pnt = s; + int seconds_exp = -9; + int tv = atoi(s); + const char *pnt = s; - while(*pnt) - { + while(*pnt) + { switch(*pnt) - { + { case 'm': seconds_exp = -3; mat = 1; break; case 'u': seconds_exp = -6; mat = 1; break; case 'n': seconds_exp = -9; mat = 1; break; @@ -2096,21 +2405,21 @@ if(xc && s) default: break; } - if(mat) break; + if(mat) break; pnt++; } - if(tv == 10) - { + if(tv == 10) + { seconds_exp++; - } + } else if(tv == 100) - { + { seconds_exp+=2; } - - fstWriterSetTimescale(ctx, seconds_exp); + + fstWriterSetTimescale(ctx, seconds_exp); } } @@ -2120,22 +2429,23 @@ void fstWriterSetTimezero(void *ctx, int64_t tim) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - off_t fpos = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET); - fstWriterUint64(xc->handle, (xc->timezero = tim)); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } + off_t fpos = ftello(xc->handle); + fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET); + fstWriterUint64(xc->handle, (xc->timezero = tim)); + fflush(xc->handle); + fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); + } } -void fstWriterSetPackType(void *ctx, int typ) +void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) - { - xc->fastpack = (typ != 0); - } + { + xc->fastpack = (typ != FST_WR_PT_ZLIB); + xc->fourpack = (typ == FST_WR_PT_LZ4); + } } @@ -2143,9 +2453,9 @@ void fstWriterSetRepackOnClose(void *ctx, int enable) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) - { - xc->repack_on_close = (enable != 0); - } + { + xc->repack_on_close = (enable != 0); + } } @@ -2153,17 +2463,17 @@ 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); + { + 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); - } + if(xc->parallel_enabled) + { + fprintf(stderr, "ERROR: fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n"); + exit(255); + } #endif - } + } } @@ -2171,9 +2481,9 @@ void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) - { - xc->dump_size_limit = numbytes; - } + { + xc->dump_size_limit = numbytes; + } } @@ -2219,96 +2529,97 @@ fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, uint32_t len, const char *nam, fstHandle aliasHandle) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; -int i, nlen, is_real; - +unsigned int i; +int nlen, is_real; + if(xc && nam) { - if(xc->valpos_mem) - { - fstDestroyMmaps(xc, 0); - } + if(xc->valpos_mem) + { + fstDestroyMmaps(xc, 0); + } - fputc(vt, xc->hier_handle); - fputc(vd, xc->hier_handle); - nlen = strlen(nam); - fstFwrite(nam, nlen, 1, xc->hier_handle); - fputc(0, xc->hier_handle); - xc->hier_file_len += (nlen+3); + fputc(vt, xc->hier_handle); + fputc(vd, xc->hier_handle); + nlen = strlen(nam); + fstFwrite(nam, nlen, 1, xc->hier_handle); + fputc(0, xc->hier_handle); + xc->hier_file_len += (nlen+3); - if((vt == FST_VT_VCD_REAL) || (vt == FST_VT_VCD_REAL_PARAMETER) || (vt == FST_VT_VCD_REALTIME) || (vt == FST_VT_SV_SHORTREAL)) - { - is_real = 1; - len = 8; /* recast number of bytes to that of what a double is */ - } - else - { - is_real = 0; - if(vt == FST_VT_GEN_STRING) - { - len = 0; - } - } + if((vt == FST_VT_VCD_REAL) || (vt == FST_VT_VCD_REAL_PARAMETER) || (vt == FST_VT_VCD_REALTIME) || (vt == FST_VT_SV_SHORTREAL)) + { + is_real = 1; + len = 8; /* recast number of bytes to that of what a double is */ + } + else + { + is_real = 0; + if(vt == FST_VT_GEN_STRING) + { + len = 0; + } + } - xc->hier_file_len += fstWriterVarint(xc->hier_handle, len); + xc->hier_file_len += fstWriterVarint(xc->hier_handle, len); - 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; + 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); - } - } - } + 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; + if(!aliasHandle) + { + uint32_t zero = 0; - if(len) - { - fstWriterVarint(xc->geom_handle, !is_real ? len : 0); /* geom section encodes reals as zero byte */ - } - else - { - fstWriterVarint(xc->geom_handle, 0xFFFFFFFF); /* geom section encodes zero len as 32b -1 */ - } + if(len) + { + fstWriterVarint(xc->geom_handle, !is_real ? len : 0); /* geom section encodes reals as zero byte */ + } + else + { + fstWriterVarint(xc->geom_handle, 0xFFFFFFFF); /* geom section encodes zero len as 32b -1 */ + } - fstFwrite(&xc->maxvalpos, sizeof(uint32_t), 1, xc->valpos_handle); - fstFwrite(&len, sizeof(uint32_t), 1, xc->valpos_handle); - fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle); - fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle); + fstFwrite(&xc->maxvalpos, sizeof(uint32_t), 1, xc->valpos_handle); + fstFwrite(&len, sizeof(uint32_t), 1, xc->valpos_handle); + fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle); + fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle); - if(!is_real) - { - for(i=0;icurval_handle); - } - } - else - { - fstFwrite(&xc->nan, 8, 1, xc->curval_handle); /* initialize doubles to NaN rather than x */ - } - - xc->maxvalpos+=len; - xc->maxhandle++; - return(xc->maxhandle); - } - else - { - return(aliasHandle); - } - } + if(!is_real) + { + for(i=0;icurval_handle); + } + } + else + { + fstFwrite(&xc->nan, 8, 1, xc->curval_handle); /* initialize doubles to NaN rather than x */ + } + + xc->maxvalpos+=len; + xc->maxhandle++; + return(xc->maxhandle); + } + else + { + return(aliasHandle); + } + } return(0); } @@ -2320,26 +2631,26 @@ void fstWriterSetScope(void *ctx, enum fstScopeType scopetype, struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) - { - fputc(FST_ST_VCD_SCOPE, xc->hier_handle); - if((scopetype < FST_ST_VCD_MODULE) || (scopetype > FST_ST_MAX)) { scopetype = FST_ST_VCD_MODULE; } - fputc(scopetype, xc->hier_handle); - fprintf(xc->hier_handle, "%s%c%s%c", - scopename ? scopename : "", 0, - scopecomp ? scopecomp : "", 0); - - if(scopename) - { - xc->hier_file_len += strlen(scopename); - } - if(scopecomp) - { - xc->hier_file_len += strlen(scopecomp); - } + { + fputc(FST_ST_VCD_SCOPE, xc->hier_handle); + if(/*(scopetype < FST_ST_VCD_MODULE) ||*/ (scopetype > FST_ST_MAX)) { scopetype = FST_ST_VCD_MODULE; } + fputc(scopetype, xc->hier_handle); + fprintf(xc->hier_handle, "%s%c%s%c", + scopename ? scopename : "", 0, + scopecomp ? scopecomp : "", 0); - xc->hier_file_len += 4; /* FST_ST_VCD_SCOPE + scopetype + two string terminating zeros */ - xc->numscopes++; - } + if(scopename) + { + xc->hier_file_len += strlen(scopename); + } + if(scopecomp) + { + xc->hier_file_len += strlen(scopecomp); + } + + xc->hier_file_len += 4; /* FST_ST_VCD_SCOPE + scopetype + two string terminating zeros */ + xc->numscopes++; + } } @@ -2348,10 +2659,10 @@ void fstWriterSetUpscope(void *ctx) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) - { - fputc(FST_ST_VCD_UPSCOPE, xc->hier_handle); - xc->hier_file_len++; - } + { + fputc(FST_ST_VCD_UPSCOPE, xc->hier_handle); + xc->hier_file_len++; + } } @@ -2361,33 +2672,33 @@ void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype, struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) - { - fputc(FST_ST_GEN_ATTRBEGIN, xc->hier_handle); - if((attrtype < FST_AT_MISC) || (attrtype > FST_AT_MAX)) { attrtype = FST_AT_MISC; subtype = FST_MT_UNKNOWN; } - fputc(attrtype, xc->hier_handle); + { + fputc(FST_ST_GEN_ATTRBEGIN, xc->hier_handle); + if(/*(attrtype < FST_AT_MISC) ||*/ (attrtype > FST_AT_MAX)) { attrtype = FST_AT_MISC; subtype = FST_MT_UNKNOWN; } + fputc(attrtype, xc->hier_handle); - switch(attrtype) - { - case FST_AT_ARRAY: if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; break; - case FST_AT_ENUM: if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; break; - case FST_AT_PACK: if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; break; + switch(attrtype) + { + case FST_AT_ARRAY: if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; break; + case FST_AT_ENUM: if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; break; + case FST_AT_PACK: if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; break; - case FST_AT_MISC: - default: break; - } + case FST_AT_MISC: + default: break; + } - fputc(subtype, xc->hier_handle); - fprintf(xc->hier_handle, "%s%c", - attrname ? attrname : "", 0); - - if(attrname) - { - xc->hier_file_len += strlen(attrname); - } + fputc(subtype, xc->hier_handle); + fprintf(xc->hier_handle, "%s%c", + attrname ? attrname : "", 0); - xc->hier_file_len += 4; /* FST_ST_GEN_ATTRBEGIN + type + subtype + string terminating zero */ - xc->hier_file_len += fstWriterVarint(xc->hier_handle, arg); - } + if(attrname) + { + xc->hier_file_len += strlen(attrname); + } + + xc->hier_file_len += 4; /* FST_ST_GEN_ATTRBEGIN + type + subtype + string terminating zero */ + xc->hier_file_len += fstWriterVarint(xc->hier_handle, arg); + } } @@ -2396,10 +2707,10 @@ void fstWriterSetAttrEnd(void *ctx) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) - { - fputc(FST_ST_GEN_ATTREND, xc->hier_handle); - xc->hier_file_len++; - } + { + fputc(FST_ST_GEN_ATTREND, xc->hier_handle); + xc->hier_file_len++; + } } @@ -2414,113 +2725,113 @@ uint32_t offs; int len; if((xc) && (handle <= xc->maxhandle)) - { - uint32_t fpos; - uint32_t *vm4ip; + { + uint32_t fpos; + uint32_t *vm4ip; - if(!xc->valpos_mem) - { - xc->vc_emitted = 1; - fstWriterCreateMmaps(xc); - } + if(!xc->valpos_mem) + { + xc->vc_emitted = 1; + fstWriterCreateMmaps(xc); + } - handle--; /* move starting at 1 index to starting at 0 */ - vm4ip = &(xc->valpos_mem[4*handle]); + handle--; /* move starting at 1 index to starting at 0 */ + vm4ip = &(xc->valpos_mem[4*handle]); - len = vm4ip[1]; - if(len) /* len of zero = variable length, use fstWriterEmitVariableLengthValueChange */ - { - if(!xc->is_initial_time) - { - fpos = xc->vchg_siz; - - if((fpos + len + 10) > xc->vchg_alloc_siz) - { - 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) - { - fprintf(stderr, "FATAL ERROR, could not realloc() in fstWriterEmitValueChange, exiting.\n"); - exit(255); - } - } + len = vm4ip[1]; + if(len) /* len of zero = variable length, use fstWriterEmitVariableLengthValueChange */ + { + if(!xc->is_initial_time) + { + fpos = xc->vchg_siz; + + if((fpos + len + 10) > xc->vchg_alloc_siz) + { + 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) + { + fprintf(stderr, "FATAL ERROR, could not realloc() in fstWriterEmitValueChange, exiting.\n"); + exit(255); + } + } #ifdef FST_REMOVE_DUPLICATE_VC - offs = vm4ip[0]; + 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;itchn_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 */ - if(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; - } + 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; - } - else - { - offs = vm4ip[0]; - memcpy(xc->curval_mem + offs, buf, len); - } - } - } + 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; + } + else + { + offs = vm4ip[0]; + memcpy(xc->curval_mem + offs, buf, len); + } + } + } } @@ -2530,95 +2841,95 @@ struct fstWriterContext *xc = (struct fstWriterContext *)ctx; const unsigned char *buf = (const unsigned char *)val; if((xc) && (handle <= xc->maxhandle)) - { - uint32_t fpos; - uint32_t *vm4ip; + { + uint32_t fpos; + uint32_t *vm4ip; - if(!xc->valpos_mem) - { - xc->vc_emitted = 1; - fstWriterCreateMmaps(xc); - } + if(!xc->valpos_mem) + { + xc->vc_emitted = 1; + fstWriterCreateMmaps(xc); + } - handle--; /* move starting at 1 index to starting at 0 */ - vm4ip = &(xc->valpos_mem[4*handle]); + handle--; /* move starting at 1 index to starting at 0 */ + vm4ip = &(xc->valpos_mem[4*handle]); - /* there is no initial time dump for variable length value changes */ - if(!vm4ip[1]) /* len of zero = variable length */ - { - fpos = xc->vchg_siz; + /* there is no initial time dump for variable length value changes */ + if(!vm4ip[1]) /* len of zero = variable length */ + { + fpos = xc->vchg_siz; - if((fpos + len + 10 + 5) > xc->vchg_alloc_siz) - { - 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) - { - fprintf(stderr, "FATAL ERROR, could not realloc() in fstWriterEmitVariableLengthValueChange, exiting.\n"); - exit(255); - } - } + if((fpos + len + 10 + 5) > xc->vchg_alloc_siz) + { + 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) + { + fprintf(stderr, "FATAL ERROR, could not realloc() in fstWriterEmitVariableLengthValueChange, exiting.\n"); + exit(255); + } + } - xc->vchg_siz += fstWriterUint32WithVarint32AndLength(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */ - vm4ip[3] = xc->tchn_idx; - vm4ip[2] = fpos; - } - } + xc->vchg_siz += fstWriterUint32WithVarint32AndLength(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */ + vm4ip[3] = xc->tchn_idx; + vm4ip[2] = fpos; + } + } } void fstWriterEmitTimeChange(void *ctx, uint64_t tim) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; -int i; +unsigned int i; int skip = 0; if(xc) - { - if(xc->is_initial_time) - { - if(xc->size_limit_locked) /* this resets xc->is_initial_time to one */ - { - return; - } + { + if(xc->is_initial_time) + { + if(xc->size_limit_locked) /* this resets xc->is_initial_time to one */ + { + return; + } - if(!xc->valpos_mem) - { - fstWriterCreateMmaps(xc); - } + if(!xc->valpos_mem) + { + fstWriterCreateMmaps(xc); + } - skip = 1; + skip = 1; - xc->firsttime = (xc->vc_emitted) ? 0: tim; - xc->curtime = 0; - xc->vchg_mem[0] = '!'; - xc->vchg_siz = 1; - fstWriterEmitSectionHeader(xc); - for(i=0;imaxhandle;i++) - { - xc->valpos_mem[4*i+2] = 0; /* zero out offset val */ - xc->valpos_mem[4*i+3] = 0; /* zero out last time change val */ - } - xc->is_initial_time = 0; - } - else - { - if((xc->vchg_siz >= xc->fst_break_size) || (xc->flush_context_pending)) - { - xc->flush_context_pending = 0; - fstWriterFlushContextPrivate(xc); - xc->tchn_cnt++; - fstWriterVarint(xc->tchn_handle, xc->curtime); - } - } + xc->firsttime = (xc->vc_emitted) ? 0: tim; + xc->curtime = 0; + xc->vchg_mem[0] = '!'; + xc->vchg_siz = 1; + fstWriterEmitSectionHeader(xc); + for(i=0;imaxhandle;i++) + { + xc->valpos_mem[4*i+2] = 0; /* zero out offset val */ + xc->valpos_mem[4*i+3] = 0; /* zero out last time change val */ + } + xc->is_initial_time = 0; + } + else + { + if((xc->vchg_siz >= xc->fst_break_size) || (xc->flush_context_pending)) + { + xc->flush_context_pending = 0; + fstWriterFlushContextPrivate(xc); + xc->tchn_cnt++; + fstWriterVarint(xc->tchn_handle, xc->curtime); + } + } - if(!skip) - { - xc->tchn_idx++; - } - fstWriterVarint(xc->tchn_handle, tim - xc->curtime); - xc->tchn_cnt++; - xc->curtime = tim; - } + if(!skip) + { + xc->tchn_idx++; + } + fstWriterVarint(xc->tchn_handle, tim - xc->curtime); + xc->tchn_cnt++; + xc->curtime = tim; + } } @@ -2627,24 +2938,24 @@ void fstWriterEmitDumpActive(void *ctx, int enable) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) - { - struct fstBlackoutChain *b = calloc(1, sizeof(struct fstBlackoutChain)); + { + struct fstBlackoutChain *b = calloc(1, sizeof(struct fstBlackoutChain)); - b->tim = xc->curtime; - b->active = (enable != 0); + b->tim = xc->curtime; + b->active = (enable != 0); - xc->num_blackouts++; - if(xc->blackout_curr) - { - xc->blackout_curr->next = b; - xc->blackout_curr = b; - } - else - { - xc->blackout_head = b; - xc->blackout_curr = b; - } - } + xc->num_blackouts++; + if(xc->blackout_curr) + { + xc->blackout_curr->next = b; + xc->blackout_curr = b; + } + else + { + xc->blackout_head = b; + xc->blackout_curr = b; + } + } } @@ -2658,35 +2969,35 @@ if(xc) * private structs */ static const char *vartypes[] = { - "event", "integer", "parameter", "real", "real_parameter", - "reg", "supply0", "supply1", "time", "tri", - "triand", "trior", "trireg", "tri0", "tri1", - "wand", "wire", "wor", "port", "sparray", "realtime", - "string", - "bit", "logic", "int", "shortint", "longint", "byte", "enum", "shortreal" - }; + "event", "integer", "parameter", "real", "real_parameter", + "reg", "supply0", "supply1", "time", "tri", + "triand", "trior", "trireg", "tri0", "tri1", + "wand", "wire", "wor", "port", "sparray", "realtime", + "string", + "bit", "logic", "int", "shortint", "longint", "byte", "enum", "shortreal" + }; static const char *modtypes[] = { - "module", "task", "function", "begin", "fork", "generate", "struct", "union", "class", "interface", "package", "program", + "module", "task", "function", "begin", "fork", "generate", "struct", "union", "class", "interface", "package", "program", "vhdl_architecture", "vhdl_procedure", "vhdl_function", "vhdl_record", "vhdl_process", "vhdl_block", "vhdl_for_generate", "vhdl_if_generate", "vhdl_generate", "vhdl_package" - }; + }; static const char *attrtypes[] = { - "misc", "array", "enum", "class" - }; + "misc", "array", "enum", "class" + }; static const char *arraytypes[] = { - "none", "unpacked", "packed", "sparse" - }; + "none", "unpacked", "packed", "sparse" + }; static const char *enumvaluetypes[] = { - "integer", "bit", "logic", "int", "shortint", "longint", "byte", - "unsigned_integer", "unsigned_bit", "unsigned_logic", "unsigned_int", "unsigned_shortint", "unsigned_longint", "unsigned_byte" - }; + "integer", "bit", "logic", "int", "shortint", "longint", "byte", + "unsigned_integer", "unsigned_bit", "unsigned_logic", "unsigned_int", "unsigned_shortint", "unsigned_longint", "unsigned_byte" + }; static const char *packtypes[] = { - "none", "unpacked", "packed", "tagged_packed" - }; + "none", "unpacked", "packed", "tagged_packed" + }; struct fstCurrHier @@ -2711,20 +3022,23 @@ fstHandle maxhandle; uint64_t num_alias; uint64_t vc_section_count; -uint32_t *signal_lens; /* maxhandle sized */ -unsigned char *signal_typs; /* maxhandle sized */ -unsigned char *process_mask; /* maxhandle-based, bitwise sized */ -uint32_t longest_signal_value_len; /* longest len value encountered */ -unsigned char *temp_signal_value_buf; /* malloced for len in longest_signal_value_len */ +uint32_t *signal_lens; /* maxhandle sized */ +unsigned char *signal_typs; /* maxhandle sized */ +unsigned char *process_mask; /* maxhandle-based, bitwise sized */ +uint32_t longest_signal_value_len; /* longest len value encountered */ +unsigned char *temp_signal_value_buf; /* malloced for len in longest_signal_value_len */ signed char timescale; unsigned char filetype; +unsigned use_vcd_extensions : 1; unsigned double_endian_match : 1; unsigned native_doubles_for_cb : 1; unsigned contains_geom_section : 1; -unsigned contains_hier_section : 1; /* valid for hier_pos */ -unsigned limit_range_valid : 1; /* valid for limit_range_start, limit_range_end */ +unsigned contains_hier_section : 1; /* valid for hier_pos */ +unsigned contains_hier_section_lz4duo : 1; /* valid for hier_pos (contains_hier_section_lz4 always also set) */ +unsigned contains_hier_section_lz4 : 1; /* valid for hier_pos */ +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]; @@ -2757,7 +3071,7 @@ unsigned char *rvat_chain_mem; fstHandle rvat_chain_facidx; uint32_t rvat_chain_pos_tidx; -uint32_t rvat_chain_pos_idx; +uint32_t rvat_chain_pos_idx; uint64_t rvat_chain_pos_time; unsigned rvat_chain_pos_valid : 1; @@ -2773,6 +3087,17 @@ char str_scope_nam[FST_ID_NAM_SIZ+1]; char str_scope_comp[FST_ID_NAM_SIZ+1]; unsigned fseek_failed : 1; + +/* self-buffered I/O for writes */ + +#ifndef FST_WRITEX_DISABLE +int writex_pos; +int writex_fd; +unsigned char writex_buf[FST_WRITEX_MAX]; +#endif + +char *f_nam; +char *fh_nam; }; @@ -2781,18 +3106,53 @@ int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, off_t offset, int int rc = fseeko(stream, offset, whence); if(rc<0) - { - xc->fseek_failed = 1; + { + xc->fseek_failed = 1; #ifdef FST_DEBUG - fprintf(stderr, "Seek to #%"PRId64" (whence = %d) failed!\n", offset, whence); - perror("Why"); + fprintf(stderr, "Seek to #%"PRId64" (whence = %d) failed!\n", offset, whence); + perror("Why"); #endif - } + } return(rc); } +#ifndef FST_WRITEX_DISABLE +static void fstWritex(struct fstReaderContext *xc, void *v, int len) +{ +unsigned char *s = (unsigned char *)v; + +if(len) + { + if(len < FST_WRITEX_MAX) + { + if(xc->writex_pos + len >= FST_WRITEX_MAX) + { + fstWritex(xc, NULL, 0); + } + + memcpy(xc->writex_buf + xc->writex_pos, s, len); + xc->writex_pos += len; + } + else + { + fstWritex(xc, NULL, 0); + if (write(xc->writex_fd, s, len)) { }; + } + } + else + { + if(xc->writex_pos) + { + if(write(xc->writex_fd, xc->writex_buf, xc->writex_pos)) { }; + xc->writex_pos = 0; + } + } +} +#endif + + /* * scope -> flat name handling */ @@ -2802,11 +3162,11 @@ struct fstCurrHier *chp; free(xc->curr_flat_hier_nam); xc->curr_flat_hier_nam = NULL; while(xc->curr_hier) - { - chp = xc->curr_hier->prev; - free(xc->curr_hier); - xc->curr_hier = chp; - } + { + chp = xc->curr_hier->prev; + free(xc->curr_hier); + xc->curr_hier = chp; + } } @@ -2814,13 +3174,13 @@ const char *fstReaderGetCurrentFlatScope(void *ctx) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) - { - return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : ""); - } - else - { - return(NULL); - } + { + return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : ""); + } + else + { + return(NULL); + } } @@ -2828,34 +3188,34 @@ void *fstReaderGetCurrentScopeUserInfo(void *ctx) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) - { - return(xc->curr_hier ? xc->curr_hier->user_info : NULL); - } - else - { - return(NULL); - } + { + return(xc->curr_hier ? xc->curr_hier->user_info : NULL); + } + else + { + return(NULL); + } } const char *fstReaderPopScope(void *ctx) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; -if(xc && xc->curr_hier) +if(xc && xc->curr_hier) { - struct fstCurrHier *ch = xc->curr_hier; - if(xc->curr_hier->prev) - { - xc->curr_flat_hier_nam[xc->curr_hier->prev->len] = 0; - } - else - { - *xc->curr_flat_hier_nam = 0; - } - xc->curr_hier = xc->curr_hier->prev; - free(ch); - return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : ""); - } + struct fstCurrHier *ch = xc->curr_hier; + if(xc->curr_hier->prev) + { + xc->curr_flat_hier_nam[xc->curr_hier->prev->len] = 0; + } + else + { + *xc->curr_flat_hier_nam = 0; + } + xc->curr_hier = xc->curr_hier->prev; + free(ch); + return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : ""); + } return(NULL); } @@ -2866,9 +3226,9 @@ void fstReaderResetScope(void *ctx) struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) - { - while(fstReaderPopScope(xc)); /* remove any already-built scoping info */ - } + { + while(fstReaderPopScope(xc)); /* remove any already-built scoping info */ + } } @@ -2876,32 +3236,32 @@ const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) - { - struct fstCurrHier *ch = malloc(sizeof(struct fstCurrHier)); - int chl = xc->curr_hier ? xc->curr_hier->len : 0; - int len = chl + 1 + strlen(nam); - if(len >= xc->flat_hier_alloc_len) - { - xc->curr_flat_hier_nam = xc->curr_flat_hier_nam ? realloc(xc->curr_flat_hier_nam, len+1) : malloc(len+1); - } + { + struct fstCurrHier *ch = malloc(sizeof(struct fstCurrHier)); + int chl = xc->curr_hier ? xc->curr_hier->len : 0; + int len = chl + 1 + strlen(nam); + if(len >= xc->flat_hier_alloc_len) + { + xc->curr_flat_hier_nam = xc->curr_flat_hier_nam ? realloc(xc->curr_flat_hier_nam, len+1) : malloc(len+1); + } - if(chl) - { - xc->curr_flat_hier_nam[chl] = '.'; - strcpy(xc->curr_flat_hier_nam + chl + 1, nam); - } - else - { - strcpy(xc->curr_flat_hier_nam, nam); - len--; - } + if(chl) + { + xc->curr_flat_hier_nam[chl] = '.'; + strcpy(xc->curr_flat_hier_nam + chl + 1, nam); + } + else + { + strcpy(xc->curr_flat_hier_nam, nam); + len--; + } - ch->len = len; - ch->prev = xc->curr_hier; - ch->user_info = user_info; - xc->curr_hier = ch; - return(xc->curr_flat_hier_nam); - } + ch->len = len; + ch->prev = xc->curr_hier; + ch->user_info = user_info; + xc->curr_hier = ch; + return(xc->curr_flat_hier_nam); + } return(NULL); } @@ -2912,9 +3272,9 @@ int fstReaderGetCurrentScopeLen(void *ctx) struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc && xc->curr_hier) - { - return(xc->curr_hier->len); - } + { + return(xc->curr_hier->len); + } return(0); } @@ -2938,18 +3298,18 @@ return(0); int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - -if(xc) - { - facidx--; - if(facidxmaxhandle) - { - int process_idx = facidx/8; - int process_bit = facidx&7; - return( (xc->process_mask[process_idx]&(1<maxhandle) + { + int process_idx = facidx/8; + int process_bit = facidx&7; + + return( (xc->process_mask[process_idx]&(1<maxhandle) - { - int idx = facidx/8; - int bitpos = facidx&7; - xc->process_mask[idx] |= (1<maxhandle) + { + int idx = facidx/8; + int bitpos = facidx&7; + + xc->process_mask[idx] |= (1<maxhandle) - { - int idx = facidx/8; - int bitpos = facidx&7; - xc->process_mask[idx] &= (~(1<maxhandle) + { + int idx = facidx/8; + int bitpos = facidx&7; + + xc->process_mask[idx] &= (~(1<process_mask, 0xff, (xc->maxhandle+7)/8); - } + { + memset(xc->process_mask, 0xff, (xc->maxhandle+7)/8); + } } void fstReaderClrFacProcessMaskAll(void *ctx) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - + if(xc) - { - memset(xc->process_mask, 0x00, (xc->maxhandle+7)/8); - } + { + memset(xc->process_mask, 0x00, (xc->maxhandle+7)/8); + } } @@ -3125,13 +3485,13 @@ uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx) struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc && (idx < xc->num_blackouts) && (xc->blackout_times)) - { - return(xc->blackout_times[idx]); - } - else - { - return(0); - } + { + return(xc->blackout_times[idx]); + } + else + { + return(0); + } } @@ -3140,13 +3500,13 @@ unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx) struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc && (idx < xc->num_blackouts) && (xc->blackout_activity)) - { - return(xc->blackout_activity[idx]); - } - else - { - return(0); - } + { + return(xc->blackout_activity[idx]); + } + else + { + return(0); + } } @@ -3155,11 +3515,11 @@ void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_tim struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) - { - xc->limit_range_valid = 1; - xc->limit_range_start = start_time; - xc->limit_range_end = end_time; - } + { + xc->limit_range_valid = 1; + xc->limit_range_start = start_time; + xc->limit_range_end = end_time; + } } @@ -3168,9 +3528,20 @@ void fstReaderSetUnlimitedTimeRange(void *ctx) struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) - { - xc->limit_range_valid = 0; - } + { + xc->limit_range_valid = 0; + } +} + + +void fstReaderSetVcdExtensions(void *ctx, int enable) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) + { + xc->use_vcd_extensions = (enable != 0); + } } @@ -3178,62 +3549,42 @@ void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) - { - xc->native_doubles_for_cb = (enable != 0); - } + { + xc->native_doubles_for_cb = (enable != 0); + } } /* * hierarchy processing */ -static char *fstVcdID(int value) +static void fstVcdID(char *buf, unsigned int value) { -static char buf[16]; char *pnt = buf; -int vmod; /* zero is illegal for a value...it is assumed they start at one */ -for(;;) +while (value) { - if((vmod = (value % 94))) - { - *(pnt++) = (char)(vmod + 32); - } - else - { - *(pnt++) = '~'; value -= 94; - } + value--; + *(pnt++) = (char)('!' + value % 94); value = value / 94; - if(!value) { break; } } *pnt = 0; -return(buf); } -static char *fstVcdIDForFwrite(int value, int *len) +static int fstVcdIDForFwrite(char *buf, unsigned int value) { -static char buf[16]; char *pnt = buf; -int vmod; /* zero is illegal for a value...it is assumed they start at one */ -for(;;) +while (value) { - if((vmod = (value % 94))) - { - *(pnt++) = (char)(vmod + 32); - } - else - { - *(pnt++) = '~'; value -= 94; - } + value--; + *(pnt++) = (char)('!' + value % 94); value = value / 94; - if(!value) { break; } } -*len = pnt-buf; -return(buf); +return(pnt - buf); } @@ -3242,71 +3593,158 @@ static int fstReaderRecreateHierFile(struct fstReaderContext *xc) int pass_status = 1; if(!xc->fh) - { - off_t offs_cache = ftello(xc->f); - char *fnam = malloc(strlen(xc->filename) + 6 + 16 + 32 + 1); - unsigned char *mem = malloc(FST_GZIO_LEN); - off_t hl, uclen; - gzFile zhandle; - int zfd; + { + off_t offs_cache = ftello(xc->f); + char *fnam = malloc(strlen(xc->filename) + 6 + 16 + 32 + 1); + unsigned char *mem = malloc(FST_GZIO_LEN); + off_t hl, uclen; + off_t clen = 0; + gzFile zhandle = NULL; + int zfd; + int htyp = FST_BL_SKIP; - sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc); - fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET); - uclen = fstReaderUint64(xc->f); - fflush(xc->f); - zfd = dup(fileno(xc->f)); - zhandle = gzdopen(zfd, "rb"); - if(!zhandle) - { - close(zfd); - free(mem); - free(fnam); - return(0); - } + /* can't handle both set at once should never happen in a real file */ + if(!xc->contains_hier_section_lz4 && xc->contains_hier_section) + { + htyp = FST_BL_HIER; + } + else + if(xc->contains_hier_section_lz4 && !xc->contains_hier_section) + { + htyp = xc->contains_hier_section_lz4duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4; + } + + sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc); + fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET); + uclen = fstReaderUint64(xc->f); +#ifndef __MINGW32__ + fflush(xc->f); +#endif + if(htyp == FST_BL_HIER) + { + fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET); + uclen = fstReaderUint64(xc->f); +#ifndef __MINGW32__ + fflush(xc->f); +#endif + zfd = dup(fileno(xc->f)); + zhandle = gzdopen(zfd, "rb"); + if(!zhandle) + { + close(zfd); + free(mem); + free(fnam); + return(0); + } + } + else + if((htyp == FST_BL_HIER_LZ4) || (htyp == FST_BL_HIER_LZ4DUO)) + { + fstReaderFseeko(xc, xc->f, xc->hier_pos - 8, SEEK_SET); /* get section len */ + clen = fstReaderUint64(xc->f) - 16; + uclen = fstReaderUint64(xc->f); +#ifndef __MINGW32__ + fflush(xc->f); +#endif + } #ifndef __MINGW32__ - xc->fh = fopen(fnam, "w+b"); + xc->fh = fopen(fnam, "w+b"); if(!xc->fh) #endif { - xc->fh = tmpfile(); + xc->fh = tmpfile_open(&xc->fh_nam); free(fnam); fnam = NULL; if(!xc->fh) - { - free(mem); - return(0); - } - } + { + tmpfile_close(&xc->fh, &xc->fh_nam); + free(mem); + return(0); + } + } #ifndef __MINGW32__ - if(fnam) unlink(fnam); + if(fnam) unlink(fnam); #endif - for(hl = 0; hl < uclen; hl += FST_GZIO_LEN) - { - size_t len = ((uclen - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - hl); - size_t gzreadlen = gzread(zhandle, mem, len); /* rc should equal len... */ - size_t fwlen; + if(htyp == FST_BL_HIER) + { + for(hl = 0; hl < uclen; hl += FST_GZIO_LEN) + { + size_t len = ((uclen - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - hl); + size_t gzreadlen = gzread(zhandle, mem, len); /* rc should equal len... */ + size_t fwlen; - if(gzreadlen != len) - { - pass_status = 0; - break; - } + if(gzreadlen != len) + { + pass_status = 0; + break; + } - fwlen = fstFwrite(mem, len, 1, xc->fh); - if(fwlen != 1) - { - pass_status = 0; - break; - } + fwlen = fstFwrite(mem, len, 1, xc->fh); + if(fwlen != 1) + { + pass_status = 0; + break; + } + } + gzclose(zhandle); } - gzclose(zhandle); - free(mem); - free(fnam); + else + if(htyp == FST_BL_HIER_LZ4DUO) + { + unsigned char *lz4_cmem = malloc(clen); + unsigned char *lz4_ucmem = malloc(uclen); + unsigned char *lz4_ucmem2; + uint64_t uclen2; + int skiplen2 = 0; - fstReaderFseeko(xc, xc->f, offs_cache, SEEK_SET); - } + fstFread(lz4_cmem, clen, 1, xc->f); + + uclen2 = fstGetVarint64(lz4_cmem, &skiplen2); + lz4_ucmem2 = malloc(uclen2); + pass_status = (uclen2 == (uint64_t)LZ4_decompress_safe_partial ((char *)lz4_cmem + skiplen2, (char *)lz4_ucmem2, clen - skiplen2, uclen2, uclen2)); + if(pass_status) + { + pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_ucmem2, (char *)lz4_ucmem, uclen2, uclen, uclen)); + + if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1) + { + pass_status = 0; + } + } + + free(lz4_ucmem2); + free(lz4_ucmem); + free(lz4_cmem); + } + else + if(htyp == FST_BL_HIER_LZ4) + { + unsigned char *lz4_cmem = malloc(clen); + unsigned char *lz4_ucmem = malloc(uclen); + + fstFread(lz4_cmem, clen, 1, xc->f); + pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_cmem, (char *)lz4_ucmem, clen, uclen, uclen)); + + if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1) + { + pass_status = 0; + } + + free(lz4_ucmem); + free(lz4_cmem); + } + else /* FST_BL_SKIP */ + { + pass_status = 0; + } + + free(mem); + free(fnam); + + fstReaderFseeko(xc, xc->f, offs_cache, SEEK_SET); + } return(pass_status); } @@ -3318,15 +3756,15 @@ struct fstReaderContext *xc = (struct fstReaderContext *)ctx; int pass_status = 0; if(xc) - { - pass_status = 1; - if(!xc->fh) - { - pass_status = fstReaderRecreateHierFile(xc); - } + { + pass_status = 1; + if(!xc->fh) + { + pass_status = fstReaderRecreateHierFile(xc); + } - xc->do_rewind = 1; - } + xc->do_rewind = 1; + } return(pass_status); } @@ -3343,149 +3781,149 @@ int ch; if(!xc) return(NULL); if(!xc->fh) - { - if(!fstReaderRecreateHierFile(xc)) - { - return(NULL); - } - } + { + if(!fstReaderRecreateHierFile(xc)) + { + return(NULL); + } + } if(xc->do_rewind) - { - xc->do_rewind = 0; - xc->current_handle = 0; - fstReaderFseeko(xc, xc->fh, 0, SEEK_SET); - clearerr(xc->fh); - } + { + xc->do_rewind = 0; + xc->current_handle = 0; + fstReaderFseeko(xc, xc->fh, 0, SEEK_SET); + clearerr(xc->fh); + } if(!(isfeof=feof(xc->fh))) - { - int tag = fgetc(xc->fh); - switch(tag) - { - case FST_ST_VCD_SCOPE: - xc->hier.htyp = FST_HT_SCOPE; - xc->hier.u.scope.typ = fgetc(xc->fh); - xc->hier.u.scope.name = pnt = xc->str_scope_nam; - while((ch = fgetc(xc->fh))) - { - *(pnt++) = ch; - }; /* scopename */ - *pnt = 0; - xc->hier.u.scope.name_length = pnt - xc->hier.u.scope.name; + { + int tag = fgetc(xc->fh); + switch(tag) + { + case FST_ST_VCD_SCOPE: + xc->hier.htyp = FST_HT_SCOPE; + xc->hier.u.scope.typ = fgetc(xc->fh); + xc->hier.u.scope.name = pnt = xc->str_scope_nam; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* scopename */ + *pnt = 0; + xc->hier.u.scope.name_length = pnt - xc->hier.u.scope.name; - xc->hier.u.scope.component = pnt = xc->str_scope_comp; - while((ch = fgetc(xc->fh))) - { - *(pnt++) = ch; - }; /* scopecomp */ - *pnt = 0; - xc->hier.u.scope.component_length = pnt - xc->hier.u.scope.component; - break; + xc->hier.u.scope.component = pnt = xc->str_scope_comp; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* scopecomp */ + *pnt = 0; + xc->hier.u.scope.component_length = pnt - xc->hier.u.scope.component; + break; - case FST_ST_VCD_UPSCOPE: - xc->hier.htyp = FST_HT_UPSCOPE; - break; + case FST_ST_VCD_UPSCOPE: + xc->hier.htyp = FST_HT_UPSCOPE; + break; - case FST_ST_GEN_ATTRBEGIN: - xc->hier.htyp = FST_HT_ATTRBEGIN; - xc->hier.u.attr.typ = fgetc(xc->fh); - xc->hier.u.attr.subtype = fgetc(xc->fh); - xc->hier.u.attr.name = pnt = xc->str_scope_nam; - while((ch = fgetc(xc->fh))) - { - *(pnt++) = ch; - }; /* scopename */ - *pnt = 0; - xc->hier.u.attr.name_length = pnt - xc->hier.u.scope.name; + case FST_ST_GEN_ATTRBEGIN: + xc->hier.htyp = FST_HT_ATTRBEGIN; + xc->hier.u.attr.typ = fgetc(xc->fh); + xc->hier.u.attr.subtype = fgetc(xc->fh); + xc->hier.u.attr.name = pnt = xc->str_scope_nam; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* scopename */ + *pnt = 0; + xc->hier.u.attr.name_length = pnt - xc->hier.u.scope.name; - xc->hier.u.attr.arg = fstReaderVarint64(xc->fh); + xc->hier.u.attr.arg = fstReaderVarint64(xc->fh); - if(xc->hier.u.attr.typ == FST_AT_MISC) - { - if((xc->hier.u.attr.subtype == FST_MT_SOURCESTEM)||(xc->hier.u.attr.subtype == FST_MT_SOURCEISTEM)) - { - int sidx_skiplen_dummy = 0; - xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_nam, &sidx_skiplen_dummy); - } - } - break; + if(xc->hier.u.attr.typ == FST_AT_MISC) + { + if((xc->hier.u.attr.subtype == FST_MT_SOURCESTEM)||(xc->hier.u.attr.subtype == FST_MT_SOURCEISTEM)) + { + int sidx_skiplen_dummy = 0; + xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_nam, &sidx_skiplen_dummy); + } + } + break; - case FST_ST_GEN_ATTREND: - xc->hier.htyp = FST_HT_ATTREND; - break; + case FST_ST_GEN_ATTREND: + xc->hier.htyp = FST_HT_ATTREND; + break; - case FST_VT_VCD_EVENT: - case FST_VT_VCD_INTEGER: - case FST_VT_VCD_PARAMETER: - case FST_VT_VCD_REAL: - case FST_VT_VCD_REAL_PARAMETER: - case FST_VT_VCD_REG: - case FST_VT_VCD_SUPPLY0: - case FST_VT_VCD_SUPPLY1: - case FST_VT_VCD_TIME: - case FST_VT_VCD_TRI: - case FST_VT_VCD_TRIAND: - case FST_VT_VCD_TRIOR: - case FST_VT_VCD_TRIREG: - case FST_VT_VCD_TRI0: - case FST_VT_VCD_TRI1: - case FST_VT_VCD_WAND: - case FST_VT_VCD_WIRE: - case FST_VT_VCD_WOR: - case FST_VT_VCD_PORT: - case FST_VT_VCD_SPARRAY: - case FST_VT_VCD_REALTIME: - case FST_VT_GEN_STRING: - case FST_VT_SV_BIT: - case FST_VT_SV_LOGIC: - case FST_VT_SV_INT: - case FST_VT_SV_SHORTINT: - case FST_VT_SV_LONGINT: - case FST_VT_SV_BYTE: - case FST_VT_SV_ENUM: - case FST_VT_SV_SHORTREAL: - xc->hier.htyp = FST_HT_VAR; - xc->hier.u.var.svt_workspace = FST_SVT_NONE; - xc->hier.u.var.sdt_workspace = FST_SDT_NONE; - xc->hier.u.var.sxt_workspace = 0; - xc->hier.u.var.typ = tag; - xc->hier.u.var.direction = fgetc(xc->fh); - xc->hier.u.var.name = pnt = xc->str_scope_nam; - while((ch = fgetc(xc->fh))) - { - *(pnt++) = ch; - }; /* varname */ - *pnt = 0; - xc->hier.u.var.name_length = pnt - xc->hier.u.var.name; - xc->hier.u.var.length = fstReaderVarint32(xc->fh); - if(tag == FST_VT_VCD_PORT) - { - xc->hier.u.var.length -= 2; /* removal of delimiting spaces */ - xc->hier.u.var.length /= 3; /* port -> signal size adjust */ - } + case FST_VT_VCD_EVENT: + case FST_VT_VCD_INTEGER: + case FST_VT_VCD_PARAMETER: + case FST_VT_VCD_REAL: + case FST_VT_VCD_REAL_PARAMETER: + case FST_VT_VCD_REG: + case FST_VT_VCD_SUPPLY0: + case FST_VT_VCD_SUPPLY1: + case FST_VT_VCD_TIME: + case FST_VT_VCD_TRI: + case FST_VT_VCD_TRIAND: + case FST_VT_VCD_TRIOR: + case FST_VT_VCD_TRIREG: + case FST_VT_VCD_TRI0: + case FST_VT_VCD_TRI1: + case FST_VT_VCD_WAND: + case FST_VT_VCD_WIRE: + case FST_VT_VCD_WOR: + case FST_VT_VCD_PORT: + case FST_VT_VCD_SPARRAY: + case FST_VT_VCD_REALTIME: + case FST_VT_GEN_STRING: + case FST_VT_SV_BIT: + case FST_VT_SV_LOGIC: + case FST_VT_SV_INT: + case FST_VT_SV_SHORTINT: + case FST_VT_SV_LONGINT: + case FST_VT_SV_BYTE: + case FST_VT_SV_ENUM: + case FST_VT_SV_SHORTREAL: + xc->hier.htyp = FST_HT_VAR; + xc->hier.u.var.svt_workspace = FST_SVT_NONE; + xc->hier.u.var.sdt_workspace = FST_SDT_NONE; + xc->hier.u.var.sxt_workspace = 0; + xc->hier.u.var.typ = tag; + xc->hier.u.var.direction = fgetc(xc->fh); + xc->hier.u.var.name = pnt = xc->str_scope_nam; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* varname */ + *pnt = 0; + xc->hier.u.var.name_length = pnt - xc->hier.u.var.name; + xc->hier.u.var.length = fstReaderVarint32(xc->fh); + if(tag == FST_VT_VCD_PORT) + { + xc->hier.u.var.length -= 2; /* removal of delimiting spaces */ + xc->hier.u.var.length /= 3; /* port -> signal size adjust */ + } - alias = fstReaderVarint32(xc->fh); + alias = fstReaderVarint32(xc->fh); - if(!alias) - { - xc->current_handle++; - xc->hier.u.var.handle = xc->current_handle; - xc->hier.u.var.is_alias = 0; - } - else - { - xc->hier.u.var.handle = alias; - xc->hier.u.var.is_alias = 1; - } - - break; + if(!alias) + { + xc->current_handle++; + xc->hier.u.var.handle = xc->current_handle; + xc->hier.u.var.is_alias = 0; + } + else + { + xc->hier.u.var.handle = alias; + xc->hier.u.var.is_alias = 1; + } - default: - isfeof = 1; - break; - } - } + break; + + default: + isfeof = 1; + break; + } + } return(!isfeof ? &xc->hier : NULL); } @@ -3500,51 +3938,52 @@ int ch, scopetype; int vartype; uint32_t len, alias; /* uint32_t maxvalpos=0; */ -int num_signal_dyn = 65536; +unsigned int num_signal_dyn = 65536; int attrtype, subtype; uint64_t attrarg; +fstHandle maxhandle_scanbuild; if(!xc) return(0); xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */ if(!xc->fh) - { - if(!fstReaderRecreateHierFile(xc)) - { - return(0); - } - } + { + if(!fstReaderRecreateHierFile(xc)) + { + return(0); + } + } str = malloc(FST_ID_NAM_ATTR_SIZ+1); if(fv) - { - char time_dimension[2] = {0, 0}; - int time_scale = 1; + { + char time_dimension[2] = {0, 0}; + int time_scale = 1; + + 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); - 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 2: time_scale = 100; time_dimension[0] = ' '; break; + case 2: time_scale = 100; time_dimension[0] = 0; break; case 1: time_scale = 10; - case 0: time_dimension[0] = ' '; break; + case 0: time_dimension[0] = 0; break; case -1: time_scale = 100; time_dimension[0] = 'm'; break; case -2: time_scale = 10; case -3: time_dimension[0] = 'm'; break; - + case -4: time_scale = 100; time_dimension[0] = 'u'; break; case -5: time_scale = 10; case -6: time_dimension[0] = 'u'; break; - + case -10: time_scale = 100; time_dimension[0] = 'p'; break; case -11: time_scale = 10; case -12: time_dimension[0] = 'p'; break; - + case -13: time_scale = 100; time_dimension[0] = 'f'; break; case -14: time_scale = 10; case -15: time_dimension[0] = 'f'; break; @@ -3556,15 +3995,15 @@ if(fv) case -19: time_scale = 100; time_dimension[0] = 'z'; break; case -20: time_scale = 10; case -21: time_dimension[0] = 'z'; break; - + case -7: time_scale = 100; time_dimension[0] = 'n'; break; case -8: time_scale = 10; case -9: default: time_dimension[0] = 'n'; break; } - if(fv) fprintf(fv, "$timescale\n\t%d%ss\n$end\n", time_scale, time_dimension); - } + if(fv) fprintf(fv, "$timescale\n\t%d%ss\n$end\n", time_scale, time_dimension); + } xc->maxhandle = 0; xc->num_alias = 0; @@ -3577,182 +4016,188 @@ xc->signal_typs = malloc(num_signal_dyn*sizeof(unsigned char)); fstReaderFseeko(xc, xc->fh, 0, SEEK_SET); while(!feof(xc->fh)) - { - int tag = fgetc(xc->fh); - switch(tag) - { - case FST_ST_VCD_SCOPE: - scopetype = fgetc(xc->fh); - if((scopetype < FST_ST_MIN) || (scopetype > FST_ST_MAX)) scopetype = FST_ST_VCD_MODULE; - pnt = str; - while((ch = fgetc(xc->fh))) - { - *(pnt++) = ch; - }; /* scopename */ - *pnt = 0; - while(fgetc(xc->fh)) { }; /* scopecomp */ + { + int tag = fgetc(xc->fh); + switch(tag) + { + case FST_ST_VCD_SCOPE: + scopetype = fgetc(xc->fh); + if((scopetype < FST_ST_MIN) || (scopetype > FST_ST_MAX)) scopetype = FST_ST_VCD_MODULE; + pnt = str; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* scopename */ + *pnt = 0; + while(fgetc(xc->fh)) { }; /* scopecomp */ - if(fv) fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str); - break; + if(fv) fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str); + break; - case FST_ST_VCD_UPSCOPE: - if(fv) fprintf(fv, "$upscope $end\n"); - break; + case FST_ST_VCD_UPSCOPE: + if(fv) fprintf(fv, "$upscope $end\n"); + break; - case FST_ST_GEN_ATTRBEGIN: - attrtype = fgetc(xc->fh); - subtype = fgetc(xc->fh); - pnt = str; - while((ch = fgetc(xc->fh))) - { - *(pnt++) = ch; - }; /* attrname */ - *pnt = 0; + case FST_ST_GEN_ATTRBEGIN: + attrtype = fgetc(xc->fh); + subtype = fgetc(xc->fh); + pnt = str; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* attrname */ + *pnt = 0; - if(!str[0]) { strcpy(str, "\"\""); } + if(!str[0]) { strcpy(str, "\"\""); } - attrarg = fstReaderVarint64(xc->fh); + attrarg = fstReaderVarint64(xc->fh); - if(fv) - { - switch(attrtype) - { - case FST_AT_ARRAY: if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; - fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], arraytypes[subtype], str, attrarg); - break; - case FST_AT_ENUM: if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; - fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], enumvaluetypes[subtype], str, attrarg); - break; - case FST_AT_PACK: if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; - fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], packtypes[subtype], str, attrarg); - break; - case FST_AT_MISC: - default: attrtype = FST_AT_MISC; - if(subtype == FST_MT_COMMENT) - { - fprintf(fv, "$comment\n\t%s\n$end\n", str); - } - else - { - if((subtype == FST_MT_SOURCESTEM)||(subtype == FST_MT_SOURCEISTEM)) - { - int sidx_skiplen_dummy = 0; - uint64_t sidx = fstGetVarint64((unsigned char *)str, &sidx_skiplen_dummy); + if(fv && xc->use_vcd_extensions) + { + switch(attrtype) + { + case FST_AT_ARRAY: if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; + fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], arraytypes[subtype], str, attrarg); + break; + case FST_AT_ENUM: if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; + fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], enumvaluetypes[subtype], str, attrarg); + break; + case FST_AT_PACK: if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; + fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], packtypes[subtype], str, attrarg); + break; + case FST_AT_MISC: + default: attrtype = FST_AT_MISC; + if(subtype == FST_MT_COMMENT) + { + fprintf(fv, "$comment\n\t%s\n$end\n", str); + } + else + { + if((subtype == FST_MT_SOURCESTEM)||(subtype == FST_MT_SOURCEISTEM)) + { + int sidx_skiplen_dummy = 0; + uint64_t sidx = fstGetVarint64((unsigned char *)str, &sidx_skiplen_dummy); - fprintf(fv, "$attrbegin %s %02x %"PRId64" %"PRId64" $end\n", attrtypes[attrtype], subtype, sidx, attrarg); - } - else - { - fprintf(fv, "$attrbegin %s %02x %s %"PRId64" $end\n", attrtypes[attrtype], subtype, str, attrarg); - } - } - break; - } - } - break; + fprintf(fv, "$attrbegin %s %02x %"PRId64" %"PRId64" $end\n", attrtypes[attrtype], subtype, sidx, attrarg); + } + else + { + fprintf(fv, "$attrbegin %s %02x %s %"PRId64" $end\n", attrtypes[attrtype], subtype, str, attrarg); + } + } + break; + } + } + break; - case FST_ST_GEN_ATTREND: - if(fv) fprintf(fv, "$attrend $end\n"); - break; + case FST_ST_GEN_ATTREND: + if(fv && xc->use_vcd_extensions) fprintf(fv, "$attrend $end\n"); + break; - case FST_VT_VCD_EVENT: - case FST_VT_VCD_INTEGER: - case FST_VT_VCD_PARAMETER: - case FST_VT_VCD_REAL: - case FST_VT_VCD_REAL_PARAMETER: - case FST_VT_VCD_REG: - case FST_VT_VCD_SUPPLY0: - case FST_VT_VCD_SUPPLY1: - case FST_VT_VCD_TIME: - case FST_VT_VCD_TRI: - case FST_VT_VCD_TRIAND: - case FST_VT_VCD_TRIOR: - case FST_VT_VCD_TRIREG: - case FST_VT_VCD_TRI0: - case FST_VT_VCD_TRI1: - case FST_VT_VCD_WAND: - case FST_VT_VCD_WIRE: - case FST_VT_VCD_WOR: - case FST_VT_VCD_PORT: - case FST_VT_VCD_SPARRAY: - case FST_VT_VCD_REALTIME: - case FST_VT_GEN_STRING: - case FST_VT_SV_BIT: - case FST_VT_SV_LOGIC: - case FST_VT_SV_INT: - case FST_VT_SV_SHORTINT: - case FST_VT_SV_LONGINT: - case FST_VT_SV_BYTE: - case FST_VT_SV_ENUM: - case FST_VT_SV_SHORTREAL: - vartype = tag; - /* vardir = */ fgetc(xc->fh); /* unused in VCD reader, but need to advance read pointer */ - pnt = str; - while((ch = fgetc(xc->fh))) - { - *(pnt++) = ch; - }; /* varname */ - *pnt = 0; - len = fstReaderVarint32(xc->fh); - alias = fstReaderVarint32(xc->fh); + case FST_VT_VCD_EVENT: + case FST_VT_VCD_INTEGER: + case FST_VT_VCD_PARAMETER: + case FST_VT_VCD_REAL: + case FST_VT_VCD_REAL_PARAMETER: + case FST_VT_VCD_REG: + case FST_VT_VCD_SUPPLY0: + case FST_VT_VCD_SUPPLY1: + case FST_VT_VCD_TIME: + case FST_VT_VCD_TRI: + case FST_VT_VCD_TRIAND: + case FST_VT_VCD_TRIOR: + case FST_VT_VCD_TRIREG: + case FST_VT_VCD_TRI0: + case FST_VT_VCD_TRI1: + case FST_VT_VCD_WAND: + case FST_VT_VCD_WIRE: + case FST_VT_VCD_WOR: + case FST_VT_VCD_PORT: + case FST_VT_VCD_SPARRAY: + case FST_VT_VCD_REALTIME: + case FST_VT_GEN_STRING: + case FST_VT_SV_BIT: + case FST_VT_SV_LOGIC: + case FST_VT_SV_INT: + case FST_VT_SV_SHORTINT: + case FST_VT_SV_LONGINT: + case FST_VT_SV_BYTE: + case FST_VT_SV_ENUM: + case FST_VT_SV_SHORTREAL: + vartype = tag; + /* vardir = */ fgetc(xc->fh); /* unused in VCD reader, but need to advance read pointer */ + pnt = str; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* varname */ + *pnt = 0; + len = fstReaderVarint32(xc->fh); + alias = fstReaderVarint32(xc->fh); - if(!alias) - { - if(xc->maxhandle == num_signal_dyn) - { - num_signal_dyn *= 2; - xc->signal_lens = realloc(xc->signal_lens, num_signal_dyn*sizeof(uint32_t)); - xc->signal_typs = realloc(xc->signal_typs, num_signal_dyn*sizeof(unsigned char)); - } - xc->signal_lens[xc->maxhandle] = len; - xc->signal_typs[xc->maxhandle] = vartype; + if(!alias) + { + if(xc->maxhandle == num_signal_dyn) + { + num_signal_dyn *= 2; + xc->signal_lens = realloc(xc->signal_lens, num_signal_dyn*sizeof(uint32_t)); + xc->signal_typs = realloc(xc->signal_typs, num_signal_dyn*sizeof(unsigned char)); + } + xc->signal_lens[xc->maxhandle] = len; + xc->signal_typs[xc->maxhandle] = vartype; - /* maxvalpos+=len; */ - if(len > xc->longest_signal_value_len) - { - xc->longest_signal_value_len = len; - } + /* maxvalpos+=len; */ + if(len > xc->longest_signal_value_len) + { + xc->longest_signal_value_len = len; + } - if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL)) - { - len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32; - xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; - } - if(fv) - { - uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); - fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, fstVcdID(xc->maxhandle+1), str); - } - xc->maxhandle++; - } - else - { - if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL)) - { - len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32; - xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; - } - if(fv) - { - uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); - fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, fstVcdID(alias), str); - } - xc->num_alias++; - } - - break; + if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL)) + { + len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32; + xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; + } + if(fv) + { + char vcdid_buf[16]; + uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); + fstVcdID(vcdid_buf, xc->maxhandle+1); + fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); + } + xc->maxhandle++; + } + else + { + if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL)) + { + len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32; + xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; + } + if(fv) + { + char vcdid_buf[16]; + uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); + fstVcdID(vcdid_buf, alias); + fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); + } + xc->num_alias++; + } - default: - break; - } - } + break; + + default: + break; + } + } if(fv) fprintf(fv, "$enddefinitions $end\n"); -xc->signal_lens = realloc(xc->signal_lens, xc->maxhandle*sizeof(uint32_t)); -xc->signal_typs = realloc(xc->signal_typs, xc->maxhandle*sizeof(unsigned char)); +maxhandle_scanbuild = xc->maxhandle ? xc->maxhandle : 1; /*scan-build warning suppression, in reality we have at least one signal */ + +xc->signal_lens = realloc(xc->signal_lens, maxhandle_scanbuild*sizeof(uint32_t)); +xc->signal_typs = realloc(xc->signal_typs, maxhandle_scanbuild*sizeof(unsigned char)); free(xc->process_mask); -xc->process_mask = calloc(1, (xc->maxhandle+7)/8); +xc->process_mask = calloc(1, (maxhandle_scanbuild+7)/8); free(xc->temp_signal_value_buf); xc->temp_signal_value_buf = malloc(xc->longest_signal_value_len + 1); @@ -3780,293 +4225,306 @@ int gzread_pass_status = 1; sectype = fgetc(xc->f); if(sectype == FST_BL_ZWRAPPER) - { - FILE *fcomp; - off_t offpnt, uclen; - char gz_membuf[FST_GZIO_LEN]; - void *zhandle; - int zfd; + { + FILE *fcomp; + off_t offpnt, uclen; + char gz_membuf[FST_GZIO_LEN]; + void *zhandle; + int zfd; int flen = strlen(xc->filename); char *hf; - seclen = fstReaderUint64(xc->f); - uclen = fstReaderUint64(xc->f); + seclen = fstReaderUint64(xc->f); + uclen = fstReaderUint64(xc->f); - if(!seclen) return(0); /* not finished compressing, this is a failed read */ + if(!seclen) return(0); /* not finished compressing, this is a failed read */ hf = calloc(1, flen + 16 + 32 + 1); - sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc); - fcomp = fopen(hf, "w+b"); - if(!fcomp) - { - fcomp = tmpfile(); - free(hf); hf = NULL; - if(!fcomp) return(0); - } + sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc); + fcomp = fopen(hf, "w+b"); + if(!fcomp) + { + fcomp = tmpfile_open(&xc->f_nam); + free(hf); hf = NULL; + if(!fcomp) { tmpfile_close(&fcomp, &xc->f_nam); return(0); } + } #if defined(FST_MACOSX) - setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ + setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ #endif #ifdef __MINGW32__ - setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ - xc->filename_unpacked = hf; + setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ + xc->filename_unpacked = hf; #else - if(hf) - { - unlink(hf); - free(hf); - } + if(hf) + { + unlink(hf); + free(hf); + } #endif - fstReaderFseeko(xc, xc->f, 1+8+8, SEEK_SET); - fflush(xc->f); + fstReaderFseeko(xc, xc->f, 1+8+8, SEEK_SET); +#ifndef __MINGW32__ + fflush(xc->f); +#endif - zfd = dup(fileno(xc->f)); - zhandle = gzdopen(zfd, "rb"); - if(zhandle) - { - for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) - { - size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); - size_t gzreadlen = gzread(zhandle, gz_membuf, this_len); - size_t fwlen; + zfd = dup(fileno(xc->f)); + zhandle = gzdopen(zfd, "rb"); + if(zhandle) + { + for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) + { + size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); + size_t gzreadlen = gzread(zhandle, gz_membuf, this_len); + size_t fwlen; - if(gzreadlen != this_len) - { - gzread_pass_status = 0; - break; - } - fwlen = fstFwrite(gz_membuf, this_len, 1, fcomp); - if(fwlen != 1) - { - gzread_pass_status = 0; - break; - } - } - gzclose(zhandle); - } - else - { - close(zfd); - } - fflush(fcomp); - fclose(xc->f); - xc->f = fcomp; - } + if(gzreadlen != this_len) + { + gzread_pass_status = 0; + break; + } + fwlen = fstFwrite(gz_membuf, this_len, 1, fcomp); + if(fwlen != 1) + { + gzread_pass_status = 0; + break; + } + } + gzclose(zhandle); + } + else + { + close(zfd); + } + fflush(fcomp); + fclose(xc->f); + xc->f = fcomp; + } if(gzread_pass_status) - { - fstReaderFseeko(xc, xc->f, 0, SEEK_END); - endfile = ftello(xc->f); + { + fstReaderFseeko(xc, xc->f, 0, SEEK_END); + endfile = ftello(xc->f); - while(blkpos < endfile) - { - fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); - - sectype = fgetc(xc->f); - seclen = fstReaderUint64(xc->f); - - if(sectype == EOF) - { - break; - } + while(blkpos < endfile) + { + fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); - if((hdr_incomplete) && (!seclen)) - { + sectype = fgetc(xc->f); + seclen = fstReaderUint64(xc->f); + + if(sectype == EOF) + { break; } - - if(!hdr_seen && (sectype != FST_BL_HDR)) - { - break; - } - - blkpos++; - if(sectype == FST_BL_HDR) - { - if(!hdr_seen) - { - int ch; - double dcheck; - - xc->start_time = fstReaderUint64(xc->f); - xc->end_time = fstReaderUint64(xc->f); - - hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0); - - fstFread(&dcheck, 8, 1, xc->f); - xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST); - if(!xc->double_endian_match) - { - union { - unsigned char rvs_buf[8]; - double d; - } vu; - - unsigned char *dcheck_alias = (unsigned char *)&dcheck; - int rvs_idx; - - for(rvs_idx=0;rvs_idx<8;rvs_idx++) - { - vu.rvs_buf[rvs_idx] = dcheck_alias[7-rvs_idx]; - } - if(vu.d != FST_DOUBLE_ENDTEST) - { - break; /* either corrupt file or wrong architecture (offset +33 also functions as matchword) */ - } - } - - hdr_seen = 1; - - xc->mem_used_by_writer = fstReaderUint64(xc->f); - xc->scope_count = fstReaderUint64(xc->f); - xc->var_count = fstReaderUint64(xc->f); - xc->maxhandle = fstReaderUint64(xc->f); - xc->num_alias = xc->var_count - xc->maxhandle; - xc->vc_section_count = fstReaderUint64(xc->f); - ch = fgetc(xc->f); - xc->timescale = (signed char)ch; - fstFread(xc->version, FST_HDR_SIM_VERSION_SIZE, 1, xc->f); - 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; - ch = fgetc(xc->f); - xc->filetype = (unsigned char)ch; - xc->timezero = fstReaderUint64(xc->f); - } - } - else if((sectype == FST_BL_VCDATA) || (sectype == FST_BL_VCDATA_DYN_ALIAS)) - { - if(hdr_incomplete) - { - uint64_t bt = fstReaderUint64(xc->f); - xc->end_time = fstReaderUint64(xc->f); - - if(!vc_section_count_actual) { xc->start_time = bt; } - } - vc_section_count_actual++; - } - else if(sectype == FST_BL_GEOM) - { - if(!hdr_incomplete) - { - uint64_t clen = seclen - 24; - uint64_t uclen = fstReaderUint64(xc->f); - unsigned char *ucdata = malloc(uclen); - unsigned char *pnt = ucdata; - int i; - - xc->contains_geom_section = 1; - xc->maxhandle = fstReaderUint64(xc->f); - xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */ + if((hdr_incomplete) && (!seclen)) + { + break; + } - free(xc->process_mask); - xc->process_mask = calloc(1, (xc->maxhandle+7)/8); + if(!hdr_seen && (sectype != FST_BL_HDR)) + { + break; + } - if(clen != uclen) - { - unsigned char *cdata = malloc(clen); - unsigned long destlen = uclen; - unsigned long sourcelen = clen; - int rc; - - fstFread(cdata, clen, 1, xc->f); - rc = uncompress(ucdata, &destlen, cdata, sourcelen); + blkpos++; + if(sectype == FST_BL_HDR) + { + if(!hdr_seen) + { + int ch; + double dcheck; - if(rc != Z_OK) - { - printf("geom uncompress rc = %d\n", rc); - exit(255); - } - - free(cdata); - } - else - { - fstFread(ucdata, uclen, 1, xc->f); - } - - free(xc->signal_lens); - xc->signal_lens = malloc(sizeof(uint32_t) * xc->maxhandle); - free(xc->signal_typs); - xc->signal_typs = malloc(sizeof(unsigned char) * xc->maxhandle); - - for(i=0;imaxhandle;i++) - { - int skiplen; - uint64_t val = fstGetVarint32(pnt, &skiplen); - - pnt += skiplen; - - if(val) - { - xc->signal_lens[i] = (val != 0xFFFFFFFF) ? val : 0; - xc->signal_typs[i] = FST_VT_VCD_WIRE; - if(xc->signal_lens[i] > xc->longest_signal_value_len) - { - xc->longest_signal_value_len = xc->signal_lens[i]; - } - } - else - { - xc->signal_lens[i] = 8; /* backpatch in real */ - xc->signal_typs[i] = FST_VT_VCD_REAL; - /* xc->longest_signal_value_len handled above by overly large init size */ - } - } + xc->start_time = fstReaderUint64(xc->f); + xc->end_time = fstReaderUint64(xc->f); - free(xc->temp_signal_value_buf); - xc->temp_signal_value_buf = malloc(xc->longest_signal_value_len + 1); - - free(ucdata); - } - } - else if(sectype == FST_BL_HIER) - { - xc->contains_hier_section = 1; - xc->hier_pos = ftello(xc->f); - } - else if(sectype == FST_BL_BLACKOUT) - { - uint32_t i; - uint64_t cur_bl = 0; - uint64_t delta; + hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0); - xc->num_blackouts = fstReaderVarint32(xc->f); - free(xc->blackout_times); - xc->blackout_times = calloc(xc->num_blackouts, sizeof(uint64_t)); - free(xc->blackout_activity); - xc->blackout_activity = calloc(xc->num_blackouts, sizeof(unsigned char)); + fstFread(&dcheck, 8, 1, xc->f); + xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST); + if(!xc->double_endian_match) + { + union { + unsigned char rvs_buf[8]; + double d; + } vu; - for(i=0;inum_blackouts;i++) - { - xc->blackout_activity[i] = fgetc(xc->f) != 0; - delta = fstReaderVarint64(xc->f); - cur_bl += delta; - xc->blackout_times[i] = cur_bl; - } - } - - blkpos += seclen; - if(!hdr_seen) break; - } + unsigned char *dcheck_alias = (unsigned char *)&dcheck; + int rvs_idx; - if(hdr_seen) - { - if(xc->vc_section_count != vc_section_count_actual) - { - xc->vc_section_count = vc_section_count_actual; - } - - if(!xc->contains_geom_section) - { - fstReaderProcessHier(xc, NULL); /* recreate signal_lens/signal_typs info */ - } - } - } + for(rvs_idx=0;rvs_idx<8;rvs_idx++) + { + vu.rvs_buf[rvs_idx] = dcheck_alias[7-rvs_idx]; + } + if(vu.d != FST_DOUBLE_ENDTEST) + { + break; /* either corrupt file or wrong architecture (offset +33 also functions as matchword) */ + } + } + + hdr_seen = 1; + + xc->mem_used_by_writer = fstReaderUint64(xc->f); + xc->scope_count = fstReaderUint64(xc->f); + xc->var_count = fstReaderUint64(xc->f); + xc->maxhandle = fstReaderUint64(xc->f); + xc->num_alias = xc->var_count - xc->maxhandle; + xc->vc_section_count = fstReaderUint64(xc->f); + ch = fgetc(xc->f); + xc->timescale = (signed char)ch; + fstFread(xc->version, FST_HDR_SIM_VERSION_SIZE, 1, xc->f); + 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; + ch = fgetc(xc->f); + xc->filetype = (unsigned char)ch; + xc->timezero = fstReaderUint64(xc->f); + } + } + else if((sectype == FST_BL_VCDATA) || (sectype == FST_BL_VCDATA_DYN_ALIAS) || (sectype == FST_BL_VCDATA_DYN_ALIAS2)) + { + if(hdr_incomplete) + { + uint64_t bt = fstReaderUint64(xc->f); + xc->end_time = fstReaderUint64(xc->f); + + if(!vc_section_count_actual) { xc->start_time = bt; } + } + + vc_section_count_actual++; + } + else if(sectype == FST_BL_GEOM) + { + if(!hdr_incomplete) + { + uint64_t clen = seclen - 24; + uint64_t uclen = fstReaderUint64(xc->f); + unsigned char *ucdata = malloc(uclen); + unsigned char *pnt = ucdata; + unsigned int i; + + xc->contains_geom_section = 1; + xc->maxhandle = fstReaderUint64(xc->f); + xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */ + + free(xc->process_mask); + xc->process_mask = calloc(1, (xc->maxhandle+7)/8); + + if(clen != uclen) + { + unsigned char *cdata = malloc(clen); + unsigned long destlen = uclen; + unsigned long sourcelen = clen; + int rc; + + fstFread(cdata, clen, 1, xc->f); + rc = uncompress(ucdata, &destlen, cdata, sourcelen); + + if(rc != Z_OK) + { + printf("geom uncompress rc = %d\n", rc); + exit(255); + } + + free(cdata); + } + else + { + fstFread(ucdata, uclen, 1, xc->f); + } + + free(xc->signal_lens); + xc->signal_lens = malloc(sizeof(uint32_t) * xc->maxhandle); + free(xc->signal_typs); + xc->signal_typs = malloc(sizeof(unsigned char) * xc->maxhandle); + + for(i=0;imaxhandle;i++) + { + int skiplen; + uint64_t val = fstGetVarint32(pnt, &skiplen); + + pnt += skiplen; + + if(val) + { + xc->signal_lens[i] = (val != 0xFFFFFFFF) ? val : 0; + xc->signal_typs[i] = FST_VT_VCD_WIRE; + if(xc->signal_lens[i] > xc->longest_signal_value_len) + { + xc->longest_signal_value_len = xc->signal_lens[i]; + } + } + else + { + xc->signal_lens[i] = 8; /* backpatch in real */ + xc->signal_typs[i] = FST_VT_VCD_REAL; + /* xc->longest_signal_value_len handled above by overly large init size */ + } + } + + free(xc->temp_signal_value_buf); + xc->temp_signal_value_buf = malloc(xc->longest_signal_value_len + 1); + + free(ucdata); + } + } + else if(sectype == FST_BL_HIER) + { + xc->contains_hier_section = 1; + xc->hier_pos = ftello(xc->f); + } + else if(sectype == FST_BL_HIER_LZ4DUO) + { + xc->contains_hier_section_lz4 = 1; + xc->contains_hier_section_lz4duo = 1; + xc->hier_pos = ftello(xc->f); + } + else if(sectype == FST_BL_HIER_LZ4) + { + xc->contains_hier_section_lz4 = 1; + xc->hier_pos = ftello(xc->f); + } + else if(sectype == FST_BL_BLACKOUT) + { + uint32_t i; + uint64_t cur_bl = 0; + uint64_t delta; + + xc->num_blackouts = fstReaderVarint32(xc->f); + free(xc->blackout_times); + xc->blackout_times = calloc(xc->num_blackouts, sizeof(uint64_t)); + free(xc->blackout_activity); + xc->blackout_activity = calloc(xc->num_blackouts, sizeof(unsigned char)); + + for(i=0;inum_blackouts;i++) + { + xc->blackout_activity[i] = fgetc(xc->f) != 0; + delta = fstReaderVarint64(xc->f); + cur_bl += delta; + xc->blackout_times[i] = cur_bl; + } + } + + blkpos += seclen; + if(!hdr_seen) break; + } + + if(hdr_seen) + { + if(xc->vc_section_count != vc_section_count_actual) + { + xc->vc_section_count = vc_section_count_actual; + } + + if(!xc->contains_geom_section) + { + fstReaderProcessHier(xc, NULL); /* recreate signal_lens/signal_typs info */ + } + } + } return(hdr_seen); } @@ -4093,31 +4551,31 @@ if((!nam)||(!(xc->f=fopen(nam, "rb")))) { int flen = strlen(nam); char *hf = calloc(1, flen + 6); - int rc; + int rc; #if defined(__MINGW32__) || defined(FST_MACOSX) - setvbuf(xc->f, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ + setvbuf(xc->f, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ #endif memcpy(hf, nam, flen); strcpy(hf + flen, ".hier"); xc->fh = fopen(hf, "rb"); - free(hf); - xc->filename = strdup(nam); - rc = fstReaderInit(xc); + free(hf); + xc->filename = strdup(nam); + rc = fstReaderInit(xc); - if((rc) && (xc->vc_section_count) && (xc->maxhandle) && ((xc->fh)||(xc->contains_hier_section))) - { - /* more init */ - xc->do_rewind = 1; - } - else - { - fstReaderClose(xc); - xc = NULL; - } - } + if((rc) && (xc->vc_section_count) && (xc->maxhandle) && ((xc->fh)||(xc->contains_hier_section||(xc->contains_hier_section_lz4)))) + { + /* more init */ + xc->do_rewind = 1; + } + else + { + fstReaderClose(xc); + xc = NULL; + } + } return(xc); } @@ -4127,15 +4585,15 @@ static void fstReaderDeallocateRvatData(void *ctx) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) - { - free(xc->rvat_chain_mem); xc->rvat_chain_mem = NULL; - free(xc->rvat_frame_data); xc->rvat_frame_data = NULL; - free(xc->rvat_time_table); xc->rvat_time_table = NULL; - free(xc->rvat_chain_table); xc->rvat_chain_table = NULL; - free(xc->rvat_chain_table_lengths); xc->rvat_chain_table_lengths = NULL; + { + free(xc->rvat_chain_mem); xc->rvat_chain_mem = NULL; + free(xc->rvat_frame_data); xc->rvat_frame_data = NULL; + free(xc->rvat_time_table); xc->rvat_time_table = NULL; + free(xc->rvat_chain_table); xc->rvat_chain_table = NULL; + free(xc->rvat_chain_table_lengths); xc->rvat_chain_table_lengths = NULL; - xc->rvat_data_valid = 0; - } + xc->rvat_data_valid = 0; + } } @@ -4144,36 +4602,36 @@ void fstReaderClose(void *ctx) struct fstReaderContext *xc = (struct fstReaderContext *)ctx; if(xc) - { - fstReaderDeallocateScopeData(xc); - fstReaderDeallocateRvatData(xc); - free(xc->rvat_sig_offs); xc->rvat_sig_offs = NULL; + { + fstReaderDeallocateScopeData(xc); + fstReaderDeallocateRvatData(xc); + free(xc->rvat_sig_offs); xc->rvat_sig_offs = NULL; - free(xc->process_mask); xc->process_mask = NULL; - free(xc->blackout_times); xc->blackout_times = NULL; - free(xc->blackout_activity); xc->blackout_activity = NULL; - free(xc->temp_signal_value_buf); xc->temp_signal_value_buf = NULL; - free(xc->signal_typs); xc->signal_typs = NULL; - free(xc->signal_lens); xc->signal_lens = NULL; - free(xc->filename); xc->filename = NULL; + free(xc->process_mask); xc->process_mask = NULL; + free(xc->blackout_times); xc->blackout_times = NULL; + free(xc->blackout_activity); xc->blackout_activity = NULL; + free(xc->temp_signal_value_buf); xc->temp_signal_value_buf = NULL; + free(xc->signal_typs); xc->signal_typs = NULL; + free(xc->signal_lens); xc->signal_lens = NULL; + free(xc->filename); xc->filename = NULL; - if(xc->fh) - { - fclose(xc->fh); xc->fh = NULL; - } + if(xc->fh) + { + tmpfile_close(&xc->fh, &xc->fh_nam); + } - if(xc->f) - { - fclose(xc->f); xc->f = NULL; - if(xc->filename_unpacked) - { - unlink(xc->filename_unpacked); - free(xc->filename_unpacked); - } - } + if(xc->f) + { + tmpfile_close(&xc->f, &xc->f_nam); + if(xc->filename_unpacked) + { + unlink(xc->filename_unpacked); + free(xc->filename_unpacked); + } + } - free(xc); - } + free(xc); + } } @@ -4192,7 +4650,7 @@ return(fstReaderIterBlocks2(ctx, value_change_callback, NULL, user_callback_data int fstReaderIterBlocks2(void *ctx, void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value), - void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len), + void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len), void *user_callback_data_pointer, FILE *fv) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; @@ -4200,14 +4658,14 @@ struct fstReaderContext *xc = (struct fstReaderContext *)ctx; uint64_t previous_time = UINT64_MAX; uint64_t *time_table = NULL; uint64_t tsec_nitems; -int secnum = 0; +unsigned int secnum = 0; int blocks_skipped = 0; off_t blkpos = 0; uint64_t seclen, beg_tim; #ifdef FST_DEBUG uint64_t end_tim; #endif -uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle; +uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle; off_t vc_start; off_t indx_pntr, indx_pos; off_t *chain_table = NULL; @@ -4226,6 +4684,8 @@ uint32_t traversal_mem_offs; uint32_t *scatterptr, *headptr, *length_remaining; uint32_t cur_blackout = 0; int packtype; +unsigned char *mc_mem = NULL; +uint32_t mc_mem_len; /* corresponds to largest value encountered in chain_table_lengths[i] */ if(!xc) return(0); @@ -4233,824 +4693,933 @@ scatterptr = calloc(xc->maxhandle, sizeof(uint32_t)); headptr = calloc(xc->maxhandle, sizeof(uint32_t)); length_remaining = calloc(xc->maxhandle, sizeof(uint32_t)); -if(fv) { fprintf(fv, "$dumpvars\n"); } +if(fv) + { + fprintf(fv, "$dumpvars\n"); +#ifndef FST_WRITEX_DISABLE + fflush(fv); + setvbuf(fv, (char *) NULL, _IONBF, 0); /* even buffered IO is slow so disable it and use our own routines that don't need seeking */ + xc->writex_fd = fileno(fv); +#endif + } for(;;) - { - uint32_t *tc_head = NULL; - traversal_mem_offs = 0; + { + uint32_t *tc_head = NULL; + traversal_mem_offs = 0; - fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); - - sectype = fgetc(xc->f); - seclen = fstReaderUint64(xc->f); + fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); - if((sectype == EOF) || (sectype == FST_BL_SKIP)) - { + sectype = fgetc(xc->f); + seclen = fstReaderUint64(xc->f); + + if((sectype == EOF) || (sectype == FST_BL_SKIP)) + { #ifdef FST_DEBUG - printf("<< EOF >>\n"); + fprintf(stderr, "<< EOF >>\n"); #endif - break; - } + break; + } - blkpos++; - if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS)) - { - blkpos += seclen; - continue; - } + blkpos++; + if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2)) + { + blkpos += seclen; + continue; + } - if(!seclen) break; + if(!seclen) break; - beg_tim = fstReaderUint64(xc->f); + beg_tim = fstReaderUint64(xc->f); #ifdef FST_DEBUG - end_tim = + end_tim = #endif - fstReaderUint64(xc->f); + fstReaderUint64(xc->f); - if(xc->limit_range_valid) - { - if(beg_tim < xc->limit_range_start) - { - blocks_skipped++; - blkpos += seclen; - continue; - } + if(xc->limit_range_valid) + { + if(beg_tim < xc->limit_range_start) + { + blocks_skipped++; + blkpos += seclen; + continue; + } - if(beg_tim > xc->limit_range_end) /* likely the compare in for(i=0;i xc->limit_range_end) /* likely the compare in for(i=0;if); - mem_for_traversal = malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */ + mem_required_for_traversal = fstReaderUint64(xc->f); + mem_for_traversal = malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */ #ifdef FST_DEBUG - printf("sec: %d seclen: %d begtim: %d endtim: %d\n", - secnum, (int)seclen, (int)beg_tim, (int)end_tim); - printf("\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal); + fprintf(stderr, "sec: %u seclen: %d begtim: %d endtim: %d\n", + secnum, (int)seclen, (int)beg_tim, (int)end_tim); + fprintf(stderr, "\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal); #endif - /* process time block */ - { - unsigned char *ucdata; - unsigned char *cdata; - unsigned long destlen /* = tsec_uclen */; /* scan-build */ - unsigned long sourcelen /*= tsec_clen */; /* scan-build */ - int rc; - unsigned char *tpnt; - uint64_t tpval; - int ti; + /* process time block */ + { + unsigned char *ucdata; + unsigned char *cdata; + unsigned long destlen /* = tsec_uclen */; /* scan-build */ + unsigned long sourcelen /*= tsec_clen */; /* scan-build */ + int rc; + unsigned char *tpnt; + uint64_t tpval; + unsigned int ti; - if(fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET) != 0) break; - tsec_uclen = fstReaderUint64(xc->f); - tsec_clen = fstReaderUint64(xc->f); - tsec_nitems = fstReaderUint64(xc->f); + if(fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET) != 0) break; + tsec_uclen = fstReaderUint64(xc->f); + tsec_clen = fstReaderUint64(xc->f); + tsec_nitems = fstReaderUint64(xc->f); #ifdef FST_DEBUG - 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; + fprintf(stderr, "\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; - fstReaderFseeko(xc, xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); + fstReaderFseeko(xc, xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); - if(tsec_uclen != tsec_clen) - { - cdata = malloc(tsec_clen); - fstFread(cdata, tsec_clen, 1, xc->f); - - rc = uncompress(ucdata, &destlen, cdata, sourcelen); - - if(rc != Z_OK) - { - printf("tsec uncompress rc = %d\n", rc); - exit(255); - } - - free(cdata); - } - else - { - fstFread(ucdata, tsec_uclen, 1, xc->f); - } - - free(time_table); - time_table = calloc(tsec_nitems, sizeof(uint64_t)); - tpnt = ucdata; - tpval = 0; - for(ti=0;tif); - tc_head = calloc(tsec_nitems, sizeof(uint32_t)); - free(ucdata); - } + rc = uncompress(ucdata, &destlen, cdata, sourcelen); - fstReaderFseeko(xc, xc->f, blkpos+32, SEEK_SET); + if(rc != Z_OK) + { + printf("tsec uncompress rc = %d\n", rc); + exit(255); + } - frame_uclen = fstReaderVarint64(xc->f); - frame_clen = fstReaderVarint64(xc->f); - frame_maxhandle = fstReaderVarint64(xc->f); + free(cdata); + } + else + { + fstFread(ucdata, tsec_uclen, 1, xc->f); + } - if(secnum == 0) - { - if((beg_tim != time_table[0]) || (blocks_skipped)) - { - unsigned char *mu = malloc(frame_uclen); - uint32_t sig_offs = 0; + free(time_table); + time_table = calloc(tsec_nitems, sizeof(uint64_t)); + tpnt = ucdata; + tpval = 0; + for(ti=0;tinum_blackouts)&&(cur_blackout != xc->num_blackouts)) - { - if(beg_tim == xc->blackout_times[cur_blackout]) - { - fprintf(fv, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); - } - } - } + tc_head = calloc(tsec_nitems /* scan-build */ ? tsec_nitems : 1, sizeof(uint32_t)); + free(ucdata); + } - if(frame_uclen == frame_clen) - { - fstFread(mu, frame_uclen, 1, xc->f); - } - else - { - unsigned char *mc = malloc(frame_clen); - int rc; + fstReaderFseeko(xc, xc->f, blkpos+32, SEEK_SET); - unsigned long destlen = frame_uclen; - unsigned long sourcelen = frame_clen; + frame_uclen = fstReaderVarint64(xc->f); + frame_clen = fstReaderVarint64(xc->f); + frame_maxhandle = fstReaderVarint64(xc->f); - fstFread(mc, sourcelen, 1, xc->f); - rc = uncompress(mu, &destlen, mc, sourcelen); - if(rc != Z_OK) - { - printf("rc: %d\n", rc); - exit(255); - } - free(mc); - } + if(secnum == 0) + { + if((beg_tim != time_table[0]) || (blocks_skipped)) + { + unsigned char *mu = malloc(frame_uclen); + uint32_t sig_offs = 0; + + if(fv) + { + char wx_buf[32]; + int wx_len; + + if(beg_tim) + { + wx_len = sprintf(wx_buf, "#%"PRIu64"\n", beg_tim); + fstWritex(xc, wx_buf, wx_len); + } + if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts)) + { + if(beg_tim == xc->blackout_times[cur_blackout]) + { + wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); + fstWritex(xc, wx_buf, wx_len); + } + } + } + + if(frame_uclen == frame_clen) + { + fstFread(mu, frame_uclen, 1, xc->f); + } + else + { + unsigned char *mc = malloc(frame_clen); + int rc; + + unsigned long destlen = frame_uclen; + unsigned long sourcelen = frame_clen; + + fstFread(mc, sourcelen, 1, xc->f); + rc = uncompress(mu, &destlen, mc, sourcelen); + if(rc != Z_OK) + { + printf("rc: %d\n", rc); + exit(255); + } + free(mc); + } - for(idx=0;idxprocess_mask[process_idx]&(1<signal_lens[idx] <= 1) - { - if(xc->signal_lens[idx] == 1) - { - unsigned char val = mu[sig_offs]; - if(value_change_callback) - { - xc->temp_signal_value_buf[0] = val; - xc->temp_signal_value_buf[1] = 0; - value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); - } - else - { - if(fv) - { - int vcdid_len; - const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len); - fputc(val, fv); - fstFwrite(vcd_id, vcdid_len, 1, fv); - fputc('\n', fv); - } - } - } - else - { - /* variable-length ("0" length) records have no initial state */ - } - } - else - { - if(xc->signal_typs[idx] != FST_VT_VCD_REAL) - { - if(value_change_callback) - { - memcpy(xc->temp_signal_value_buf, mu+sig_offs, xc->signal_lens[idx]); - xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0; - value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); - } - else - { - if(fv) - { - int vcdid_len; - const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len); - fputc((xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p', fv); - fstFwrite(mu+sig_offs, xc->signal_lens[idx], 1, fv); - fputc(' ', fv); - fstFwrite(vcd_id, vcdid_len, 1, fv); - fputc('\n', fv); - } - } - } - else - { - double d; - unsigned char *clone_d; - unsigned char *srcdata = mu+sig_offs; - - if(value_change_callback) - { - if(xc->native_doubles_for_cb) - { - if(xc->double_endian_match) - { - clone_d = srcdata; - } - else - { - int j; - - clone_d = (unsigned char *)&d; - for(j=0;j<8;j++) - { - clone_d[j] = srcdata[7-j]; - } - } - value_change_callback(user_callback_data_pointer, beg_tim, idx+1, clone_d); - } - else - { - clone_d = (unsigned char *)&d; - if(xc->double_endian_match) - { - memcpy(clone_d, srcdata, 8); - } - else - { - int j; - - for(j=0;j<8;j++) - { - clone_d[j] = srcdata[7-j]; - } - } - sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); - value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); - } - } - else - { - if(fv) - { - clone_d = (unsigned char *)&d; - if(xc->double_endian_match) - { - memcpy(clone_d, srcdata, 8); - } - else - { - int j; - - for(j=0;j<8;j++) - { - clone_d[j] = srcdata[7-j]; - } - } - - fprintf(fv, "r%.16g %s\n", d, fstVcdID(idx+1)); - } - } - } - } - } + if(xc->process_mask[process_idx]&(1<signal_lens[idx] <= 1) + { + if(xc->signal_lens[idx] == 1) + { + unsigned char val = mu[sig_offs]; + if(value_change_callback) + { + xc->temp_signal_value_buf[0] = val; + xc->temp_signal_value_buf[1] = 0; + value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) + { + char vcd_id[16]; - sig_offs += xc->signal_lens[idx]; - } + int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); + vcd_id[0] = val; /* collapse 3 writes into one I/O call */ + vcd_id[vcdid_len + 1] = '\n'; + fstWritex(xc, vcd_id, vcdid_len + 2); + } + } + } + else + { + /* variable-length ("0" length) records have no initial state */ + } + } + else + { + if(xc->signal_typs[idx] != FST_VT_VCD_REAL) + { + if(value_change_callback) + { + memcpy(xc->temp_signal_value_buf, mu+sig_offs, xc->signal_lens[idx]); + xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0; + value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) + { + char vcd_id[16]; + int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); - free(mu); - fstReaderFseeko(xc, xc->f, -((off_t)frame_clen), SEEK_CUR); - } - } + vcd_id[0] = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; + fstWritex(xc, vcd_id, 1); + fstWritex(xc,mu+sig_offs, xc->signal_lens[idx]); - fstReaderFseeko(xc, xc->f, (off_t)frame_clen, SEEK_CUR); /* skip past compressed data */ + vcd_id[0] = ' '; /* collapse 3 writes into one I/O call */ + vcd_id[vcdid_len + 1] = '\n'; + fstWritex(xc, vcd_id, vcdid_len + 2); + } + } + } + else + { + double d; + unsigned char *clone_d; + unsigned char *srcdata = mu+sig_offs; - vc_maxhandle = fstReaderVarint64(xc->f); - vc_start = ftello(xc->f); /* points to '!' character */ - packtype = fgetc(xc->f); + if(value_change_callback) + { + if(xc->native_doubles_for_cb) + { + if(xc->double_endian_match) + { + clone_d = srcdata; + } + else + { + int j; + + clone_d = (unsigned char *)&d; + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + value_change_callback(user_callback_data_pointer, beg_tim, idx+1, clone_d); + } + else + { + clone_d = (unsigned char *)&d; + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); + value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); + } + } + else + { + if(fv) + { + char vcdid_buf[16]; + char wx_buf[64]; + int wx_len; + + clone_d = (unsigned char *)&d; + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + + fstVcdID(vcdid_buf, idx+1); + wx_len = sprintf(wx_buf, "r%.16g %s\n", d, vcdid_buf); + fstWritex(xc, wx_buf, wx_len); + } + } + } + } + } + + sig_offs += xc->signal_lens[idx]; + } + + free(mu); + fstReaderFseeko(xc, xc->f, -((off_t)frame_clen), SEEK_CUR); + } + } + + fstReaderFseeko(xc, xc->f, (off_t)frame_clen, SEEK_CUR); /* skip past compressed data */ + + vc_maxhandle = fstReaderVarint64(xc->f); + vc_start = ftello(xc->f); /* points to '!' character */ + packtype = fgetc(xc->f); #ifdef FST_DEBUG - printf("\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", - (int)frame_uclen, (int)frame_clen, (int)frame_maxhandle); - printf("\tvc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype); + fprintf(stderr, "\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", + (int)frame_uclen, (int)frame_clen, (int)frame_maxhandle); + fprintf(stderr, "\tvc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype); #endif - indx_pntr = blkpos + seclen - 24 -tsec_clen -8; - fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET); - chain_clen = fstReaderUint64(xc->f); - indx_pos = indx_pntr - chain_clen; + indx_pntr = blkpos + seclen - 24 -tsec_clen -8; + fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET); + chain_clen = fstReaderUint64(xc->f); + indx_pos = indx_pntr - chain_clen; #ifdef FST_DEBUG - printf("\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); + fprintf(stderr, "\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); #endif - chain_cmem = malloc(chain_clen); - if(!chain_cmem) goto block_err; - fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); - fstFread(chain_cmem, chain_clen, 1, xc->f); - - if(vc_maxhandle > vc_maxhandle_largest) - { - free(chain_table); - free(chain_table_lengths); + chain_cmem = malloc(chain_clen); + if(!chain_cmem) goto block_err; + fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); + fstFread(chain_cmem, chain_clen, 1, xc->f); - vc_maxhandle_largest = vc_maxhandle; - chain_table = calloc((vc_maxhandle+1), sizeof(off_t)); - chain_table_lengths = calloc((vc_maxhandle+1), sizeof(uint32_t)); - } + if(vc_maxhandle > vc_maxhandle_largest) + { + free(chain_table); + free(chain_table_lengths); - if(!chain_table || !chain_table_lengths) goto block_err; + vc_maxhandle_largest = vc_maxhandle; + chain_table = calloc((vc_maxhandle+1), sizeof(off_t)); + chain_table_lengths = calloc((vc_maxhandle+1), sizeof(uint32_t)); + } - pnt = chain_cmem; - idx = 0; - pval = 0; + if(!chain_table || !chain_table_lengths) goto block_err; - do - { - int skiplen; - uint64_t val = fstGetVarint32(pnt, &skiplen); - - if(!val) - { - pnt += skiplen; - val = fstGetVarint32(pnt, &skiplen); - chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ - chain_table_lengths[idx] = -val; /* because during this loop iter would give stale data! */ - idx++; - } - else - if(val&1) - { - pval = chain_table[idx] = pval + (val >> 1); - if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; } - pidx = idx++; - } - else - { - int loopcnt = val >> 1; - for(i=0;i> 1; + if(shval > 0) + { + pval = chain_table[idx] = pval + shval; + if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; } + pidx = idx++; + } + else if(shval < 0) + { + chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ + chain_table_lengths[idx] = prev_alias = shval; /* because during this loop iter would give stale data! */ + idx++; + } + else + { + chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ + chain_table_lengths[idx] = prev_alias; /* because during this loop iter would give stale data! */ + idx++; + } + } + else + { + uint64_t val = fstGetVarint32(pnt, &skiplen); + + fstHandle loopcnt = val >> 1; + for(i=0;i> 1); + if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; } + pidx = idx++; + } + else + { + fstHandle loopcnt = val >> 1; + for(i=0;i xc->maxhandle) idx = xc->maxhandle; - for(i=0;iprocess_mask[process_idx]&(1<f, vc_start + chain_table[i], SEEK_SET); - val = fstReaderVarint32WithSkip(xc->f, &skiplen); - if(val) - { - unsigned char *mu = mem_for_traversal + traversal_mem_offs; - unsigned char *mc = malloc(chain_table_lengths[i]); - unsigned long destlen = val; - unsigned long sourcelen = chain_table_lengths[i]; - - fstFread(mc, chain_table_lengths[i], 1, xc->f); - if(packtype == 'F') - { - rc = fastlz_decompress(mc, sourcelen, mu, destlen); - } - else - { - rc = uncompress(mu, &destlen, mc, sourcelen); - } - free(mc); - /* data to process is for(j=0;jf); - /* data to process is for(j=0;jsignal_lens[i] == 1) - { - uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]); - uint32_t shcnt = 2 << (vli & 1); - tdelta = vli >> shcnt; - } - else - { - uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]); - tdelta = vli >> 1; - } - - scatterptr[i] = tc_head[tdelta]; - tc_head[tdelta] = i+1; - } - } - } + mc_mem_len = 16384; + mc_mem = malloc(mc_mem_len); /* buffer for compressed reads */ - for(i=0;i xc->maxhandle) idx = xc->maxhandle; + for(i=0;ilimit_range_valid) - { - if(time_table[i] > xc->limit_range_end) - { - break; - } - } + if(xc->process_mask[process_idx]&(1<num_blackouts)&&(cur_blackout != xc->num_blackouts)) - { - if(time_table[i] == xc->blackout_times[cur_blackout]) - { - fprintf(fv, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); - } - } - previous_time = time_table[i]; - } - } - - while(tc_head[i]) - { - idx = tc_head[i] - 1; - vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); + fstReaderFseeko(xc, xc->f, vc_start + chain_table[i], SEEK_SET); + val = fstReaderVarint32WithSkip(xc->f, &skiplen); + if(val) + { + unsigned char *mu = mem_for_traversal + traversal_mem_offs; /* uncomp: dst */ + unsigned char *mc; /* comp: src */ + unsigned long destlen = val; + unsigned long sourcelen = chain_table_lengths[i]; - if(xc->signal_lens[idx] <= 1) - { - if(xc->signal_lens[idx] == 1) - { - unsigned char val; - if(!(vli & 1)) - { - /* tdelta = vli >> 2; */ /* scan-build */ - val = ((vli >> 1) & 1) | '0'; - } - else - { - /* tdelta = vli >> 4; */ /* scan-build */ - val = FST_RCV_STR[((vli >> 1) & 7)]; - } + if(mc_mem_len < chain_table_lengths[i]) + { + free(mc_mem); + mc_mem = malloc(mc_mem_len = chain_table_lengths[i]); + } + mc = mc_mem; - if(value_change_callback) - { - xc->temp_signal_value_buf[0] = val; - xc->temp_signal_value_buf[1] = 0; - value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); - } - else - { - if(fv) - { - int vcdid_len; - const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len); - fputc(val, fv); - fstFwrite(vcd_id, vcdid_len, 1, fv); - fputc('\n', fv); - } - } - headptr[idx] += skiplen; - length_remaining[idx] -= skiplen; - - tc_head[i] = scatterptr[idx]; - scatterptr[idx] = 0; - - if(length_remaining[idx]) - { - int shamt; - vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); - shamt = 2 << (vli & 1); - tdelta = vli >> shamt; - - scatterptr[idx] = tc_head[i+tdelta]; - tc_head[i+tdelta] = idx+1; - } - } - else - { - unsigned char *vdata; - uint32_t len; + fstFread(mc, chain_table_lengths[i], 1, xc->f); - vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); - len = fstGetVarint32(mem_for_traversal + headptr[idx] + skiplen, &skiplen2); - /* tdelta = vli >> 1; */ /* scan-build */ - skiplen += skiplen2; - vdata = mem_for_traversal + headptr[idx] + skiplen; + switch(packtype) + { + case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR; + break; + case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */ + break; + default: rc = uncompress(mu, &destlen, mc, sourcelen); + break; + } - if(!(vli & 1)) - { - if(value_change_callback_varlen) - { - value_change_callback_varlen(user_callback_data_pointer, time_table[i], idx+1, vdata, len); - } - else - { - if(fv) - { - int vcdid_len; - const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len); - - fputc('s', fv); - { - unsigned char *vesc = malloc(len*4 + 1); - int vlen = fstUtilityBinToEsc(vesc, vdata, len); + /* data to process is for(j=0;jf); + /* data to process is for(j=0;jsignal_lens[i] == 1) + { + uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]); + uint32_t shcnt = 2 << (vli & 1); + tdelta = vli >> shcnt; + } + else + { + uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]); + tdelta = vli >> 1; + } - tc_head[i] = scatterptr[idx]; - scatterptr[idx] = 0; - - if(length_remaining[idx]) - { - vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); - tdelta = vli >> 1; - - scatterptr[idx] = tc_head[i+tdelta]; - tc_head[i+tdelta] = idx+1; - } - } - } - else - { - uint32_t len = xc->signal_lens[idx]; - unsigned char *vdata; + scatterptr[i] = tc_head[tdelta]; + tc_head[tdelta] = i+1; + } + } + } - vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); - /* tdelta = vli >> 1; */ /* scan-build */ - vdata = mem_for_traversal + headptr[idx] + skiplen; + free(mc_mem); /* there is no usage below for this, no real need to clear out mc_mem or mc_mem_len */ - if(xc->signal_typs[idx] != FST_VT_VCD_REAL) - { - if(!(vli & 1)) - { - int byte = 0; - int bit; - int j; + for(i=0;i> bit) & 1) | '0'; - xc->temp_signal_value_buf[j] = ch; - } - xc->temp_signal_value_buf[j] = 0; + if(fv) + { + char wx_buf[32]; + int wx_len; - if(value_change_callback) - { - value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); - } - else - { - if(fv) { - fputc((xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p', fv); - fstFwrite(xc->temp_signal_value_buf, len, 1, fv); - } - } + if(time_table[i] != previous_time) + { + if(xc->limit_range_valid) + { + if(time_table[i] > xc->limit_range_end) + { + break; + } + } - len = byte+1; - } - else - { - if(value_change_callback) - { - memcpy(xc->temp_signal_value_buf, vdata, len); - xc->temp_signal_value_buf[len] = 0; - value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); - } - else - { - if(fv) - { - fputc((xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p', fv); - fstFwrite(vdata, len, 1, fv); - } - } - } - } - else - { - double d; - unsigned char *clone_d /*= (unsigned char *)&d */; /* scan-build */ - unsigned char buf[8]; - unsigned char *srcdata; + wx_len = sprintf(wx_buf, "#%"PRIu64"\n", time_table[i]); + fstWritex(xc, wx_buf, wx_len); - if(!(vli & 1)) /* very rare case, but possible */ - { - int bit; - int j; + if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts)) + { + if(time_table[i] == xc->blackout_times[cur_blackout]) + { + wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); + fstWritex(xc, wx_buf, wx_len); + } + } + previous_time = time_table[i]; + } + } - for(j=0;j<8;j++) - { - unsigned char ch; - bit = 7 - (j & 7); - ch = ((vdata[0] >> bit) & 1) | '0'; - buf[j] = ch; - } - - len = 1; - srcdata = buf; - } - else - { - srcdata = vdata; - } + while(tc_head[i]) + { + idx = tc_head[i] - 1; + vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); - if(value_change_callback) - { - if(xc->native_doubles_for_cb) - { - if(xc->double_endian_match) - { - clone_d = srcdata; - } - else - { - int j; - - clone_d = (unsigned char *)&d; - for(j=0;j<8;j++) - { - clone_d[j] = srcdata[7-j]; - } - } - value_change_callback(user_callback_data_pointer, time_table[i], idx+1, clone_d); - } - else - { - clone_d = (unsigned char *)&d; - if(xc->double_endian_match) - { - memcpy(clone_d, srcdata, 8); - } - else - { - int j; - - for(j=0;j<8;j++) - { - clone_d[j] = srcdata[7-j]; - } - } - sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); - value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); - } - } - else - { - if(fv) - { - clone_d = (unsigned char *)&d; - if(xc->double_endian_match) - { - memcpy(clone_d, srcdata, 8); - } - else - { - int j; - - for(j=0;j<8;j++) - { - clone_d[j] = srcdata[7-j]; - } - } - - fprintf(fv, "r%.16g", d); - } - } - } + if(xc->signal_lens[idx] <= 1) + { + if(xc->signal_lens[idx] == 1) + { + unsigned char val; + if(!(vli & 1)) + { + /* tdelta = vli >> 2; */ /* scan-build */ + val = ((vli >> 1) & 1) | '0'; + } + else + { + /* tdelta = vli >> 4; */ /* scan-build */ + val = FST_RCV_STR[((vli >> 1) & 7)]; + } - if(fv) - { - int vcdid_len; - const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len); - fputc(' ', fv); - fstFwrite(vcd_id, vcdid_len, 1, fv); - fputc('\n', fv); - } + if(value_change_callback) + { + xc->temp_signal_value_buf[0] = val; + xc->temp_signal_value_buf[1] = 0; + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) + { + char vcd_id[16]; + int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); - skiplen += len; - headptr[idx] += skiplen; - length_remaining[idx] -= skiplen; + vcd_id[0] = val; + vcd_id[vcdid_len+1] = '\n'; + fstWritex(xc, vcd_id, vcdid_len+2); + } + } + headptr[idx] += skiplen; + length_remaining[idx] -= skiplen; - tc_head[i] = scatterptr[idx]; - scatterptr[idx] = 0; - - if(length_remaining[idx]) - { - vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); - tdelta = vli >> 1; + tc_head[i] = scatterptr[idx]; + scatterptr[idx] = 0; - scatterptr[idx] = tc_head[i+tdelta]; - tc_head[i+tdelta] = idx+1; - } - } - } - } + if(length_remaining[idx]) + { + int shamt; + vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); + shamt = 2 << (vli & 1); + tdelta = vli >> shamt; + + scatterptr[idx] = tc_head[i+tdelta]; + tc_head[i+tdelta] = idx+1; + } + } + else + { + unsigned char *vdata; + uint32_t len; + + vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); + len = fstGetVarint32(mem_for_traversal + headptr[idx] + skiplen, &skiplen2); + /* tdelta = vli >> 1; */ /* scan-build */ + skiplen += skiplen2; + vdata = mem_for_traversal + headptr[idx] + skiplen; + + if(!(vli & 1)) + { + if(value_change_callback_varlen) + { + value_change_callback_varlen(user_callback_data_pointer, time_table[i], idx+1, vdata, len); + } + else + { + if(fv) + { + char vcd_id[16]; + int vcdid_len; + + vcd_id[0] = 's'; + fstWritex(xc, vcd_id, 1); + + vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); + { + unsigned char *vesc = malloc(len*4 + 1); + int vlen = fstUtilityBinToEsc(vesc, vdata, len); + fstWritex(xc, vesc, vlen); + free(vesc); + } + + vcd_id[0] = ' '; + vcd_id[vcdid_len + 1] = '\n'; + fstWritex(xc, vcd_id, vcdid_len+2); + } + } + } + + skiplen += len; + headptr[idx] += skiplen; + length_remaining[idx] -= skiplen; + + tc_head[i] = scatterptr[idx]; + scatterptr[idx] = 0; + + if(length_remaining[idx]) + { + vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); + tdelta = vli >> 1; + + scatterptr[idx] = tc_head[i+tdelta]; + tc_head[i+tdelta] = idx+1; + } + } + } + else + { + uint32_t len = xc->signal_lens[idx]; + unsigned char *vdata; + + vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); + /* tdelta = vli >> 1; */ /* scan-build */ + vdata = mem_for_traversal + headptr[idx] + skiplen; + + if(xc->signal_typs[idx] != FST_VT_VCD_REAL) + { + if(!(vli & 1)) + { + int byte = 0; + int bit; + unsigned int j; + + for(j=0;j> bit) & 1) | '0'; + xc->temp_signal_value_buf[j] = ch; + } + xc->temp_signal_value_buf[j] = 0; + + if(value_change_callback) + { + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) { + unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; + + fstWritex(xc, &ch_bp, 1); + fstWritex(xc, xc->temp_signal_value_buf, len); + } + } + + len = byte+1; + } + else + { + if(value_change_callback) + { + memcpy(xc->temp_signal_value_buf, vdata, len); + xc->temp_signal_value_buf[len] = 0; + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) + { + unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; + + fstWritex(xc, &ch_bp, 1); + fstWritex(xc, vdata, len); + } + } + } + } + else + { + double d; + unsigned char *clone_d /*= (unsigned char *)&d */; /* scan-build */ + unsigned char buf[8]; + unsigned char *srcdata; + + if(!(vli & 1)) /* very rare case, but possible */ + { + int bit; + int j; + + for(j=0;j<8;j++) + { + unsigned char ch; + bit = 7 - (j & 7); + ch = ((vdata[0] >> bit) & 1) | '0'; + buf[j] = ch; + } + + len = 1; + srcdata = buf; + } + else + { + srcdata = vdata; + } + + if(value_change_callback) + { + if(xc->native_doubles_for_cb) + { + if(xc->double_endian_match) + { + clone_d = srcdata; + } + else + { + int j; + + clone_d = (unsigned char *)&d; + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, clone_d); + } + else + { + clone_d = (unsigned char *)&d; + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); + } + } + else + { + if(fv) + { + char wx_buf[32]; + int wx_len; + + clone_d = (unsigned char *)&d; + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + + wx_len = sprintf(wx_buf, "r%.16g", d); + fstWritex(xc, wx_buf, wx_len); + } + } + } + + if(fv) + { + char vcd_id[16]; + int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); + vcd_id[0] = ' '; + vcd_id[vcdid_len+1] = '\n'; + fstWritex(xc, vcd_id, vcdid_len+2); + } + + skiplen += len; + headptr[idx] += skiplen; + length_remaining[idx] -= skiplen; + + tc_head[i] = scatterptr[idx]; + scatterptr[idx] = 0; + + if(length_remaining[idx]) + { + vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); + tdelta = vli >> 1; + + scatterptr[idx] = tc_head[i+tdelta]; + tc_head[i+tdelta] = idx+1; + } + } + } + } block_err: - free(tc_head); - free(chain_cmem); - free(mem_for_traversal); + free(tc_head); + free(chain_cmem); + free(mem_for_traversal); mem_for_traversal = NULL; - secnum++; - if(secnum == xc->vc_section_count) break; /* in case file is growing, keep with original block count */ - blkpos += seclen; - } + secnum++; + if(secnum == xc->vc_section_count) break; /* in case file is growing, keep with original block count */ + blkpos += seclen; + } +if(mem_for_traversal) free(mem_for_traversal); /* scan-build */ free(length_remaining); free(headptr); free(scatterptr); -if(chain_table) - { - free(chain_table); - free(chain_table_lengths); - } +if(chain_table) free(chain_table); +if(chain_table_lengths) free(chain_table_lengths); free(time_table); +#ifndef FST_WRITEX_DISABLE +if(fv) + { + fstWritex(xc, NULL, 0); + } +#endif + return(1); } @@ -5060,45 +5629,45 @@ return(1); static char *fstExtractRvatDataFromFrame(struct fstReaderContext *xc, fstHandle facidx, char *buf) { if(facidx >= xc->rvat_frame_maxhandle) - { - return(NULL); - } + { + return(NULL); + } if(xc->signal_lens[facidx] == 1) - { - buf[0] = (char)xc->rvat_frame_data[xc->rvat_sig_offs[facidx]]; - buf[1] = 0; - } - else - { - if(xc->signal_typs[facidx] != FST_VT_VCD_REAL) - { - memcpy(buf, xc->rvat_frame_data + xc->rvat_sig_offs[facidx], xc->signal_lens[facidx]); - buf[xc->signal_lens[facidx]] = 0; - } - else - { - double d; - unsigned char *clone_d = (unsigned char *)&d; - unsigned char *srcdata = xc->rvat_frame_data + xc->rvat_sig_offs[facidx]; + { + buf[0] = (char)xc->rvat_frame_data[xc->rvat_sig_offs[facidx]]; + buf[1] = 0; + } + else + { + if(xc->signal_typs[facidx] != FST_VT_VCD_REAL) + { + memcpy(buf, xc->rvat_frame_data + xc->rvat_sig_offs[facidx], xc->signal_lens[facidx]); + buf[xc->signal_lens[facidx]] = 0; + } + else + { + double d; + unsigned char *clone_d = (unsigned char *)&d; + unsigned char *srcdata = xc->rvat_frame_data + xc->rvat_sig_offs[facidx]; - if(xc->double_endian_match) - { - memcpy(clone_d, srcdata, 8); - } - else - { - int j; + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; - for(j=0;j<8;j++) - { - clone_d[j] = srcdata[7-j]; - } - } - - sprintf((char *)buf, "%.16g", d); - } - } + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + + sprintf((char *)buf, "%.16g", d); + } + } return(buf); } @@ -5110,7 +5679,7 @@ struct fstReaderContext *xc = (struct fstReaderContext *)ctx; off_t blkpos = 0, prev_blkpos; uint64_t beg_tim, end_tim, beg_tim2, end_tim2; int sectype; -int secnum = 0; +unsigned int secnum = 0; uint64_t seclen; uint64_t tsec_uclen = 0, tsec_clen = 0; uint64_t tsec_nitems; @@ -5126,97 +5695,97 @@ fstHandle idx, pidx=0, i; uint64_t pval; if((!xc) || (!facidx) || (facidx > xc->maxhandle) || (!buf) || (!xc->signal_lens[facidx-1])) - { - return(NULL); - } + { + return(NULL); + } if(!xc->rvat_sig_offs) - { - uint32_t cur_offs = 0; + { + uint32_t cur_offs = 0; - xc->rvat_sig_offs = calloc(xc->maxhandle, sizeof(uint32_t)); - for(i=0;imaxhandle;i++) - { - xc->rvat_sig_offs[i] = cur_offs; - cur_offs += xc->signal_lens[i]; - } - } + xc->rvat_sig_offs = calloc(xc->maxhandle, sizeof(uint32_t)); + for(i=0;imaxhandle;i++) + { + xc->rvat_sig_offs[i] = cur_offs; + cur_offs += xc->signal_lens[i]; + } + } if(xc->rvat_data_valid) - { - if((xc->rvat_beg_tim <= tim) && (tim <= xc->rvat_end_tim)) - { - goto process_value; - } + { + if((xc->rvat_beg_tim <= tim) && (tim <= xc->rvat_end_tim)) + { + goto process_value; + } - fstReaderDeallocateRvatData(xc); - } + fstReaderDeallocateRvatData(xc); + } xc->rvat_chain_pos_valid = 0; for(;;) - { - fstReaderFseeko(xc, xc->f, (prev_blkpos = blkpos), SEEK_SET); + { + fstReaderFseeko(xc, xc->f, (prev_blkpos = blkpos), SEEK_SET); - sectype = fgetc(xc->f); - seclen = fstReaderUint64(xc->f); + sectype = fgetc(xc->f); + seclen = fstReaderUint64(xc->f); - if((sectype == EOF) || (sectype == FST_BL_SKIP) || (!seclen)) - { - return(NULL); /* if this loop exits on break, it's successful */ - } + if((sectype == EOF) || (sectype == FST_BL_SKIP) || (!seclen)) + { + return(NULL); /* if this loop exits on break, it's successful */ + } - blkpos++; - if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS)) - { - blkpos += seclen; - continue; - } + blkpos++; + if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2)) + { + blkpos += seclen; + continue; + } - beg_tim = fstReaderUint64(xc->f); - end_tim = fstReaderUint64(xc->f); + beg_tim = fstReaderUint64(xc->f); + end_tim = fstReaderUint64(xc->f); - if((beg_tim <= tim) && (tim <= end_tim)) - { - if((tim == end_tim) && (tim != xc->end_time)) - { - off_t cached_pos = ftello(xc->f); - fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); + if((beg_tim <= tim) && (tim <= end_tim)) + { + if((tim == end_tim) && (tim != xc->end_time)) + { + off_t cached_pos = ftello(xc->f); + fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); - sectype = fgetc(xc->f); - seclen = fstReaderUint64(xc->f); + sectype = fgetc(xc->f); + seclen = fstReaderUint64(xc->f); - beg_tim2 = fstReaderUint64(xc->f); - end_tim2 = fstReaderUint64(xc->f); + beg_tim2 = fstReaderUint64(xc->f); + end_tim2 = fstReaderUint64(xc->f); - if(((sectype != FST_BL_VCDATA)&&(sectype != FST_BL_VCDATA_DYN_ALIAS)) || (!seclen) || (beg_tim2 != tim)) - { - blkpos = prev_blkpos; - break; - } - beg_tim = beg_tim2; - end_tim = end_tim2; - fstReaderFseeko(xc, xc->f, cached_pos, SEEK_SET); - } - break; - } + if(((sectype != FST_BL_VCDATA)&&(sectype != FST_BL_VCDATA_DYN_ALIAS)&&(sectype != FST_BL_VCDATA_DYN_ALIAS2)) || (!seclen) || (beg_tim2 != tim)) + { + blkpos = prev_blkpos; + break; + } + beg_tim = beg_tim2; + end_tim = end_tim2; + fstReaderFseeko(xc, xc->f, cached_pos, SEEK_SET); + } + break; + } - blkpos += seclen; - secnum++; - } + blkpos += seclen; + secnum++; + } xc->rvat_beg_tim = beg_tim; xc->rvat_end_tim = end_tim; #ifdef FST_DEBUG -mem_required_for_traversal = +mem_required_for_traversal = #endif - fstReaderUint64(xc->f); + fstReaderUint64(xc->f); #ifdef FST_DEBUG -printf("rvat sec: %d seclen: %d begtim: %d endtim: %d\n", - secnum, (int)seclen, (int)beg_tim, (int)end_tim); -printf("\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal); +fprintf(stderr, "rvat sec: %u seclen: %d begtim: %d endtim: %d\n", + secnum, (int)seclen, (int)beg_tim, (int)end_tim); +fprintf(stderr, "\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal); #endif /* process time block */ @@ -5228,51 +5797,51 @@ unsigned long sourcelen /* = tsec_clen */; /* scan-build */ int rc; unsigned char *tpnt; uint64_t tpval; -int ti; +unsigned int ti; fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET); tsec_uclen = fstReaderUint64(xc->f); tsec_clen = fstReaderUint64(xc->f); tsec_nitems = fstReaderUint64(xc->f); #ifdef FST_DEBUG -printf("\ttime section unc: %d, com: %d (%d items)\n", - (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems); -#endif +fprintf(stderr, "\ttime section unc: %d, com: %d (%d items)\n", + (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems); +#endif ucdata = malloc(tsec_uclen); destlen = tsec_uclen; sourcelen = tsec_clen; - + fstReaderFseeko(xc, xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); if(tsec_uclen != tsec_clen) - { - cdata = malloc(tsec_clen); - fstFread(cdata, tsec_clen, 1, xc->f); - - rc = uncompress(ucdata, &destlen, cdata, sourcelen); - - if(rc != Z_OK) - { - printf("tsec uncompress rc = %d\n", rc); - exit(255); - } - - free(cdata); - } - else - { - fstFread(ucdata, tsec_uclen, 1, xc->f); - } + { + cdata = malloc(tsec_clen); + fstFread(cdata, tsec_clen, 1, xc->f); + + rc = uncompress(ucdata, &destlen, cdata, sourcelen); + + if(rc != Z_OK) + { + printf("tsec uncompress rc = %d\n", rc); + exit(255); + } + + free(cdata); + } + else + { + fstFread(ucdata, tsec_uclen, 1, xc->f); + } xc->rvat_time_table = calloc(tsec_nitems, sizeof(uint64_t)); tpnt = ucdata; tpval = 0; for(ti=0;tirvat_time_table[ti] = tpval + val; - tpnt += skiplen; - } + { + int skiplen; + uint64_t val = fstGetVarint64(tpnt, &skiplen); + tpval = xc->rvat_time_table[ti] = tpval + val; + tpnt += skiplen; + } free(ucdata); } @@ -5285,34 +5854,34 @@ xc->rvat_frame_maxhandle = fstReaderVarint64(xc->f); xc->rvat_frame_data = malloc(frame_uclen); if(frame_uclen == frame_clen) - { - fstFread(xc->rvat_frame_data, frame_uclen, 1, xc->f); - } - else - { - unsigned char *mc = malloc(frame_clen); - int rc; + { + fstFread(xc->rvat_frame_data, frame_uclen, 1, xc->f); + } + else + { + unsigned char *mc = malloc(frame_clen); + int rc; - unsigned long destlen = frame_uclen; - unsigned long sourcelen = frame_clen; + unsigned long destlen = frame_uclen; + unsigned long sourcelen = frame_clen; - fstFread(mc, sourcelen, 1, xc->f); - rc = uncompress(xc->rvat_frame_data, &destlen, mc, sourcelen); - if(rc != Z_OK) - { - printf("decompress rc: %d\n", rc); - exit(255); - } - free(mc); - } + fstFread(mc, sourcelen, 1, xc->f); + rc = uncompress(xc->rvat_frame_data, &destlen, mc, sourcelen); + if(rc != Z_OK) + { + printf("decompress rc: %d\n", rc); + exit(255); + } + free(mc); + } xc->rvat_vc_maxhandle = fstReaderVarint64(xc->f); -xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */ +xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */ #ifdef FST_DEBUG -printf("\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", - (int)frame_uclen, (int)frame_clen, (int)xc->rvat_frame_maxhandle); -printf("\tvc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle); +fprintf(stderr, "\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", + (int)frame_uclen, (int)frame_clen, (int)xc->rvat_frame_maxhandle); +fprintf(stderr, "\tvc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle); #endif indx_pntr = blkpos + seclen - 24 -tsec_clen -8; @@ -5320,12 +5889,12 @@ fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET); chain_clen = fstReaderUint64(xc->f); indx_pos = indx_pntr - chain_clen; #ifdef FST_DEBUG -printf("\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); +fprintf(stderr, "\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); #endif chain_cmem = malloc(chain_clen); fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); fstFread(chain_cmem, chain_clen, 1, xc->f); - + xc->rvat_chain_table = calloc((xc->rvat_vc_maxhandle+1), sizeof(off_t)); xc->rvat_chain_table_lengths = calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t)); @@ -5333,125 +5902,125 @@ pnt = chain_cmem; idx = 0; pval = 0; do - { - int skiplen; - uint64_t val = fstGetVarint32(pnt, &skiplen); + { + int skiplen; + uint64_t val = fstGetVarint32(pnt, &skiplen); if(!val) - { - pnt += skiplen; - val = fstGetVarint32(pnt, &skiplen); - xc->rvat_chain_table[idx] = 0; + { + pnt += skiplen; + val = fstGetVarint32(pnt, &skiplen); + xc->rvat_chain_table[idx] = 0; xc->rvat_chain_table_lengths[idx] = -val; idx++; } - else - if(val&1) - { - pval = xc->rvat_chain_table[idx] = pval + (val >> 1); - if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; } - pidx = idx++; - } - else - { - int loopcnt = val >> 1; - for(i=0;irvat_chain_table[idx++] = 0; - } - } - - pnt += skiplen; - } while (pnt != (chain_cmem + chain_clen)); + else + if(val&1) + { + pval = xc->rvat_chain_table[idx] = pval + (val >> 1); + if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; } + pidx = idx++; + } + else + { + fstHandle loopcnt = val >> 1; + for(i=0;irvat_chain_table[idx++] = 0; + } + } -free(chain_cmem); + pnt += skiplen; + } while (pnt != (chain_cmem + chain_clen)); + +free(chain_cmem); xc->rvat_chain_table[idx] = indx_pos - xc->rvat_vc_start; xc->rvat_chain_table_lengths[pidx] = xc->rvat_chain_table[idx] - xc->rvat_chain_table[pidx]; for(i=0;irvat_chain_table_lengths[i]; - if((v32 < 0) && (!xc->rvat_chain_table[i])) - { + if((v32 < 0) && (!xc->rvat_chain_table[i])) + { v32 = -v32; - v32--; - if(((uint32_t)v32) < i) /* sanity check */ - { - xc->rvat_chain_table[i] = xc->rvat_chain_table[v32]; - xc->rvat_chain_table_lengths[i] = xc->rvat_chain_table_lengths[v32]; - } + v32--; + if(((uint32_t)v32) < i) /* sanity check */ + { + xc->rvat_chain_table[i] = xc->rvat_chain_table[v32]; + xc->rvat_chain_table_lengths[i] = xc->rvat_chain_table_lengths[v32]; + } } - } + } #ifdef FST_DEBUG -printf("\tdecompressed chain idx len: %"PRIu32"\n", idx); +fprintf(stderr, "\tdecompressed chain idx len: %"PRIu32"\n", idx); #endif xc->rvat_data_valid = 1; -/* all data at this point is loaded or resident in fst cache, process and return appropriate value */ +/* all data at this point is loaded or resident in fst cache, process and return appropriate value */ process_value: if(facidx > xc->rvat_vc_maxhandle) - { - return(NULL); - } + { + return(NULL); + } facidx--; /* scale down for array which starts at zero */ if(((tim == xc->rvat_beg_tim)&&(!xc->rvat_chain_table[facidx])) || (!xc->rvat_chain_table[facidx])) - { - return(fstExtractRvatDataFromFrame(xc, facidx, buf)); - } + { + return(fstExtractRvatDataFromFrame(xc, facidx, buf)); + } if(facidx != xc->rvat_chain_facidx) - { - if(xc->rvat_chain_mem) - { - free(xc->rvat_chain_mem); - xc->rvat_chain_mem = NULL; + { + if(xc->rvat_chain_mem) + { + free(xc->rvat_chain_mem); + xc->rvat_chain_mem = NULL; - xc->rvat_chain_pos_valid = 0; - } - } + xc->rvat_chain_pos_valid = 0; + } + } if(!xc->rvat_chain_mem) - { - uint32_t skiplen; - fstReaderFseeko(xc, xc->f, xc->rvat_vc_start + xc->rvat_chain_table[facidx], SEEK_SET); - xc->rvat_chain_len = fstReaderVarint32WithSkip(xc->f, &skiplen); - if(xc->rvat_chain_len) - { - unsigned char *mu = malloc(xc->rvat_chain_len); - unsigned char *mc = malloc(xc->rvat_chain_table_lengths[facidx]); - unsigned long destlen = xc->rvat_chain_len; - unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx]; - int rc; - - fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f); - rc = uncompress(mu, &destlen, mc, sourcelen); - free(mc); - - if(rc != Z_OK) - { - printf("\tclen: %d (rc=%d)\n", (int)xc->rvat_chain_len, rc); - exit(255); - } - - /* data to process is for(j=0;jrvat_chain_mem = mu; - } - else - { - int destlen = xc->rvat_chain_table_lengths[facidx] - skiplen; - unsigned char *mu = malloc(xc->rvat_chain_len = destlen); - fstFread(mu, destlen, 1, xc->f); - /* data to process is for(j=0;jrvat_chain_mem = mu; - } + { + uint32_t skiplen; + fstReaderFseeko(xc, xc->f, xc->rvat_vc_start + xc->rvat_chain_table[facidx], SEEK_SET); + xc->rvat_chain_len = fstReaderVarint32WithSkip(xc->f, &skiplen); + if(xc->rvat_chain_len) + { + unsigned char *mu = malloc(xc->rvat_chain_len); + unsigned char *mc = malloc(xc->rvat_chain_table_lengths[facidx]); + unsigned long destlen = xc->rvat_chain_len; + unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx]; + int rc; - xc->rvat_chain_facidx = facidx; - } + fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f); + rc = uncompress(mu, &destlen, mc, sourcelen); + free(mc); + + if(rc != Z_OK) + { + printf("\tclen: %d (rc=%d)\n", (int)xc->rvat_chain_len, rc); + exit(255); + } + + /* data to process is for(j=0;jrvat_chain_mem = mu; + } + else + { + int destlen = xc->rvat_chain_table_lengths[facidx] - skiplen; + unsigned char *mu = malloc(xc->rvat_chain_len = destlen); + fstFread(mu, destlen, 1, xc->f); + /* data to process is for(j=0;jrvat_chain_mem = mu; + } + + xc->rvat_chain_facidx = facidx; + } /* process value chain here */ @@ -5459,186 +6028,186 @@ if(!xc->rvat_chain_mem) uint32_t tidx = 0, ptidx = 0; uint32_t tdelta; int skiplen; -int iprev = xc->rvat_chain_len; +unsigned int iprev = xc->rvat_chain_len; uint32_t pvli = 0; int pskip = 0; if((xc->rvat_chain_pos_valid)&&(tim >= xc->rvat_chain_pos_time)) - { - i = xc->rvat_chain_pos_idx; - tidx = xc->rvat_chain_pos_tidx; - } - else - { - i = 0; - tidx = 0; - xc->rvat_chain_pos_time = xc->rvat_beg_tim; - } - -if(xc->signal_lens[facidx] == 1) - { - while(irvat_chain_len) - { - uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen); - uint32_t shcnt = 2 << (vli & 1); - tdelta = vli >> shcnt; - - if(xc->rvat_time_table[tidx + tdelta] <= tim) - { - iprev = i; - pvli = vli; - ptidx = tidx; - /* pskip = skiplen; */ /* scan-build */ - - tidx += tdelta; - i+=skiplen; - } - else - { - break; - } - } - if(iprev != xc->rvat_chain_len) - { - xc->rvat_chain_pos_tidx = ptidx; - xc->rvat_chain_pos_idx = iprev; - xc->rvat_chain_pos_time = tim; - xc->rvat_chain_pos_valid = 1; - - if(!(pvli & 1)) - { - buf[0] = ((pvli >> 1) & 1) | '0'; - } - else - { - buf[0] = FST_RCV_STR[((pvli >> 1) & 7)]; - } - buf[1] = 0; - return(buf); - } - else - { - return(fstExtractRvatDataFromFrame(xc, facidx, buf)); - } + { + i = xc->rvat_chain_pos_idx; + tidx = xc->rvat_chain_pos_tidx; } else { - while(irvat_chain_len) - { - uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen); - tdelta = vli >> 1; + i = 0; + tidx = 0; + xc->rvat_chain_pos_time = xc->rvat_beg_tim; + } - if(xc->rvat_time_table[tidx + tdelta] <= tim) - { - iprev = i; - pvli = vli; - ptidx = tidx; - pskip = skiplen; +if(xc->signal_lens[facidx] == 1) + { + while(irvat_chain_len) + { + uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen); + uint32_t shcnt = 2 << (vli & 1); + tdelta = vli >> shcnt; - tidx += tdelta; - i+=skiplen; + if(xc->rvat_time_table[tidx + tdelta] <= tim) + { + iprev = i; + pvli = vli; + ptidx = tidx; + /* pskip = skiplen; */ /* scan-build */ - if(!(pvli & 1)) - { - i+=((xc->signal_lens[facidx]+7)/8); - } - else - { - i+=xc->signal_lens[facidx]; - } - } - else - { - break; - } - } + tidx += tdelta; + i+=skiplen; + } + else + { + break; + } + } + if(iprev != xc->rvat_chain_len) + { + xc->rvat_chain_pos_tidx = ptidx; + xc->rvat_chain_pos_idx = iprev; + xc->rvat_chain_pos_time = tim; + xc->rvat_chain_pos_valid = 1; - if(iprev != xc->rvat_chain_len) - { - unsigned char *vdata = xc->rvat_chain_mem + iprev + pskip; + if(!(pvli & 1)) + { + buf[0] = ((pvli >> 1) & 1) | '0'; + } + else + { + buf[0] = FST_RCV_STR[((pvli >> 1) & 7)]; + } + buf[1] = 0; + return(buf); + } + else + { + return(fstExtractRvatDataFromFrame(xc, facidx, buf)); + } + } + else + { + while(irvat_chain_len) + { + uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen); + tdelta = vli >> 1; - xc->rvat_chain_pos_tidx = ptidx; - xc->rvat_chain_pos_idx = iprev; - xc->rvat_chain_pos_time = tim; - xc->rvat_chain_pos_valid = 1; + if(xc->rvat_time_table[tidx + tdelta] <= tim) + { + iprev = i; + pvli = vli; + ptidx = tidx; + pskip = skiplen; - if(xc->signal_typs[facidx] != FST_VT_VCD_REAL) - { - if(!(pvli & 1)) - { - int byte = 0; - int bit; - int j; + tidx += tdelta; + i+=skiplen; - for(j=0;jsignal_lens[facidx];j++) - { - unsigned char ch; - byte = j/8; - bit = 7 - (j & 7); - ch = ((vdata[byte] >> bit) & 1) | '0'; - buf[j] = ch; - } - buf[j] = 0; + if(!(pvli & 1)) + { + i+=((xc->signal_lens[facidx]+7)/8); + } + else + { + i+=xc->signal_lens[facidx]; + } + } + else + { + break; + } + } - return(buf); - } - else - { - memcpy(buf, vdata, xc->signal_lens[facidx]); - buf[xc->signal_lens[facidx]] = 0; - return(buf); - } - } - else - { - double d; - unsigned char *clone_d = (unsigned char *)&d; - unsigned char bufd[8]; - unsigned char *srcdata; + if(iprev != xc->rvat_chain_len) + { + unsigned char *vdata = xc->rvat_chain_mem + iprev + pskip; - if(!(pvli & 1)) /* very rare case, but possible */ - { - int bit; - int j; + xc->rvat_chain_pos_tidx = ptidx; + xc->rvat_chain_pos_idx = iprev; + xc->rvat_chain_pos_time = tim; + xc->rvat_chain_pos_valid = 1; - for(j=0;j<8;j++) - { - unsigned char ch; - bit = 7 - (j & 7); - ch = ((vdata[0] >> bit) & 1) | '0'; - bufd[j] = ch; - } - - srcdata = bufd; - } - else - { - srcdata = vdata; - } + if(xc->signal_typs[facidx] != FST_VT_VCD_REAL) + { + if(!(pvli & 1)) + { + int byte = 0; + int bit; + unsigned int j; - if(xc->double_endian_match) - { - memcpy(clone_d, srcdata, 8); - } - else - { - int j; + for(j=0;jsignal_lens[facidx];j++) + { + unsigned char ch; + byte = j/8; + bit = 7 - (j & 7); + ch = ((vdata[byte] >> bit) & 1) | '0'; + buf[j] = ch; + } + buf[j] = 0; - for(j=0;j<8;j++) - { - clone_d[j] = srcdata[7-j]; - } - } + return(buf); + } + else + { + memcpy(buf, vdata, xc->signal_lens[facidx]); + buf[xc->signal_lens[facidx]] = 0; + return(buf); + } + } + else + { + double d; + unsigned char *clone_d = (unsigned char *)&d; + unsigned char bufd[8]; + unsigned char *srcdata; - sprintf(buf, "r%.16g", d); - return(buf); - } - } - else - { - return(fstExtractRvatDataFromFrame(xc, facidx, buf)); - } - } + if(!(pvli & 1)) /* very rare case, but possible */ + { + int bit; + int j; + + for(j=0;j<8;j++) + { + unsigned char ch; + bit = 7 - (j & 7); + ch = ((vdata[0] >> bit) & 1) | '0'; + bufd[j] = ch; + } + + srcdata = bufd; + } + else + { + srcdata = vdata; + } + + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + + sprintf(buf, "r%.16g", d); + return(buf); + } + } + else + { + return(fstExtractRvatDataFromFrame(xc, facidx, buf)); + } + } } /* return(NULL); */ @@ -5647,7 +6216,6 @@ if(xc->signal_lens[facidx] == 1) /**********************************************************************/ -#ifndef FST_DYNAMIC_ALIAS_DISABLE #ifndef _WAVE_HAVE_JUDY /***********************/ @@ -5666,16 +6234,16 @@ For every delta with one or two bits set, and the deltas of all three have at least 1/4 probability of changing. * If mix() is run forward, every bit of c will change between 1/3 and 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) -mix() was built out of 36 single-cycle latency instructions in a +mix() was built out of 36 single-cycle latency instructions in a structure that could supported 2x parallelism, like so: - a -= b; + a -= b; a -= c; x = (c>>13); b -= c; a ^= x; b -= a; x = (a<<8); c -= a; b ^= x; c -= b; x = (b>>13); ... - Unfortunately, superscalar Pentiums and Sparcs can't take advantage + Unfortunately, superscalar Pentiums and Sparcs can't take advantage of that parallelism. They've also turned some of those single-cycle latency instructions into multi-cycle latency instructions. Still, this is the fastest good hash I could find. There were about 2^^68 @@ -5790,34 +6358,34 @@ struct collchain_t **ar; struct collchain_t *chain, *pchain; if(!*base) - { - *base = calloc(1, (hashmask + 1) * sizeof(void *)); - } + { + *base = calloc(1, (hashmask + 1) * sizeof(void *)); + } ar = *base; h = (hf = j_hash(mem, length, length)) & hashmask; pchain = chain = ar[h]; while(chain) - { - if((chain->fullhash == hf) && (chain->length == length) && !memcmp(chain->mem, mem, length)) - { - if(pchain != chain) /* move hit to front */ - { - pchain->next = chain->next; - chain->next = ar[h]; - ar[h] = chain; - } - return(&(chain->payload)); - } + { + if((chain->fullhash == hf) && (chain->length == length) && !memcmp(chain->mem, mem, length)) + { + if(pchain != chain) /* move hit to front */ + { + pchain->next = chain->next; + chain->next = ar[h]; + ar[h] = chain; + } + return(&(chain->payload)); + } - pchain = chain; - chain = chain->next; - } + pchain = chain; + chain = chain->next; + } chain = calloc(1, sizeof(struct collchain_t) + length - 1); memcpy(chain->mem, mem, length); -chain->fullhash = hf; -chain->length = length; +chain->fullhash = hf; +chain->length = length; chain->next = ar[h]; ar[h] = chain; return(&(chain->payload)); @@ -5832,25 +6400,24 @@ struct collchain_t **ar; struct collchain_t *chain, *chain_next; if(base && *base) - { - ar = *base; - for(h=0;h<=hashmask;h++) - { - chain = ar[h]; - while(chain) - { - chain_next = chain->next; - free(chain); - chain = chain_next; - } - } + { + ar = *base; + for(h=0;h<=hashmask;h++) + { + chain = ar[h]; + while(chain) + { + chain_next = chain->next; + free(chain); + chain = chain_next; + } + } - free(*base); - *base = NULL; - } + free(*base); + *base = NULL; + } } -#endif #endif /**********************************************************************/ @@ -5869,35 +6436,35 @@ unsigned char val; int i; for(i=0;i ' ') && (src[i] <= '~')) /* no white spaces in output */ - { - *(dst++) = src[i]; - } - else - { - val = src[i]; - *(dst++) = '\\'; - *(dst++) = (val/64) + '0'; val = val & 63; - *(dst++) = (val/8) + '0'; val = val & 7; - *(dst++) = (val) + '0'; - } - break; - } - } + { + switch(src[i]) + { + case '\a': *(dst++) = '\\'; *(dst++) = 'a'; break; + case '\b': *(dst++) = '\\'; *(dst++) = 'b'; break; + case '\f': *(dst++) = '\\'; *(dst++) = 'f'; break; + case '\n': *(dst++) = '\\'; *(dst++) = 'n'; break; + case '\r': *(dst++) = '\\'; *(dst++) = 'r'; break; + case '\t': *(dst++) = '\\'; *(dst++) = 't'; break; + case '\v': *(dst++) = '\\'; *(dst++) = 'v'; break; + case '\'': *(dst++) = '\\'; *(dst++) = '\''; break; + case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break; + case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break; + case '\?': *(dst++) = '\\'; *(dst++) = '\?'; break; + default: if((src[i] > ' ') && (src[i] <= '~')) /* no white spaces in output */ + { + *(dst++) = src[i]; + } + else + { + val = src[i]; + *(dst++) = '\\'; + *(dst++) = (val/64) + '0'; val = val & 63; + *(dst++) = (val/8) + '0'; val = val & 7; + *(dst++) = (val) + '0'; + } + break; + } + } return(dst - d); } @@ -5914,51 +6481,51 @@ unsigned char val[3]; int i; for(i=0;i='A')&&(val[0]<='F')) ? (val[0] - 'A' + 10) : (val[0] - '0'); - val[1] = ((val[1]>='A')&&(val[1]<='F')) ? (val[1] - 'A' + 10) : (val[1] - '0'); - *(dst++) = val[0] * 16 + val[1]; - break; + case 'x': val[0] = toupper(src[++i]); + val[1] = toupper(src[++i]); + val[0] = ((val[0]>='A')&&(val[0]<='F')) ? (val[0] - 'A' + 10) : (val[0] - '0'); + val[1] = ((val[1]>='A')&&(val[1]<='F')) ? (val[1] - 'A' + 10) : (val[1] - '0'); + *(dst++) = val[0] * 16 + val[1]; + break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': val[0] = src[ i] - '0'; - val[1] = src[++i] - '0'; - val[2] = src[++i] - '0'; - *(dst++) = val[0] * 64 + val[1] * 8 + val[2]; - break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': val[0] = src[ i] - '0'; + val[1] = src[++i] - '0'; + val[2] = src[++i] - '0'; + *(dst++) = val[0] * 64 + val[1] * 8 + val[2]; + break; - default: *(dst++) = src[i]; break; - } - } - } + default: *(dst++) = src[i]; break; + } + } + } return(dst - s); } diff --git a/vpi/fstapi.h b/vpi/fstapi.h index 9ace034ac..83daac4b0 100644 --- a/vpi/fstapi.h +++ b/vpi/fstapi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2013 Tony Bybell. + * Copyright (c) 2009-2014 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -40,26 +40,35 @@ extern "C" { typedef uint32_t fstHandle; +enum fstWriterPackType { + FST_WR_PT_ZLIB = 0, + FST_WR_PT_FASTLZ = 1, + FST_WR_PT_LZ4 = 2 +}; + enum fstFileType { FST_FT_MIN = 0, FST_FT_VERILOG = 0, FST_FT_VHDL = 1, - FST_FT_VERILOG_VHDL = 2, + FST_FT_VERILOG_VHDL = 2, FST_FT_MAX = 2 }; enum fstBlockType { - FST_BL_HDR = 0, + FST_BL_HDR = 0, FST_BL_VCDATA = 1, - FST_BL_BLACKOUT = 2, + FST_BL_BLACKOUT = 2, FST_BL_GEOM = 3, FST_BL_HIER = 4, FST_BL_VCDATA_DYN_ALIAS = 5, + FST_BL_HIER_LZ4 = 6, + FST_BL_HIER_LZ4DUO = 7, + FST_BL_VCDATA_DYN_ALIAS2 = 8, - FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */ - FST_BL_SKIP = 255 /* used while block is being written */ + FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */ + FST_BL_SKIP = 255 /* used while block is being written */ }; enum fstScopeType { @@ -99,7 +108,7 @@ enum fstScopeType { }; enum fstVarType { - FST_VT_MIN = 0, /* start of vartypes */ + FST_VT_MIN = 0, /* start of vartypes */ FST_VT_VCD_EVENT = 0, FST_VT_VCD_INTEGER = 1, @@ -109,7 +118,7 @@ enum fstVarType { FST_VT_VCD_REG = 5, FST_VT_VCD_SUPPLY0 = 6, FST_VT_VCD_SUPPLY1 = 7, - FST_VT_VCD_TIME = 8, + FST_VT_VCD_TIME = 8, FST_VT_VCD_TRI = 9, FST_VT_VCD_TRIAND = 10, FST_VT_VCD_TRIOR = 11, @@ -120,21 +129,21 @@ enum fstVarType { FST_VT_VCD_WIRE = 16, FST_VT_VCD_WOR = 17, FST_VT_VCD_PORT = 18, - FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */ + FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */ FST_VT_VCD_REALTIME = 20, - FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */ + FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */ FST_VT_SV_BIT = 22, FST_VT_SV_LOGIC = 23, - FST_VT_SV_INT = 24, /* declare as size = 32 */ - FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */ - FST_VT_SV_LONGINT = 26, /* declare as size = 64 */ - FST_VT_SV_BYTE = 27, /* declare as size = 8 */ - FST_VT_SV_ENUM = 28, /* declare as appropriate type range */ - FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */ + FST_VT_SV_INT = 24, /* declare as size = 32 */ + FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */ + FST_VT_SV_LONGINT = 26, /* declare as size = 64 */ + FST_VT_SV_BYTE = 27, /* declare as size = 8 */ + FST_VT_SV_ENUM = 28, /* declare as appropriate type range */ + FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */ - FST_VT_MAX = 29 /* end of vartypes */ + FST_VT_MAX = 29 /* end of vartypes */ }; enum fstVarDir { @@ -165,7 +174,7 @@ enum fstHierType { enum fstAttrType { FST_AT_MIN = 0, - FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */ + FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */ FST_AT_ARRAY = 1, FST_AT_ENUM = 2, FST_AT_PACK = 3, @@ -176,9 +185,9 @@ enum fstAttrType { enum fstMiscType { FST_MT_MIN = 0, - FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */ - FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */ - FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */ + FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */ + FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */ + FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */ FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */ FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */ FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */ @@ -265,7 +274,7 @@ enum fstSupplementalDataType { FST_SDT_MAX = 16, FST_SDT_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left after shifting FST_SDT_SVT_SHIFT_COUNT */ - FST_SDT_ABS_MAX = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1) + FST_SDT_ABS_MAX = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1) }; @@ -274,140 +283,141 @@ struct fstHier unsigned char htyp; union { - /* if htyp == FST_HT_SCOPE */ - struct fstHierScope { - unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */ - const char *name; - const char *component; - uint32_t name_length; /* strlen(u.scope.name) */ - uint32_t component_length; /* strlen(u.scope.component) */ - } scope; + /* if htyp == FST_HT_SCOPE */ + struct fstHierScope { + unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */ + const char *name; + const char *component; + uint32_t name_length; /* strlen(u.scope.name) */ + uint32_t component_length; /* strlen(u.scope.component) */ + } scope; - /* if htyp == FST_HT_VAR */ - struct fstHierVar { - unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */ - unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */ - unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */ - unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */ - unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */ - const char *name; - uint32_t length; - fstHandle handle; - uint32_t name_length; /* strlen(u.var.name) */ - unsigned is_alias : 1; - } var; + /* if htyp == FST_HT_VAR */ + struct fstHierVar { + unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */ + unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */ + unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */ + unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */ + unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */ + const char *name; + uint32_t length; + fstHandle handle; + uint32_t name_length; /* strlen(u.var.name) */ + unsigned is_alias : 1; + } var; - /* if htyp == FST_HT_ATTRBEGIN */ - struct fstHierAttr { - unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */ - unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */ - const char *name; - uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */ - uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */ - uint32_t name_length; /* strlen(u.attr.name) */ - } attr; - } u; + /* if htyp == FST_HT_ATTRBEGIN */ + struct fstHierAttr { + unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */ + unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */ + const char *name; + uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */ + uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */ + uint32_t name_length; /* strlen(u.attr.name) */ + } attr; + } u; }; /* * writer functions */ -void fstWriterClose(void *ctx); -void * fstWriterCreate(const char *nam, int use_compressed_hier); - /* used for Verilog/SV */ -fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, - uint32_t len, const char *nam, fstHandle aliasHandle); - /* future expansion for VHDL and other languages. The variable type, data type, etc map onto - the current Verilog/SV one. The "type" string is optional for a more verbose or custom description */ -fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd, - uint32_t len, const char *nam, fstHandle aliasHandle, - const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt); -void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val); -void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len); -void fstWriterEmitDumpActive(void *ctx, int enable); -void fstWriterEmitTimeChange(void *ctx, uint64_t tim); -void fstWriterFlushContext(void *ctx); -int fstWriterGetDumpSizeLimitReached(void *ctx); -int fstWriterGetFseekFailed(void *ctx); -void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype, - const char *attrname, uint64_t arg); -void fstWriterSetAttrEnd(void *ctx); -void fstWriterSetComment(void *ctx, const char *comm); -void fstWriterSetDate(void *ctx, const char *dat); -void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes); -void fstWriterSetEnvVar(void *ctx, const char *envvar); -void fstWriterSetFileType(void *ctx, enum fstFileType filetype); -void fstWriterSetPackType(void *ctx, int typ); /* type = 0 (libz), 1 (fastlz) */ -void fstWriterSetParallelMode(void *ctx, int enable); -void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */ -void fstWriterSetScope(void *ctx, enum fstScopeType scopetype, - const char *scopename, const char *scopecomp); -void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); -void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); -void fstWriterSetTimescale(void *ctx, int ts); -void fstWriterSetTimescaleFromString(void *ctx, const char *s); -void fstWriterSetTimezero(void *ctx, int64_t tim); -void fstWriterSetUpscope(void *ctx); -void fstWriterSetVersion(void *ctx, const char *vers); +void fstWriterClose(void *ctx); +void * fstWriterCreate(const char *nam, int use_compressed_hier); + /* used for Verilog/SV */ +fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, + uint32_t len, const char *nam, fstHandle aliasHandle); + /* future expansion for VHDL and other languages. The variable type, data type, etc map onto + the current Verilog/SV one. The "type" string is optional for a more verbose or custom description */ +fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd, + uint32_t len, const char *nam, fstHandle aliasHandle, + const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt); +void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val); +void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len); +void fstWriterEmitDumpActive(void *ctx, int enable); +void fstWriterEmitTimeChange(void *ctx, uint64_t tim); +void fstWriterFlushContext(void *ctx); +int fstWriterGetDumpSizeLimitReached(void *ctx); +int fstWriterGetFseekFailed(void *ctx); +void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype, + const char *attrname, uint64_t arg); +void fstWriterSetAttrEnd(void *ctx); +void fstWriterSetComment(void *ctx, const char *comm); +void fstWriterSetDate(void *ctx, const char *dat); +void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes); +void fstWriterSetEnvVar(void *ctx, const char *envvar); +void fstWriterSetFileType(void *ctx, enum fstFileType filetype); +void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ); +void fstWriterSetParallelMode(void *ctx, int enable); +void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */ +void fstWriterSetScope(void *ctx, enum fstScopeType scopetype, + const char *scopename, const char *scopecomp); +void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); +void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); +void fstWriterSetTimescale(void *ctx, int ts); +void fstWriterSetTimescaleFromString(void *ctx, const char *s); +void fstWriterSetTimezero(void *ctx, int64_t tim); +void fstWriterSetUpscope(void *ctx); +void fstWriterSetVersion(void *ctx, const char *vers); /* * reader functions */ -void fstReaderClose(void *ctx); -void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx); -void fstReaderClrFacProcessMaskAll(void *ctx); -uint64_t fstReaderGetAliasCount(void *ctx); -const char * fstReaderGetCurrentFlatScope(void *ctx); -void * fstReaderGetCurrentScopeUserInfo(void *ctx); -int fstReaderGetCurrentScopeLen(void *ctx); -const char * fstReaderGetDateString(void *ctx); -int fstReaderGetDoubleEndianMatchState(void *ctx); -uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx); -unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx); -uint64_t fstReaderGetEndTime(void *ctx); -int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx); -int fstReaderGetFileType(void *ctx); -int fstReaderGetFseekFailed(void *ctx); -fstHandle fstReaderGetMaxHandle(void *ctx); -uint64_t fstReaderGetMemoryUsedByWriter(void *ctx); -uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx); -uint64_t fstReaderGetScopeCount(void *ctx); -uint64_t fstReaderGetStartTime(void *ctx); -signed char fstReaderGetTimescale(void *ctx); -int64_t fstReaderGetTimezero(void *ctx); -uint64_t fstReaderGetValueChangeSectionCount(void *ctx); -char * fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf); -uint64_t fstReaderGetVarCount(void *ctx); -const char * fstReaderGetVersionString(void *ctx); +void fstReaderClose(void *ctx); +void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx); +void fstReaderClrFacProcessMaskAll(void *ctx); +uint64_t fstReaderGetAliasCount(void *ctx); +const char * fstReaderGetCurrentFlatScope(void *ctx); +void * fstReaderGetCurrentScopeUserInfo(void *ctx); +int fstReaderGetCurrentScopeLen(void *ctx); +const char * fstReaderGetDateString(void *ctx); +int fstReaderGetDoubleEndianMatchState(void *ctx); +uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx); +unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx); +uint64_t fstReaderGetEndTime(void *ctx); +int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx); +int fstReaderGetFileType(void *ctx); +int fstReaderGetFseekFailed(void *ctx); +fstHandle fstReaderGetMaxHandle(void *ctx); +uint64_t fstReaderGetMemoryUsedByWriter(void *ctx); +uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx); +uint64_t fstReaderGetScopeCount(void *ctx); +uint64_t fstReaderGetStartTime(void *ctx); +signed char fstReaderGetTimescale(void *ctx); +int64_t fstReaderGetTimezero(void *ctx); +uint64_t fstReaderGetValueChangeSectionCount(void *ctx); +char * fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf); +uint64_t fstReaderGetVarCount(void *ctx); +const char * fstReaderGetVersionString(void *ctx); struct fstHier *fstReaderIterateHier(void *ctx); -int fstReaderIterateHierRewind(void *ctx); -int fstReaderIterBlocks(void *ctx, - void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value), - void *user_callback_data_pointer, FILE *vcdhandle); -int fstReaderIterBlocks2(void *ctx, - void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value), - void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len), - void *user_callback_data_pointer, FILE *vcdhandle); -void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable); -void * fstReaderOpen(const char *nam); -void * fstReaderOpenForUtilitiesOnly(void); -const char * fstReaderPopScope(void *ctx); -int fstReaderProcessHier(void *ctx, FILE *vcdhandle); -const char * fstReaderPushScope(void *ctx, const char *nam, void *user_info); -void fstReaderResetScope(void *ctx); -void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx); -void fstReaderSetFacProcessMaskAll(void *ctx); -void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time); -void fstReaderSetUnlimitedTimeRange(void *ctx); +int fstReaderIterateHierRewind(void *ctx); +int fstReaderIterBlocks(void *ctx, + void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value), + void *user_callback_data_pointer, FILE *vcdhandle); +int fstReaderIterBlocks2(void *ctx, + void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value), + void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len), + void *user_callback_data_pointer, FILE *vcdhandle); +void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable); +void * fstReaderOpen(const char *nam); +void * fstReaderOpenForUtilitiesOnly(void); +const char * fstReaderPopScope(void *ctx); +int fstReaderProcessHier(void *ctx, FILE *vcdhandle); +const char * fstReaderPushScope(void *ctx, const char *nam, void *user_info); +void fstReaderResetScope(void *ctx); +void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx); +void fstReaderSetFacProcessMaskAll(void *ctx); +void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time); +void fstReaderSetUnlimitedTimeRange(void *ctx); +void fstReaderSetVcdExtensions(void *ctx, int enable); /* * utility functions */ -int fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len); -int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len); +int fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len); +int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len); #ifdef __cplusplus } diff --git a/vpi/lxt2_write.c b/vpi/lxt2_write.c index c53854d04..b50aa2359 100644 --- a/vpi/lxt2_write.c +++ b/vpi/lxt2_write.c @@ -30,18 +30,18 @@ static char *lxt2_wr_vcd_truncate_bitvec(char *s) { -char l, r; +char l, r; r=*s; -if(r=='1') +if(r=='1') { return s; - } + } else { s++; } - + for(;;s++) { l=r; r=*s; @@ -50,7 +50,7 @@ for(;;s++) if(l!=r) { return(((l=='0')&&(r=='1'))?s:s-1); - } + } } } @@ -155,7 +155,7 @@ static lxt2_wr_ds_Tree * lxt2_wr_ds_insert(granmsk_t i, lxt2_wr_ds_Tree * t, int /* Insert i into the tree t, unless it's already there. */ /* Return a pointer to the resulting tree. */ lxt2_wr_ds_Tree * n; - + n = (lxt2_wr_ds_Tree *) calloc (1, sizeof (lxt2_wr_ds_Tree)); if (n == NULL) { fprintf(stderr, "ds_insert: ran out of memory, exiting.\n"); @@ -245,7 +245,7 @@ static lxt2_wr_dslxt_Tree * lxt2_wr_dslxt_insert(char *i, lxt2_wr_dslxt_Tree * t /* Return a pointer to the resulting tree. */ lxt2_wr_dslxt_Tree * n; int dir; - + n = (lxt2_wr_dslxt_Tree *) calloc (1, sizeof (lxt2_wr_dslxt_Tree)); if (n == NULL) { fprintf(stderr, "dslxt_insert: ran out of memory, exiting.\n"); @@ -281,7 +281,7 @@ static lxt2_wr_dslxt_Tree * lxt2_wr_dslxt_insert(char *i, lxt2_wr_dslxt_Tree * t /* * functions which emit various big endian * data to a file - */ + */ static int lxt2_wr_emit_u8(struct lxt2_wr_trace *lt, int value) { unsigned char buf[1]; @@ -340,7 +340,7 @@ return(rc); * data to a file. (lt->position needs to be * fixed up on gzclose so the tables don't * get out of sync!) - */ + */ static int gzwrite_buffered(struct lxt2_wr_trace *lt) { int rc = 1; @@ -446,7 +446,7 @@ return(rc); static int lxt2_wr_emit_stringz(struct lxt2_wr_trace *lt, char *value) { int rc=1; -do +do { rc&=lxt2_wr_emit_u8z(lt, *value); } while(*(value++)); @@ -473,7 +473,7 @@ for(p=s;*p;p++) { h=h^(g>>24); h=h^g; - } + } } h^=h2; /* combine the two hashes */ @@ -500,17 +500,17 @@ struct lxt2_wr_symbol *temp; hv=lxt2_wr_hash(s); if(!(temp=lt->sym[hv])) return(NULL); /* no hash entry, add here wanted to add */ - + while(temp) { if(!strcmp(temp->name,s)) { - return(temp); /* in table already */ + return(temp); /* in table already */ } if(!temp->next) break; temp=temp->next; } - + return(NULL); /* not found, add here if you want to add*/ } @@ -535,13 +535,13 @@ if(lt->compress_fac_str) lxt2_wr_emit_u16z(lt, i); lxt2_wr_emit_stringz(lt, str+i); free(lt->compress_fac_str); - } + } else { lxt2_wr_emit_u16z(lt, 0); lxt2_wr_emit_stringz(lt, str); } - + lt->compress_fac_str = (char *) malloc((lt->compress_fac_len=len)+1); strcpy(lt->compress_fac_str, str); } @@ -567,10 +567,10 @@ while(lastch!=s->name) if(*lastch=='[') { - *lastch=0x00; + *lastch=0x00; return; } - lastch--; + lastch--; } return; } @@ -578,13 +578,13 @@ return; static void lxt2_wr_emitfacs(struct lxt2_wr_trace *lt) { -int i; +unsigned int i; if((lt)&&(lt->numfacs)) { struct lxt2_wr_symbol *s = lt->symchain; struct lxt2_wr_symbol **aliascache = calloc(lt->numalias ? lt->numalias : 1, sizeof(struct lxt2_wr_symbol *)); - int aliases_encountered, facs_encountered; + unsigned int aliases_encountered, facs_encountered; lt->sorted_facs = (struct lxt2_wr_symbol **)calloc(lt->numfacs, sizeof(struct lxt2_wr_symbol *)); @@ -597,19 +597,19 @@ if((lt)&&(lt->numfacs)) strip_brack(s); s=s->symchain; } - else + else for(i=0;inumfacs;i++) { lt->sorted_facs[lt->numfacs - i - 1] = s; /* facs were chained backwards so reverse to restore bitslicing */ s=s->symchain; - } + } wave_msort(lt->sorted_facs, lt->numfacs); if(lt->partial_preference) { /* move preferenced facs up */ struct lxt2_wr_symbol **prefcache = aliascache; - int prefs_encountered = 0; + int prefs_encountered = 0; facs_encountered = 0; for(i=0;inumfacs;i++) @@ -700,7 +700,7 @@ if((lt)&&(lt->numfacs)) free(lt->compress_fac_str); lt->compress_fac_str=NULL; lt->compress_fac_len=0; lt->zfacname_predec_size = lt->zpackcount; - + gzflush_buffered(lt, 1); fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); @@ -746,7 +746,7 @@ if((lt)&&(lt->numfacs)) } -/* +/* * initialize the trace and get back an lt context */ struct lxt2_wr_trace *lxt2_wr_init(const char *name) @@ -805,15 +805,15 @@ if(lt) { lt->partial = 1; lt->partial_zip = (zipmode != 0); - lt->partial_iter = LXT2_WR_PARTIAL_SIZE; + lt->partial_iter = LXT2_WR_PARTIAL_SIZE; } } void lxt2_wr_set_partial_preference(struct lxt2_wr_trace *lt, const char *name) { struct lxt2_wr_symbol *s; - -if((lt)&&(name)&&(!lt->sorted_facs)) + +if((lt)&&(name)&&(!lt->sorted_facs)) { s=lxt2_wr_symfind(lt, name); if(s) @@ -852,8 +852,8 @@ if(lt) /* * set initial value of trace (0, 1, x, z) only legal vals */ -void lxt2_wr_set_initial_value(struct lxt2_wr_trace *lt, char value) -{ +void lxt2_wr_set_initial_value(struct lxt2_wr_trace *lt, char value) +{ if(lt) { switch(value) @@ -991,7 +991,7 @@ return(sa); } -/* +/* * set current time/granule updating */ int lxt2_wr_inc_time_by_delta(struct lxt2_wr_trace *lt, unsigned int timeval) @@ -1057,7 +1057,7 @@ if(!clone) for(cnt = 0; cnt < lt->break_header_size; cnt += sizeof(buf)) { seg = lt->break_header_size - cnt; - if(seg > sizeof(buf)) + if(seg > (off_t)sizeof(buf)) { seg = sizeof(buf); } @@ -1221,7 +1221,7 @@ if(using_partial) lxt2_wr_emit_u32(lt, partial_length+9); /* size of this section (uncompressed) */ lxt2_wr_emit_u32(lt, iter); /* begin iter of section */ fflush(lt->handle); - + lt->zhandle = gzdopen(dup(fileno(lt->handle)), lt->zmode); lt->zpackcount = 0; } @@ -1331,7 +1331,7 @@ if((lt->timegranule>=lt->maxgranule)||(do_finalize)||(early_flush)) lxt2_wr_emit_u32(lt, 0); /* size of this section (uncompressed) */ lxt2_wr_emit_u32(lt, ~0); /* control section */ fflush(lt->handle); - + lt->zhandle = gzdopen(dup(fileno(lt->handle)), lt->zmode); lt->zpackcount = 0; } @@ -1354,9 +1354,9 @@ if((lt->timegranule>=lt->maxgranule)||(do_finalize)||(early_flush)) exit(255); } - lxt2_wr_emit_stringz(lt, ds->item); + lxt2_wr_emit_stringz(lt, ds->item); ds2 = ds->next; - free(ds->item); + free(ds->item); free(ds); ds = ds2; } @@ -1369,7 +1369,7 @@ if((lt->timegranule>=lt->maxgranule)||(do_finalize)||(early_flush)) for(i=0;inum_map_entries;i++) { /* fprintf(stderr, "+++ %08x (%d)(%d)\n", dt->item, i, dt->val); */ - if(dt->val != i) + if(((unsigned int)dt->val) != i) { fprintf(stderr, "internal error line %d\n", __LINE__); exit(255); @@ -1382,7 +1382,7 @@ if((lt->timegranule>=lt->maxgranule)||(do_finalize)||(early_flush)) #endif dt2 = dt->next; - free(dt); + free(dt); dt = dt2; } lt->mapdict_head = lt->mapdict_curr = lt->mapdict = NULL; @@ -1399,11 +1399,11 @@ if((lt->timegranule>=lt->maxgranule)||(do_finalize)||(early_flush)) if(using_partial_zip) { off_t c_len; - + gzflush_buffered(lt, 1); fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); - + c_len = lt->position - current_iter_pos - 12; fseeko(lt->handle, current_iter_pos, SEEK_SET); @@ -1467,7 +1467,7 @@ if(lt) { lt->bumptime = 0; - if(!lt->flush_valid) + if(!lt->flush_valid) { lt->timepos++; } @@ -1475,7 +1475,7 @@ if(lt) { lt->flush_valid = 0; } - + if(lt->timepos == LXT2_WR_GRANULE_SIZE) { /* fprintf(stderr, "flushing granule to disk at time %d\n", (unsigned int)timeval); */ @@ -1484,7 +1484,7 @@ if(lt) } /* fprintf(stderr, "updating time to %d (%d dict entries/%d bytes)\n", (unsigned int)timeval, lt->num_dict_entries, lt->dict_string_mem_required); */ - lt->timetable[lt->timepos] = timeval; + lt->timetable[lt->timepos] = timeval; lt->lasttime = timeval; } } @@ -1493,7 +1493,7 @@ if(lt) lt->timeset = 1; lt->mintime = lt->maxtime = timeval; - lt->timetable[lt->timepos] = timeval; + lt->timetable[lt->timepos] = timeval; } if( (!lt->timepos) && (!lt->timegranule) ) @@ -1524,7 +1524,7 @@ if(lt) else if (s->flags&LXT2_WR_SYM_F_DOUBLE) { double value = 0; - + sscanf(s->value, "%lg", &value); errno = 0; lxt2_wr_emit_value_double(lt, s, 0, value); @@ -1625,7 +1625,7 @@ int rc=0; if((!lt)||(lt->blackout)||(!s)||(row)) return(rc); -if(!lt->emitted) +if(!lt->emitted) { lxt2_wr_emitfacs(lt); lt->emitted = 1; @@ -1666,7 +1666,7 @@ if(s->flags&LXT2_WR_SYM_F_DOUBLE) if(lt->dict_curr) { - lt->dict_curr->next = lt->dict; + lt->dict_curr->next = lt->dict; lt->dict_curr = lt->dict; } else @@ -1707,7 +1707,7 @@ int rc=0; if((!lt)||(lt->blackout)||(!s)||(!value)||(row)) return(rc); -if(!lt->emitted) +if(!lt->emitted) { lxt2_wr_emitfacs(lt); lt->emitted = 1; @@ -1746,7 +1746,7 @@ if(s->flags&LXT2_WR_SYM_F_STRING) if(lt->dict_curr) { - lt->dict_curr->next = lt->dict; + lt->dict_curr->next = lt->dict; lt->dict_curr = lt->dict; } else @@ -1791,7 +1791,7 @@ int i; if((!lt)||(lt->blackout)||(!s)||(!value)||(!*value)||(row)) return(rc); -if(!lt->emitted) +if(!lt->emitted) { lxt2_wr_emitfacs(lt); lt->emitted = 1; @@ -1856,12 +1856,12 @@ if(!(s->flags&(LXT2_WR_SYM_F_DOUBLE|LXT2_WR_SYM_F_STRING))) prevch = *vpnt; while(*vpnt) { - if(prevch == *vpnt) + if(prevch == *vpnt) { vpnt++; } else - { + { prevch = 0; break; } @@ -1968,7 +1968,7 @@ idxchk: if(idx<0) if(lt->dict_curr) { - lt->dict_curr->next = lt->dict; + lt->dict_curr->next = lt->dict; lt->dict_curr = lt->dict; } else @@ -2016,15 +2016,15 @@ struct lxt2_wr_symbol *s; if((lt)&&(!lt->blackout)) { - if(!lt->emitted) + if(!lt->emitted) { lxt2_wr_emitfacs(lt); lt->emitted = 1; - + if(!lt->timeset) { lxt2_wr_set_time(lt, 0); - } + } } s = lt->symchain; @@ -2036,7 +2036,7 @@ if((lt)&&(!lt->blackout)) { s->msk |= (LXT2_WR_GRAN_1VAL<timepos); s->chg[s->chgpos] = LXT2_WR_ENC_BLACKOUT; - + s->chgpos++; } else @@ -2158,7 +2158,7 @@ if(lt) { struct lxt2_wr_symbol *s = lt->symchain; struct lxt2_wr_symbol *s2; - + while(s) { free(s->name); @@ -2170,7 +2170,7 @@ if(lt) lt->symchain=NULL; } - + free(lt->lxtname); free(lt->sorted_facs); fclose(lt->handle); @@ -2193,13 +2193,13 @@ if(lt) /* - * time zero offset + * time zero offset */ -void lxt2_wr_set_timezero(struct lxt2_wr_trace *lt, lxtstime_t timeval) -{ +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 f1487fb34..7f2c6d134 100644 --- a/vpi/lxt2_write.h +++ b/vpi/lxt2_write.h @@ -3,19 +3,19 @@ * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ @@ -83,12 +83,12 @@ typedef unsigned long long granmsk_t; #define LXT2_WR_GRAN_1VAL (LXT2_WR_ULLDESC(1)) #else typedef unsigned int granmsk_t; -#define LXT2_WR_GRAN_0VAL (0) +#define LXT2_WR_GRAN_0VAL (0) #define LXT2_WR_GRAN_1VAL (1) #endif -enum LXT2_WR_Encodings { +enum LXT2_WR_Encodings { LXT2_WR_ENC_0, LXT2_WR_ENC_1, LXT2_WR_ENC_INV, @@ -132,12 +132,12 @@ struct lxt2_wr_ds_tree_node { */ typedef struct lxt2_wr_dslxt_tree_node lxt2_wr_dslxt_Tree; struct lxt2_wr_dslxt_tree_node { - lxt2_wr_dslxt_Tree * left, * right; + lxt2_wr_dslxt_Tree * left, * right; char *item; unsigned int val; lxt2_wr_dslxt_Tree * next; }; - + struct lxt2_wr_trace { @@ -163,7 +163,7 @@ off_t current_chunk, current_chunkz; struct lxt2_wr_symbol *sym[LXT2_WR_SYMPRIME]; struct lxt2_wr_symbol **sorted_facs; struct lxt2_wr_symbol *symchain; -int numfacs, numalias; +unsigned int numfacs, numalias; int numfacbytes; int longestname; @@ -174,7 +174,7 @@ lxttime_t mintime, maxtime; lxtstime_t timezero; unsigned int timegranule; int timescale; -int timepos; +unsigned int timepos; unsigned int maxgranule; lxttime_t firsttime, lasttime; lxttime_t timetable[LXT2_WR_GRANULE_SIZE]; diff --git a/vpi/lxt_write.c b/vpi/lxt_write.c index 9e9cf2ea9..be22866da 100644 --- a/vpi/lxt_write.c +++ b/vpi/lxt_write.c @@ -132,7 +132,7 @@ static dslxt_Tree * dslxt_insert(char *i, dslxt_Tree * t, unsigned int val) { /* Return a pointer to the resulting tree. */ dslxt_Tree * n; int dir; - + n = (dslxt_Tree *) calloc (1, sizeof (dslxt_Tree)); if (n == NULL) { fprintf(stderr, "dslxt_insert: ran out of memory, exiting.\n"); @@ -190,7 +190,7 @@ static dslxt_Tree * dslxt_delete(char *i, dslxt_Tree * t) { /* * functions which emit various big endian * data to a file - */ + */ static int lt_emit_u8(struct lt_trace *lt, int value) { unsigned char buf[1]; @@ -271,7 +271,7 @@ return(nmemb); static int lt_emit_string(struct lt_trace *lt, char *value) { int rc=1; -do +do { rc&=lt_emit_u8(lt, *value); } while(*(value++)); @@ -284,7 +284,7 @@ return(rc); * data to a file. (lt->position needs to be * fixed up on gzclose so the tables don't * get out of sync!) - */ + */ static int lt_emit_u8z(struct lt_trace *lt, int value) { unsigned char buf[1]; @@ -371,7 +371,7 @@ return(nmemb); static int lt_emit_stringz(struct lt_trace *lt, char *value) { int rc=1; -do +do { rc&=lt_emit_u8z(lt, *value); } while(*(value++)); @@ -383,7 +383,7 @@ return(rc); * data to a file. (lt->position needs to be * fixed up on BZ2_bzclose so the tables don't * get out of sync!) - */ + */ static int lt_emit_u8bz(struct lt_trace *lt, int value) { unsigned char buf[1]; @@ -470,7 +470,7 @@ return(nmemb); static int lt_emit_stringbz(struct lt_trace *lt, char *value) { int rc=1; -do +do { rc&=lt_emit_u8bz(lt, *value); } while(*(value++)); @@ -537,7 +537,7 @@ for(p=s;*p;p++) { h=h^(g>>24); h=h^g; - } + } } h^=h2; /* combine the two hashes */ @@ -564,17 +564,17 @@ struct lt_symbol *temp; hv=lt_hash(s); if(!(temp=lt->sym[hv])) return(NULL); /* no hash entry, add here wanted to add */ - + while(temp) { if(!strcmp(temp->name,s)) { - return(temp); /* in table already */ + return(temp); /* in table already */ } if(!temp->next) break; temp=temp->next; } - + return(NULL); /* not found, add here if you want to add*/ } @@ -599,13 +599,13 @@ if(lt->compress_fac_str) lt_emit_u16z(lt, i); lt_emit_stringz(lt, str+i); free(lt->compress_fac_str); - } + } else { lt_emit_u16z(lt, 0); lt_emit_stringz(lt, str); } - + lt->compress_fac_str = (char *) malloc((lt->compress_fac_len=len)+1); strcpy(lt->compress_fac_str, str); } @@ -626,10 +626,10 @@ while(lastch!=s->name) if(*lastch=='[') { - *lastch=0x00; + *lastch=0x00; return; } - lastch--; + lastch--; } return; } @@ -655,12 +655,12 @@ if((lt)&&(lt->numfacs)) strip_brack(s); s=s->symchain; } - else + else for(i=0;inumfacs;i++) { lt->sorted_facs[lt->numfacs - i - 1] = s; /* facs were chained backwards so reverse to restore bitslicing*/ s=s->symchain; - } + } wave_msort(lt->sorted_facs, lt->numfacs); for(i=0;inumfacs;i++) @@ -688,7 +688,7 @@ if((lt)&&(lt->numfacs)) free(lt->compress_fac_str); lt->compress_fac_str=NULL; lt->compress_fac_len=0; lt->zfacname_predec_size = lt->zpackcount; - + gzclose(lt->zhandle); fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); @@ -723,13 +723,13 @@ if((lt)&&(lt->numfacs)) if(is_interlaced_trace) { lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9"); - + lt->sync_table_offset = lt->position; for(i=0;inumfacs;i++) { lt_emit_u32z(lt, lt->sorted_facs[i]->last_change); } - + gzclose(lt->zhandle); lt->zhandle = NULL; fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); @@ -740,7 +740,7 @@ if((lt)&&(lt->numfacs)) } -/* +/* * initialize the trace and get back an lt context */ struct lt_trace *lt_init(const char *name) @@ -866,7 +866,7 @@ switch(numbytes_trans&3) case 3: lt->lt_emit_u32(lt, numtrans); break; } -/* printf("Clock finish for '%s' at %lld ending with '%c' for %d repeats over a switch delta of %d\n", +/* printf("Clock finish for '%s' at %lld ending with '%c' for %d repeats over a switch delta of %d\n", s->name, lt->timeval, s->clk_prevval, s->clk_numtrans - LT_CLKPACK, s->clk_delta); */ s->clk_prevtrans = ULLDescriptor(~0); s->clk_numtrans = 0; @@ -967,7 +967,7 @@ switch(numbytes_trans&3) case 3: lt->lt_emit_u32(lt, numtrans); break; } -/* printf("Clock finish for '%s' at %lld ending with '%08x' for %d repeats over a switch delta of %lld\n", +/* printf("Clock finish for '%s' at %lld ending with '%08x' for %d repeats over a switch delta of %lld\n", s->name, lt->timeval, s->clk_prevval, s->clk_numtrans - LT_CLKPACK_M, s->clk_delta); */ s->clk_prevtrans = ULLDescriptor(~0); s->clk_numtrans = 0; @@ -1004,7 +1004,7 @@ if(s1->val > s2->val) return(1); else return(-1); /* they're *never* equal */ static void lt_finalize_dictionary(struct lt_trace *lt) { -int i; +unsigned int i; lt->sorted_dict = calloc(lt->num_dict_entries, sizeof(dslxt_Tree *)); @@ -1035,7 +1035,7 @@ for(i=0;inum_dict_entries;i++) /* fprintf(stderr, "%8d) '%s'\n", ds->val, ds->item); */ lt_emit_stringz(lt, ds->item+1); } - + gzclose(lt->zhandle); fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); @@ -1072,13 +1072,13 @@ if(lt) if(s->clk_numtrans > LT_CLKPACK_M) lt_flushclock_m(lt, s); } else - { + { if(s->clk_numtrans > LT_CLKPACK) lt_flushclock(lt, s); } } - + s=s->symchain; - } + } lt_set_dumpon(lt); /* in case it was turned off */ @@ -1134,7 +1134,7 @@ if(lt) while(t) { lt_emit_u32z(lt, t->position - lastposition); lastposition = t->position; - t=t->next; + t=t->next; } t=lt->timehead; @@ -1144,9 +1144,9 @@ if(lt) { lxttime_t delta = t->timeval - lasttime; lt_emit_u64z(lt, (int)(delta>>32), (int)delta); lasttime = t->timeval; - + t2=t->next; - free(t); + free(t); t=t2; } } @@ -1155,12 +1155,12 @@ if(lt) while(t) { lt_emit_u32z(lt, (int)(t->timeval - lasttime)); lasttime = t->timeval; - + t2=t->next; - free(t); + free(t); t=t2; } - + lt->timehead = lt->timecurr = NULL; } @@ -1170,7 +1170,7 @@ if(lt) lt->ztime_table_size = lt->position - lt->ztime_table_size; } - if(lt->initial_value>=0) + if(lt->initial_value>=0) { lt->initial_value_offset = lt->position; lt_emit_u8(lt, lt->initial_value); @@ -1185,7 +1185,7 @@ if(lt) if(lt->double_used) { lt->double_test_offset = lt->position; - lt_emit_double(lt, 3.14159); + lt_emit_double(lt, 3.14159); } if(lt->dumpoffcount) @@ -1201,7 +1201,7 @@ if(lt) lt_emit_u64(lt, (int)((ltt->timeval)>>32), (int)ltt->timeval); ltt2 = ltt; ltt=ltt->next; - free(ltt2); + free(ltt2); } lt->dumpoffhead = lt->dumpoffcurr = NULL; @@ -1253,7 +1253,7 @@ if(lt) { struct lt_symbol *sc = lt->symchain; struct lt_symbol *s2; - + while(sc) { free(sc->name); @@ -1262,7 +1262,7 @@ if(lt) sc=s2; } } - + free(lt->sorted_facs); fclose(lt->handle); free(lt); @@ -1368,7 +1368,7 @@ return(sa); } -/* +/* * set current time */ int lt_inc_time_by_delta(struct lt_trace *lt, unsigned int timeval) @@ -1407,7 +1407,7 @@ if(lt) else { free(trl); - goto bail; + goto bail; } } else @@ -1485,7 +1485,7 @@ if((lt)&&(!lt->emitted)) } /* - * sets change interlace + * sets change interlace */ void lt_set_no_interlace(struct lt_trace *lt) { @@ -1510,12 +1510,12 @@ if((lt)&&(!lt->emitted)&&(!lt->sorted_facs)) strip_brack(s); s=s->symchain; } - else + else for(i=0;inumfacs;i++) { lt->sorted_facs[lt->numfacs - i - 1] = s; /* facs were chained backwards so reverse to restore bitslicing */ s=s->symchain; - } + } wave_msort(lt->sorted_facs, lt->numfacs); for(i=0;inumfacs;i++) @@ -1555,12 +1555,12 @@ if(lt) { int tag; switch(value) - { + { case '0': tag = 0; break; case '1': tag = 1; break; - case 'Z': + case 'Z': case 'z': tag = 2; break; - case 'X': + case 'X': case 'x': tag = 3; break; case 'H': case 'h': tag = 4; break; @@ -1594,7 +1594,7 @@ if(lt) /* * emission for trace values.. */ -static unsigned int lt_optimask[]= +static int lt_optimask[]= { 0x00000000, @@ -1674,7 +1674,7 @@ while(s->aliased_to) /* find root alias if exists */ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) { int numbytes; /* number of bytes to store value minus one */ - int len = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; + unsigned int len = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; unsigned int last_change_delta; if((lt->clock_compress)&&(s->rows==0)) @@ -1686,7 +1686,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) s->clk_mask <<= 1; s->clk_mask |= 1; - if( ((s->clk_mask&0x1f)==0x1f) && + if( ((s->clk_mask&0x1f)==0x1f) && ( (delta1=(ivalue - s->clk_prevval1) & lt_optimask[s->len]) == ((s->clk_prevval1 - s->clk_prevval3) & lt_optimask[s->len]) ) && ( (delta2=(s->clk_prevval - s->clk_prevval2) & lt_optimask[s->len]) == ((s->clk_prevval2 - s->clk_prevval4) & lt_optimask[s->len]) ) && ( (delta1==delta2) || ((!delta1)&&(!delta2)) ) @@ -1862,7 +1862,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) { tag = (numbytes<<4); } - + lt->lt_emit_u8(lt, tag); switch(numbytes&3) { @@ -1883,7 +1883,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) } lt->lt_emit_u8(lt, optimized ? (3+optimized1) : 0); } - + s->last_change = start_position; if(s->rows>0) @@ -1949,7 +1949,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) { if(lt->num_dict_entries==(256*65536)) lt->dict32_offset = lt->position; } - + lt->num_dict_entries++; } @@ -1994,14 +1994,14 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) value <<= (24-len); rc=lt->lt_emit_u24(lt, value); } - else + else { value <<= (32-len); rc=lt->lt_emit_u32(lt, value); } } - } - + } + if(lt->timebuff) { lt->timechangecount++; @@ -2063,7 +2063,7 @@ if((s->flags)<_SYM_F_DOUBLE) { numbytes = 0; } - + start_position = lt->position; s->last_change = start_position; @@ -2119,7 +2119,7 @@ if((s->flags)<_SYM_F_DOUBLE) } rc=lt->lt_emit_double(lt, value); - + if(lt->timebuff) { lt->timechangecount++; @@ -2181,7 +2181,7 @@ if((s->flags)<_SYM_F_STRING) { numbytes = 0; } - + start_position = lt->position; s->last_change = start_position; @@ -2237,7 +2237,7 @@ if((s->flags)<_SYM_F_STRING) } rc=lt->lt_emit_string(lt, value); - + if(lt->timebuff) { lt->timechangecount++; @@ -2283,7 +2283,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) char prevch; unsigned int last_change_delta; - int len = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; + unsigned int len = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; if((lt->clock_compress)&&(s->rows==0)) { @@ -2291,7 +2291,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) { int legal = 0; int ivalue = 0; - int i; + unsigned int i; char *pntv = value; int delta1, delta2; @@ -2318,7 +2318,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) s->clk_mask <<= 1; s->clk_mask |= legal; - if( ((s->clk_mask&0x1f)==0x1f) && + if( ((s->clk_mask&0x1f)==0x1f) && ( (delta1=(ivalue - s->clk_prevval1) & lt_optimask[s->len]) == ((s->clk_prevval1 - s->clk_prevval3) & lt_optimask[s->len]) ) && ( (delta2=(s->clk_prevval - s->clk_prevval2) & lt_optimask[s->len]) == ((s->clk_prevval2 - s->clk_prevval4) & lt_optimask[s->len]) ) && ( (delta1==delta2) || ((!delta1)&&(!delta2)) ) @@ -2350,7 +2350,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) s->clk_prevval1 = s->clk_prevval; s->clk_prevval = ivalue; - /* printf("Clock value '%08x' for '%s' [len=%d] at %lld (#%d)\n", + /* printf("Clock value '%08x' for '%s' [len=%d] at %lld (#%d)\n", ivalue, s->name, len, lt->timeval, s->clk_numtrans); */ return(1); } @@ -2480,12 +2480,12 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) while((ch=*(pnt++))) { switch(ch) - { + { case '0': case '1': mvl|=LT_MVL_2; break; - case 'Z': - case 'z': - case 'X': + case 'Z': + case 'z': + case 'X': case 'x': mvl|=LT_MVL_4; break; default: mvl|=LT_MVL_9; break; } @@ -2494,13 +2494,13 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) } switch(prevch) - { + { case 0x00: tagadd = 0; break; case '0': tagadd = 3; break; case '1': tagadd = 4; break; - case 'Z': + case 'Z': case 'z': tagadd = 5; break; - case 'X': + case 'X': case 'x': tagadd = 6; break; case 'H': case 'h': tagadd = 7; break; @@ -2589,15 +2589,15 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) if(!tagadd) { - int len2 = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; + unsigned int len2 = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; if((mvl & (LT_MVL_2|LT_MVL_4|LT_MVL_9)) == LT_MVL_2) { - int i; + unsigned int i; int bitpos = 7; int outval = 0; int thisval= 0; - pnt = value; + pnt = value; if((lt->dictmode)&&(len2>lt->mindictwidth)) { @@ -2628,7 +2628,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) { if(lt->num_dict_entries==(256*65536)) lt->dict32_offset = lt->position; } - + lt->num_dict_entries++; } @@ -2666,8 +2666,8 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) outval |= (thisval<lt_emit_u8(lt, outval); + { + lt->lt_emit_u8(lt, outval); outval = 0; bitpos = 7; } @@ -2676,12 +2676,12 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) else if((mvl & (LT_MVL_4|LT_MVL_9)) == LT_MVL_4) { - int i; + unsigned int i; int bitpos = 6; int outval = 0; int thisval= 0; - pnt = value; + pnt = value; for(i=0;iflags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) outval |= (thisval<lt_emit_u8(lt, outval); + { + lt->lt_emit_u8(lt, outval); outval = 0; bitpos = 6; } @@ -2710,12 +2710,12 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) else /* if(mvl & LT_MVL_9) */ { - int i; + unsigned int i; int bitpos = 4; int outval = 0; int thisval= 0; - pnt = value; + pnt = value; for(i=0;iflags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) outval |= (thisval<lt_emit_u8(lt, outval); + { + lt->lt_emit_u8(lt, outval); outval = 0; bitpos = 4; } @@ -2755,7 +2755,7 @@ if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) rc=1; } - + if(lt->timebuff) { lt->timechangecount++; diff --git a/vpi/lxt_write.h b/vpi/lxt_write.h index 8fbb0a797..48a60fcb0 100644 --- a/vpi/lxt_write.h +++ b/vpi/lxt_write.h @@ -3,19 +3,19 @@ * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ @@ -47,11 +47,11 @@ extern "C" { typedef struct dslxt_tree_node dslxt_Tree; struct dslxt_tree_node { - dslxt_Tree * left, * right; + dslxt_Tree * left, * right; char *item; unsigned int val; }; - + #define LT_HDRID (0x0138) #define LT_VERSION (0x0004) @@ -180,7 +180,7 @@ unsigned double_used : 1; unsigned do_strip_brackets : 1; unsigned clock_compress : 1; unsigned dictmode : 1; /* dictionary compression enabled */ -unsigned zmode : 2; /* for value changes */ +unsigned zmode : 2; /* for value changes */ unsigned emitted : 1; /* gate off change field zmode changes when set */ }; @@ -252,9 +252,9 @@ void lt_set_dumpoff(struct lt_trace *lt); void lt_set_dumpon(struct lt_trace *lt); /* - * value change functions..note that if the value string len for - * lt_emit_value_bit_string() is shorter than the symbol length - * it will be left justified with the rightmost character used as + * value change functions..note that if the value string len for + * lt_emit_value_bit_string() is shorter than the symbol length + * it will be left justified with the rightmost character used as * a repeat value that will be propagated to pad the value string out: * * "10x" for 8 bits becomes "10xxxxxx" diff --git a/vpi/lz4.c b/vpi/lz4.c new file mode 100644 index 000000000..39f176faf --- /dev/null +++ b/vpi/lz4.c @@ -0,0 +1,1267 @@ +/* + LZ4 - Fast LZ compression algorithm + Copyright (C) 2011-2014, Yann Collet. + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 source repository : http://code.google.com/p/lz4/ + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ + +/************************************** + Tuning parameters +**************************************/ +/* + * HEAPMODE : + * Select how default compression functions will allocate memory for their hash table, + * in memory stack (0:default, fastest), or in memory heap (1:requires memory allocation (malloc)). + */ +#define HEAPMODE 0 + + +/************************************** + CPU Feature Detection +**************************************/ +/* 32 or 64 bits ? */ +#if (defined(__x86_64__) || defined(_M_X64) || defined(_WIN64) \ + || defined(__64BIT__) || defined(__mips64) \ + || defined(__powerpc64__) || defined(__powerpc64le__) \ + || defined(__ppc64__) || defined(__ppc64le__) \ + || defined(__PPC64__) || defined(__PPC64LE__) \ + || defined(__ia64) || defined(__itanium__) || defined(_M_IA64) \ + || defined(__s390x__) ) /* Detects 64 bits mode */ +# define LZ4_ARCH64 1 +#else +# define LZ4_ARCH64 0 +#endif +#define LZ4_32BITS (sizeof(void*)==4) +#define LZ4_64BITS (sizeof(void*)==8) + +/* + * Little Endian or Big Endian ? + * Overwrite the #define below if you know your architecture endianess + */ +#include /* Apparently required to detect endianess */ +#if defined (__GLIBC__) +# include +# if (__BYTE_ORDER == __BIG_ENDIAN) +# define LZ4_BIG_ENDIAN 1 +# endif +#elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN)) +# define LZ4_BIG_ENDIAN 1 +#elif defined(__sparc) || defined(__sparc__) \ + || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \ + || defined(__hpux) || defined(__hppa) \ + || defined(_MIPSEB) || defined(__s390__) +# define LZ4_BIG_ENDIAN 1 +#else +/* Little Endian assumed. PDP Endian and other very rare endian format are unsupported. */ +#endif + +/* + * Unaligned memory access is automatically enabled for "common" CPU, such as x86. + * For others CPU, such as ARM, the compiler may be more cautious, inserting unnecessary extra code to ensure aligned access property + * If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance + */ +#if defined(__ARM_FEATURE_UNALIGNED) +# define LZ4_FORCE_UNALIGNED_ACCESS 1 +#endif + +/* Define this parameter if your target system or compiler does not support hardware bit count */ +#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ +# define LZ4_FORCE_SW_BITCOUNT +#endif + +/* + * BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE : + * This option may provide a small boost to performance for some big endian cpu, although probably modest. + * You may set this option to 1 if data will remain within closed environment. + * This option is useless on Little_Endian CPU (such as x86) + */ + +/* #define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 */ + + +/************************************** + Compiler Options +**************************************/ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ +/* "restrict" is a known keyword */ +#else +# define restrict /* Disable restrict */ +#endif + +#ifdef _MSC_VER /* Visual Studio */ +# define FORCE_INLINE static __forceinline +# include /* For Visual 2005 */ +# if LZ4_ARCH64 /* 64-bits */ +# pragma intrinsic(_BitScanForward64) /* For Visual 2005 */ +# pragma intrinsic(_BitScanReverse64) /* For Visual 2005 */ +# else /* 32-bits */ +# pragma intrinsic(_BitScanForward) /* For Visual 2005 */ +# pragma intrinsic(_BitScanReverse) /* For Visual 2005 */ +# endif +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#else +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif +#endif + +#ifdef _MSC_VER /* Visual Studio */ +# define lz4_bswap16(x) _byteswap_ushort(x) +#else +# define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))) +#endif + +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) +# define expect(expr,value) (__builtin_expect ((expr),(value)) ) +#else +# define expect(expr,value) (expr) +#endif + +#define likely(expr) expect((expr) != 0, 1) +#define unlikely(expr) expect((expr) != 0, 0) + + +/************************************** + Memory routines +**************************************/ +#include /* malloc, calloc, free */ +#define ALLOCATOR(n,s) calloc(n,s) +#define FREEMEM free +#include /* memset, memcpy */ +#define MEM_INIT memset + + +/************************************** + Includes +**************************************/ +#include "lz4.h" + + +/************************************** + Basic Types +**************************************/ +#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ +# include + typedef uint8_t BYTE; + typedef uint16_t U16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; +#else + typedef unsigned char BYTE; + typedef unsigned short U16; + typedef unsigned int U32; + typedef signed int S32; + typedef unsigned long long U64; +#endif + +#if defined(__GNUC__) && !defined(LZ4_FORCE_UNALIGNED_ACCESS) +# define _PACKED __attribute__ ((packed)) +#else +# define _PACKED +#endif + +#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) +# if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack(1) +# else +# pragma pack(push, 1) +# endif +#endif + +typedef struct { U16 v; } _PACKED U16_S; +typedef struct { U32 v; } _PACKED U32_S; +typedef struct { U64 v; } _PACKED U64_S; +typedef struct {size_t v;} _PACKED size_t_S; + +#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) +# if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack(0) +# else +# pragma pack(pop) +# endif +#endif + +#define A16(x) (((U16_S *)(x))->v) +#define A32(x) (((U32_S *)(x))->v) +#define A64(x) (((U64_S *)(x))->v) +#define AARCH(x) (((size_t_S *)(x))->v) + + +/************************************** + Constants +**************************************/ +#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) +#define HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) +#define HASH_SIZE_U32 (1 << LZ4_HASHLOG) + +#define MINMATCH 4 + +#define COPYLENGTH 8 +#define LASTLITERALS 5 +#define MFLIMIT (COPYLENGTH+MINMATCH) +static const int LZ4_minLength = (MFLIMIT+1); + +#define KB *(1U<<10) +#define MB *(1U<<20) +#define GB *(1U<<30) + +#define LZ4_64KLIMIT ((64 KB) + (MFLIMIT-1)) +#define SKIPSTRENGTH 6 /* Increasing this value will make the compression run slower on incompressible data */ + +#define MAXD_LOG 16 +#define MAX_DISTANCE ((1 << MAXD_LOG) - 1) + +#define ML_BITS 4 +#define ML_MASK ((1U<=e; */ +#else +# define LZ4_WILDCOPY(d,s,e) { if (likely(e-d <= 8)) LZ4_COPY8(d,s) else do { LZ4_COPY8(d,s) } while (d>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clzll(val) >> 3); +# else + int r; + if (!(val>>32)) { r=4; } else { r=0; val>>=32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; +# endif +# else +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanForward64( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctzll(val) >> 3); +# else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif +# endif +} + +#else + +static int LZ4_NbCommonBytes (register U32 val) +{ +# if defined(LZ4_BIG_ENDIAN) +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clz(val) >> 3); +# else + int r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; +# endif +# else +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r; + _BitScanForward( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctz(val) >> 3); +# else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif +# endif +} + +#endif + + +/******************************** + Compression functions +********************************/ +int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } +int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } + +static int LZ4_hashSequence(U32 sequence, tableType_t tableType) +{ + if (tableType == byU16) + return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + else + return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); +} + +static int LZ4_hashPosition(const BYTE* p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); } + +static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + switch (tableType) + { + case byPtr: { const BYTE** hashTable = (const BYTE**) tableBase; hashTable[h] = p; break; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); break; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); break; } + } +} + +static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); +} + +static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } + if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } + { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ +} + +static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); +} + +static unsigned LZ4_count(const BYTE* pIn, const BYTE* pRef, const BYTE* pInLimit) +{ + const BYTE* const pStart = pIn; + + while (likely(pIndictSize; + const BYTE* const dictionary = dictPtr->dictionary; + const BYTE* const dictEnd = dictionary + dictPtr->dictSize; + const size_t dictDelta = dictEnd - (const BYTE*)source; + const BYTE* anchor = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; + + BYTE* op = (BYTE*) dest; + BYTE* const olimit = op + maxOutputSize; + + const int skipStrength = SKIPSTRENGTH; + U32 forwardH; + size_t refDelta=0; + + /* Init conditions */ + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + switch(dict) + { + case noDict: + default: + base = (const BYTE*)source; + lowLimit = (const BYTE*)source; + break; + case withPrefix64k: + base = (const BYTE*)source - dictPtr->currentOffset; + lowLimit = (const BYTE*)source - dictPtr->dictSize; + break; + case usingExtDict: + base = (const BYTE*)source - dictPtr->currentOffset; + lowLimit = (const BYTE*)source; + break; + } + if ((tableType == byU16) && (inputSize>=(int)LZ4_64KLIMIT)) return 0; /* Size too large (not within 64K limit) */ + if (inputSize> skipStrength; + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + ref = LZ4_getPositionOnHash(h, ctx, tableType, base); + if (dict==usingExtDict) + { + if (ref<(const BYTE*)source) + { + refDelta = dictDelta; + lowLimit = dictionary; + } + else + { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + + } while ( ((dictIssue==dictSmall) ? (ref < lowRefLimit) : 0) + || ((tableType==byU16) ? 0 : (ref + MAX_DISTANCE < ip)) + || (A32(ref+refDelta) != A32(ip)) ); + } + + /* Catch up */ + while ((ip>anchor) && (ref+refDelta > lowLimit) && (unlikely(ip[-1]==ref[refDelta-1]))) { ip--; ref--; } + + { + /* Encode Literal length */ + unsigned litLength = (unsigned)(ip - anchor); + token = op++; + if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) + return 0; /* Check output limit */ + if (litLength>=RUN_MASK) + { + int len = (int)litLength-RUN_MASK; + *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< matchlimit) limit = matchlimit; + matchLength = LZ4_count(ip+MINMATCH, ref+MINMATCH, limit); + ip += MINMATCH + matchLength; + if (ip==limit) + { + unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit); + matchLength += more; + ip += more; + } + } + else + { + matchLength = LZ4_count(ip+MINMATCH, ref+MINMATCH, matchlimit); + ip += MINMATCH + matchLength; + } + + if (matchLength>=ML_MASK) + { + if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit))) + return 0; /* Check output limit */ + *token += ML_MASK; + matchLength -= ML_MASK; + for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; } + if (matchLength >= 255) { matchLength-=255; *op++ = 255; } + *op++ = (BYTE)matchLength; + } + else *token += (BYTE)(matchLength); + } + + anchor = ip; + + /* Test end of chunk */ + if (ip > mflimit) break; + + /* Fill table */ + LZ4_putPosition(ip-2, ctx, tableType, base); + + /* Test next position */ + ref = LZ4_getPosition(ip, ctx, tableType, base); + if (dict==usingExtDict) + { + if (ref<(const BYTE*)source) + { + refDelta = dictDelta; + lowLimit = dictionary; + } + else + { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } + LZ4_putPosition(ip, ctx, tableType, base); + if ( ((dictIssue==dictSmall) ? (ref>=lowRefLimit) : 1) + && (ref+MAX_DISTANCE>=ip) + && (A32(ref+refDelta)==A32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } + +_last_literals: + /* Encode Last Literals */ + { + int lastRun = (int)(iend - anchor); + if ((outputLimited) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) + return 0; /* Check output limit */ + if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } + else *op++ = (BYTE)(lastRun<= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ + if (dict->initCheck) LZ4_resetStream(LZ4_dict); /* Uninitialized structure detected */ + + if (dictSize < MINMATCH) + { + dict->dictionary = NULL; + dict->dictSize = 0; + return 1; + } + + if (p <= dictEnd - 64 KB) p = dictEnd - 64 KB; + base = p - dict->currentOffset; + dict->dictionary = p; + dict->dictSize = (U32)(dictEnd - p); + dict->currentOffset += dict->dictSize; + + while (p <= dictEnd-MINMATCH) + { + LZ4_putPosition(p, dict, byU32, base); + p+=3; + } + + return 1; +} + + +static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) +{ + if ((LZ4_dict->currentOffset > 0x80000000) || + ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */ + { + /* rescale hash table */ + U32 delta = LZ4_dict->currentOffset - 64 KB; + const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; + int i; + for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; + else LZ4_dict->hashTable[i] -= delta; + } + LZ4_dict->currentOffset = 64 KB; + if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; + LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; + } +} + + +FORCE_INLINE int LZ4_compress_continue_generic (void* LZ4_stream, const char* source, char* dest, int inputSize, + int maxOutputSize, limitedOutput_directive limit) +{ + LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + + const BYTE* smallest = (const BYTE*) source; + if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ + if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; + LZ4_renormDictT(streamPtr, smallest); + + /* Check overlapping input/dictionary space */ + { + const BYTE* sourceEnd = (const BYTE*) source + inputSize; + if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) + { + streamPtr->dictSize = (U32)(dictEnd - sourceEnd); + if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; + if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; + streamPtr->dictionary = dictEnd - streamPtr->dictSize; + } + } + + /* prefix mode : source data follows dictionary */ + if (dictEnd == (const BYTE*)source) + { + int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, withPrefix64k, dictSmall); + else + result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, withPrefix64k, noDictIssue); + streamPtr->dictSize += (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; + } + + /* external dictionary mode */ + { + int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, usingExtDict, dictSmall); + else + result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, usingExtDict, noDictIssue); + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; + } +} + +int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) +{ + return LZ4_compress_continue_generic(LZ4_stream, source, dest, inputSize, 0, notLimited); +} + +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_compress_continue_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput); +} + + +/* Hidden debug function, to force separate dictionary mode */ +int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) +{ + LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict; + int result; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + + const BYTE* smallest = dictEnd; + if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; + LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest); + + result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue); + + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + + return result; +} + + +int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) +{ + LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; + const BYTE* previousDictEnd = dict->dictionary + dict->dictSize; + + if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; + + memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + + dict->dictionary = (const BYTE*)safeBuffer; + dict->dictSize = (U32)dictSize; + + return dictSize; +} + + + +/**************************** + Decompression functions +****************************/ +/* + * This generic decompression function cover all use cases. + * It shall be instantiated several times, using different sets of directives + * Note that it is essential this generic function is really inlined, + * in order to remove useless branches during compilation optimization. + */ +FORCE_INLINE int LZ4_decompress_generic( + const char* source, + char* dest, + int inputSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ + + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const char* dictStart, /* only if dict==usingExtDict */ + int dictSize /* note : = 0 if noDict */ + ) +{ + /* Local Variables */ + const BYTE* restrict ip = (const BYTE*) source; + const BYTE* ref; + const BYTE* const iend = ip + inputSize; + + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + const BYTE* const lowLimit = (const BYTE*)dest - dictSize; + + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; + const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; + + const int safeDecode = (endOnInput==endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + + + /* Special cases */ + if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ + if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ + if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); + + + /* Main Loop */ + while (1) + { + unsigned token; + size_t length; + + /* get runlength */ + token = *ip++; + if ((length=(token>>ML_BITS)) == RUN_MASK) + { + unsigned s; + do + { + s = *ip++; + length += s; + } + while (likely((endOnInput)?ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) + || ((!endOnInput) && (cpy>oend-COPYLENGTH))) + { + if (partialDecoding) + { + if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ + if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ + } + else + { + if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ + if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ + } + memcpy(op, ip, length); + ip += length; + op += length; + break; /* Necessarily EOF, due to parsing restrictions */ + } + LZ4_WILDCOPY(op, ip, cpy); ip -= (op-cpy); op = cpy; + + /* get offset */ + LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2; + if ((checkOffset) && (unlikely(ref < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */ + + /* get matchlength */ + if ((length=(token&ML_MASK)) == ML_MASK) + { + unsigned s; + do + { + if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; + s = *ip++; + length += s; + } while (s==255); + if ((safeDecode) && LZ4_32BITS && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */ + } + length += MINMATCH; + + /* check external dictionary */ + if ((dict==usingExtDict) && (ref < (BYTE* const)dest)) + { + if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; + + if (length <= (size_t)(dest-(char*)ref)) + { + ref = dictEnd - (dest-(char*)ref); + memcpy(op, ref, length); + op += length; + } + else + { + size_t copySize = (size_t)(dest-(char*)ref); + memcpy(op, dictEnd - copySize, copySize); + op += copySize; + copySize = length - copySize; + if (copySize > (size_t)((char*)op-dest)) /* overlap */ + { + BYTE* const endOfMatch = op + copySize; + const BYTE* copyFrom = (BYTE*)dest; + while (op < endOfMatch) *op++ = *copyFrom++; + } + else + { + memcpy(op, dest, copySize); + op += copySize; + } + } + continue; + } + + /* copy repeated sequence */ + cpy = op + length; + if (unlikely((op-ref)<(int)STEPSIZE)) + { + const size_t dec64 = dec64table[op-ref]; + op[0] = ref[0]; + op[1] = ref[1]; + op[2] = ref[2]; + op[3] = ref[3]; + ref += dec32table[op-ref]; + A32(op+4) = A32(ref); + op += 8; ref -= dec64; + } else { LZ4_COPY8(op,ref); } + + if (unlikely(cpy>oend-12)) + { + if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last 5 bytes must be literals */ + if (opdictionary = dictionary; + lz4sd->dictSize = dictSize; + return 1; +} + +/* +*_continue() : + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks must still be available at the memory position where they were decoded. + If it's not possible, save the relevant part of decoded data into a safe buffer, + and indicate where it stands using LZ4_setDictDecode() +*/ +int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; + int result; + + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, lz4sd->dictionary, lz4sd->dictSize); + if (result <= 0) return result; + if (lz4sd->dictionary + lz4sd->dictSize == dest) + { + lz4sd->dictSize += result; + } + else + { + lz4sd->dictionary = dest; + lz4sd->dictSize = result; + } + + return result; +} + +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) +{ + LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; + int result; + + result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, lz4sd->dictionary, lz4sd->dictSize); + if (result <= 0) return result; + if (lz4sd->dictionary + lz4sd->dictSize == dest) + { + lz4sd->dictSize += result; + } + else + { + lz4sd->dictionary = dest; + lz4sd->dictSize = result; + } + + return result; +} + + +/* +Advanced decoding functions : +*_usingDict() : + These decoding functions work the same as "_continue" ones, + the dictionary must be explicitly provided within parameters +*/ + +FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) +{ + if (dictSize==0) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, NULL, 64 KB); + if ((dictStart+dictSize == dest) && (dictSize >= (int)(64 KB - 1))) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, NULL, 64 KB); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, dictStart, dictSize); +} + +int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + //return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, dictStart, dictSize); + return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); +} + +int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) +{ + //return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, dictStart, dictSize); + return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); +} + +/* debug function */ +int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, dictStart, dictSize); +} + + +/*************************************************** + Obsolete Functions +***************************************************/ +/* +These function names are deprecated and should no longer be used. +They are only provided here for compatibility with older user programs. +- LZ4_uncompress is totally equivalent to LZ4_decompress_fast +- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe +*/ +int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } +int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } + + +/* Obsolete Streaming functions */ + +int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } + +static void LZ4_init(LZ4_stream_t_internal* lz4ds, const BYTE* base) +{ + MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE); + lz4ds->bufferStart = base; +} + +int LZ4_resetStreamState(void* state, const char* inputBuffer) +{ + if ((((size_t)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ + LZ4_init((LZ4_stream_t_internal*)state, (const BYTE*)inputBuffer); + return 0; +} + +void* LZ4_create (const char* inputBuffer) +{ + void* lz4ds = ALLOCATOR(4, LZ4_STREAMSIZE_U32); + LZ4_init ((LZ4_stream_t_internal*)lz4ds, (const BYTE*)inputBuffer); + return lz4ds; +} + +char* LZ4_slideInputBuffer (void* LZ4_Data) +{ + LZ4_stream_t_internal* lz4ds = (LZ4_stream_t_internal*)LZ4_Data; + + LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)lz4ds->bufferStart, 64 KB); + + return (char*)(lz4ds->bufferStart + 64 KB); +} + +/* Obsolete compresson functions using User-allocated state */ + +int LZ4_sizeofState() { return LZ4_STREAMSIZE; } + +int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize) +{ + if (((size_t)(state)&3) != 0) return 0; /* Error : state is not aligned on 4-bytes boundary */ + MEM_INIT(state, 0, LZ4_STREAMSIZE); + + if (inputSize < (int)LZ4_64KLIMIT) + return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue); + else + return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64BITS ? byU32 : byPtr, noDict, noDictIssue); +} + +int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize) +{ + if (((size_t)(state)&3) != 0) return 0; /* Error : state is not aligned on 4-bytes boundary */ + MEM_INIT(state, 0, LZ4_STREAMSIZE); + + if (inputSize < (int)LZ4_64KLIMIT) + return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue); + else + return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64BITS ? byU32 : byPtr, noDict, noDictIssue); +} + +/* Obsolete streaming decompression functions */ + +int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, NULL, 64 KB); +} + +int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) +{ + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, NULL, 64 KB); +} diff --git a/vpi/lz4.h b/vpi/lz4.h new file mode 100644 index 000000000..44ada149e --- /dev/null +++ b/vpi/lz4.h @@ -0,0 +1,323 @@ +/* + LZ4 - Fast LZ compression algorithm + Header File + Copyright (C) 2011-2014, Yann Collet. + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 source repository : http://code.google.com/p/lz4/ + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ +#pragma once + +#if defined (__cplusplus) +extern "C" { +#endif + +/* + * lz4.h provides raw compression format functions, for optimal performance and integration into programs. + * If you need to generate data using an inter-operable format (respecting the framing specification), + * please use lz4frame.h instead. +*/ + +/************************************** + Version +**************************************/ +#define LZ4_VERSION_MAJOR 1 /* for major interface/format changes */ +#define LZ4_VERSION_MINOR 3 /* for minor interface/format changes */ +#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */ +#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) +int LZ4_versionNumber (void); + +/************************************** + Tuning parameter +**************************************/ +/* + * LZ4_MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + * Increasing memory usage improves compression ratio + * Reduced memory usage can improve speed, due to cache effect + * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache + */ +#define LZ4_MEMORY_USAGE 14 + + +/************************************** + Simple Functions +**************************************/ + +int LZ4_compress (const char* source, char* dest, int sourceSize); +int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); + +/* +LZ4_compress() : + Compresses 'sourceSize' bytes from 'source' into 'dest'. + Destination buffer must be already allocated, + and must be sized to handle worst cases situations (input data not compressible) + Worst case size evaluation is provided by function LZ4_compressBound() + inputSize : Max supported value is LZ4_MAX_INPUT_SIZE + return : the number of bytes written in buffer dest + or 0 if the compression fails + +LZ4_decompress_safe() : + compressedSize : is obviously the source size + maxDecompressedSize : is the size of the destination buffer, which must be already allocated. + return : the number of bytes decompressed into the destination buffer (necessarily <= maxDecompressedSize) + If the destination buffer is not large enough, decoding will stop and output an error code (<0). + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function is protected against buffer overflow exploits, + and never writes outside of output buffer, nor reads outside of input buffer. + It is also protected against malicious data packets. +*/ + + +/************************************** + Advanced Functions +**************************************/ +#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ +#define LZ4_COMPRESSBOUND(isize) ((unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) + +/* +LZ4_compressBound() : + Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) + This function is primarily useful for memory allocation purposes (output buffer size). + Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). + + isize : is the input size. Max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) +*/ +int LZ4_compressBound(int isize); + + +/* +LZ4_compress_limitedOutput() : + Compress 'sourceSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'. + If it cannot achieve it, compression will stop, and result of the function will be zero. + This saves time and memory on detecting non-compressible (or barely compressible) data. + This function never writes outside of provided output buffer. + + sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE + maxOutputSize : is the size of the destination buffer (which must be already allocated) + return : the number of bytes written in buffer 'dest' + or 0 if compression fails +*/ +int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); + + +/* +LZ4_compress_withState() : + Same compression functions, but using an externally allocated memory space to store compression state. + Use LZ4_sizeofState() to know how much memory must be allocated, + and then, provide it as 'void* state' to compression functions. +*/ +int LZ4_sizeofState(void); +int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); +int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); + + +/* +LZ4_decompress_fast() : + originalSize : is the original and therefore uncompressed size + return : the number of bytes read from the source buffer (in other words, the compressed size) + If the source stream is detected malformed, the function will stop decoding and return a negative result. + Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. + note : This function fully respect memory boundaries for properly formed compressed data. + It is a bit faster than LZ4_decompress_safe(). + However, it does not provide any protection against intentionally modified data stream (malicious input). + Use this function in trusted environment only (data to decode comes from a trusted source). +*/ +int LZ4_decompress_fast (const char* source, char* dest, int originalSize); + + +/* +LZ4_decompress_safe_partial() : + This function decompress a compressed block of size 'compressedSize' at position 'source' + into destination buffer 'dest' of size 'maxDecompressedSize'. + The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, + reducing decompression time. + return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) + Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. + Always control how many bytes were decoded. + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets +*/ +int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); + + +/*********************************************** + Experimental Streaming Compression Functions +***********************************************/ + +#define LZ4_STREAMSIZE_U32 ((1 << (LZ4_MEMORY_USAGE-2)) + 8) +#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U32 * sizeof(unsigned int)) +/* + * LZ4_stream_t + * information structure to track an LZ4 stream. + * important : init this structure content before first use ! + */ +typedef struct { unsigned int table[LZ4_STREAMSIZE_U32]; } LZ4_stream_t; + +/* + * LZ4_resetStream + * Use this function to init an allocated LZ4_stream_t structure + */ +void LZ4_resetStream (LZ4_stream_t* LZ4_streamPtr); + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStream will allocate and initialize an LZ4_stream_t structure + * LZ4_freeStream releases its memory. + */ +LZ4_stream_t* LZ4_createStream(void); +int LZ4_freeStream (LZ4_stream_t* LZ4_stream); + +/* + * LZ4_loadDict + * Use this function to load a static dictionary into LZ4_stream. + * Any previous data will be forgotten, only 'dictionary' will remain in memory. + * Loading a size of 0 is allowed. + * Return : 1 if OK, 0 if error + */ +int LZ4_loadDict (LZ4_stream_t* LZ4_stream, const char* dictionary, int dictSize); + +/* + * LZ4_compress_continue + * Compress data block 'source', using blocks compressed before as dictionary to improve compression ratio + * Previous data blocks are assumed to still be present at their previous location. + */ +int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize); + +/* + * LZ4_compress_limitedOutput_continue + * Same as before, but also specify a maximum target compressed size (maxOutputSize) + * If objective cannot be met, compression exits, and returns a zero. + */ +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize); + +/* + * LZ4_saveDict + * If previously compressed data block is not guaranteed to remain available at its memory location + * save it into a safer place (char* safeBuffer) + * Note : you don't need to call LZ4_loadDict() afterwards, + * dictionary is immediately usable, you can therefore call again LZ4_compress_continue() + * Return : dictionary size in bytes, or 0 if error + * Note : any dictSize > 64 KB will be interpreted as 64KB. + */ +int LZ4_saveDict (LZ4_stream_t* LZ4_stream, char* safeBuffer, int dictSize); + + +/************************************************ + Experimental Streaming Decompression Functions +************************************************/ + +#define LZ4_STREAMDECODESIZE_U32 4 +#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U32 * sizeof(unsigned int)) +/* + * LZ4_streamDecode_t + * information structure to track an LZ4 stream. + * important : init this structure content using LZ4_setStreamDecode or memset() before first use ! + */ +typedef struct { unsigned int table[LZ4_STREAMDECODESIZE_U32]; } LZ4_streamDecode_t; + +/* + * LZ4_setStreamDecode + * Use this function to instruct where to find the dictionary. + * This function can be used to specify a static dictionary, + * or to instruct where to find some previously decoded data saved into a different memory space. + * Setting a size of 0 is allowed (same effect as no dictionary). + * Return : 1 if OK, 0 if error + */ +int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure + * LZ4_freeStreamDecode releases its memory. + */ +LZ4_streamDecode_t* LZ4_createStreamDecode(void); +int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); + +/* +*_continue() : + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks must still be available at the memory position where they were decoded. + If it's not possible, save the relevant part of decoded data into a safe buffer, + and indicate where its new address using LZ4_setStreamDecode() +*/ +int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); + + +/* +Advanced decoding functions : +*_usingDict() : + These decoding functions work the same as + a combination of LZ4_setDictDecode() followed by LZ4_decompress_x_continue() + They don't use nor update an LZ4_streamDecode_t structure. +*/ +int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); +int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); + + + +/************************************** + Obsolete Functions +**************************************/ +/* +Obsolete decompression functions +These function names are deprecated and should no longer be used. +They are only provided here for compatibility with older user programs. +- LZ4_uncompress is the same as LZ4_decompress_fast +- LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe +These function prototypes are now disabled; uncomment them if you really need them. +It is highly recommended to stop using these functions and migrated to newer ones */ +/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */ +/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */ + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStreamDecode() + * provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure. + * LZ4_free just frees it. + */ +/* void* LZ4_createStreamDecode(void); */ +/*int LZ4_free (void* LZ4_stream); yes, it's the same one as for compression */ + +/* Obsolete streaming functions; use new streaming interface whenever possible */ +void* LZ4_create (const char* inputBuffer); +int LZ4_sizeofStreamState(void); +int LZ4_resetStreamState(void* state, const char* inputBuffer); +char* LZ4_slideInputBuffer (void* state); + +/* Obsolete streaming decoding functions */ +int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int compressedSize, int maxOutputSize); +int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int originalSize); + + +#if defined (__cplusplus) +} +#endif diff --git a/vpi/sdf_lexor.lex b/vpi/sdf_lexor.lex index 523550db9..0b8c7767e 100644 --- a/vpi/sdf_lexor.lex +++ b/vpi/sdf_lexor.lex @@ -5,7 +5,7 @@ %{ /* - * Copyright (c) 2007-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2014 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 @@ -107,6 +107,11 @@ static int yywrap(void) "===" { return K_CEQ; } "!==" { return K_CNE; } + /* Other operators. */ + +"&&" { return K_LAND; } +"||" { return K_LOR; } + /* The HCHAR (hierarchy separator) is set by the SDF file itself. We recognize here the HCHAR. */ [./] { @@ -124,34 +129,36 @@ static struct { const char*name; int code; } keywords[] = { - { "ABSOLUTE", K_ABSOLUTE }, - { "CELL", K_CELL }, - { "CELLTYPE", K_CELLTYPE }, - { "DATE", K_DATE }, - { "DELAY", K_DELAY }, - { "DELAYFILE", K_DELAYFILE }, - { "DESIGN", K_DESIGN }, - { "DIVIDER", K_DIVIDER }, - { "HOLD", K_HOLD }, - { "INCREMENT", K_INCREMENT }, - { "INTERCONNECT",K_INTERCONNECT }, - { "INSTANCE", K_INSTANCE }, - { "IOPATH", K_IOPATH }, - { "PROCESS", K_PROCESS }, - { "PROGRAM", K_PROGRAM }, - { "RECREM", K_RECREM }, - { "RECOVERY", K_RECOVERY }, - { "REMOVAL", K_REMOVAL }, - { "SDFVERSION", K_SDFVERSION }, - { "SETUP", K_SETUP }, - { "SETUPHOLD", K_SETUPHOLD }, - { "TEMPERATURE",K_TEMPERATURE }, - { "TIMESCALE", K_TIMESCALE }, - { "TIMINGCHECK",K_TIMINGCHECK }, - { "VENDOR", K_VENDOR }, - { "VERSION", K_VERSION }, - { "VOLTAGE", K_VOLTAGE }, - { "WIDTH", K_WIDTH }, + { "ABSOLUTE", K_ABSOLUTE }, + { "CELL", K_CELL }, + { "CELLTYPE", K_CELLTYPE }, + { "DATE", K_DATE }, + { "COND", K_COND }, + { "CONDELSE", K_CONDELSE }, + { "DELAY", K_DELAY }, + { "DELAYFILE", K_DELAYFILE }, + { "DESIGN", K_DESIGN }, + { "DIVIDER", K_DIVIDER }, + { "HOLD", K_HOLD }, + { "INCREMENT", K_INCREMENT }, + { "INTERCONNECT", K_INTERCONNECT }, + { "INSTANCE", K_INSTANCE }, + { "IOPATH", K_IOPATH }, + { "PROCESS", K_PROCESS }, + { "PROGRAM", K_PROGRAM }, + { "RECREM", K_RECREM }, + { "RECOVERY", K_RECOVERY }, + { "REMOVAL", K_REMOVAL }, + { "SDFVERSION", K_SDFVERSION }, + { "SETUP", K_SETUP }, + { "SETUPHOLD", K_SETUPHOLD }, + { "TEMPERATURE", K_TEMPERATURE }, + { "TIMESCALE", K_TIMESCALE }, + { "TIMINGCHECK", K_TIMINGCHECK }, + { "VENDOR", K_VENDOR }, + { "VERSION", K_VERSION }, + { "VOLTAGE", K_VOLTAGE }, + { "WIDTH", K_WIDTH }, { 0, IDENTIFIER } }; @@ -206,7 +213,7 @@ static void process_quoted_string(void) /* * Modern version of flex (>=2.5.9) can clean up the scanner data. */ -static void destroy_sdf_lexor() +static void destroy_sdf_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 diff --git a/vpi/sdf_parse.y b/vpi/sdf_parse.y index 793ad120c..0cb7b2045 100644 --- a/vpi/sdf_parse.y +++ b/vpi/sdf_parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -44,13 +44,15 @@ char sdf_use_hchar = '.'; struct sdf_delval_list_s delval_list; }; -%token K_ABSOLUTE K_CELL K_CELLTYPE K_COND K_DATE K_DELAYFILE K_DELAY K_DESIGN -%token K_DIVIDER K_HOLD K_INCREMENT K_INSTANCE K_INTERCONNECT K_IOPATH -%token K_NEGEDGE K_POSEDGE K_PROCESS K_PROGRAM K_RECREM K_RECOVERY -%token K_REMOVAL K_SDFVERSION K_SETUP K_SETUPHOLD K_TEMPERATURE -%token K_TIMESCALE K_TIMINGCHECK K_VENDOR K_VERSION K_VOLTAGE K_WIDTH +%token K_ABSOLUTE K_CELL K_CELLTYPE K_COND K_CONDELSE K_DATE K_DELAYFILE +%token K_DELAY K_DESIGN K_DIVIDER K_HOLD K_INCREMENT K_INSTANCE +%token K_INTERCONNECT K_IOPATH K_NEGEDGE K_POSEDGE K_PROCESS K_PROGRAM +%token K_RECREM K_RECOVERY K_REMOVAL K_SDFVERSION K_SETUP K_SETUPHOLD +%token K_TEMPERATURE K_TIMESCALE K_TIMINGCHECK K_VENDOR K_VERSION +%token K_VOLTAGE K_WIDTH %token K_01 K_10 K_0Z K_Z1 K_1Z K_Z0 %token K_EQ K_NE K_CEQ K_CNE K_LOGICAL_ONE K_LOGICAL_ZERO +%token K_LAND K_LOR %token HCHAR %token QSTRING IDENTIFIER @@ -70,6 +72,10 @@ char sdf_use_hchar = '.'; %type delval_list +%left K_LOR +%left K_LAND +%left K_EQ K_NE K_CEQ K_CNE + %% source_file @@ -261,6 +267,36 @@ del_def | '(' K_IOPATH error ')' { vpi_printf("%s:%d: SDF ERROR: Invalid/malformed IOPATH\n", sdf_parse_path, @2.first_line); } + | '(' K_COND conditional_port_expr + '(' K_IOPATH port_spec port_instance delval_list ')' ')' + { if (sdf_flag_warning) vpi_printf("%s:%d: SDF WARNING: " + "COND not supported.\n", + sdf_parse_path, @2.first_line); + free($6.string_val); + free($7); + } + | '(' K_COND QSTRING conditional_port_expr + '(' K_IOPATH port_spec port_instance delval_list ')' ')' + { if (sdf_flag_warning) vpi_printf("%s:%d: SDF WARNING: " + "COND not supported.\n", + sdf_parse_path, @2.first_line); + free($3); + free($7.string_val); + free($8); + } + | '(' K_COND error ')' + { vpi_printf("%s:%d: SDF ERROR: Invalid/malformed COND\n", + sdf_parse_path, @2.first_line); } + | '(' K_CONDELSE '(' K_IOPATH port_spec port_instance delval_list ')' ')' + { if (sdf_flag_warning) vpi_printf("%s:%d: SDF WARNING: " + "CONDELSE not supported.\n", + sdf_parse_path, @2.first_line); + free($5.string_val); + free($6); + } + | '(' K_CONDELSE error ')' + { vpi_printf("%s:%d: SDF ERROR: Invalid/malformed CONDELSE\n", + sdf_parse_path, @2.first_line); } /* | '(' K_INTERCONNECT port_instance port_instance delval_list ')' */ | '(' K_INTERCONNECT port_interconnect port_interconnect delval_list ')' { if (sdf_flag_warning) vpi_printf("%s:%d: SDF WARNING: " @@ -292,11 +328,17 @@ tchk_def port_tchk : port_instance + { free($1); } /* This must only be an edge. For now we just accept everything. */ | cond_edge_start port_instance ')' + { free($2); } /* These must only be a cond. For now we just accept everything. */ | cond_edge_start timing_check_condition port_spec ')' + { free($3.string_val); } | cond_edge_start QSTRING timing_check_condition port_spec ')' + { free($2); + free($4.string_val); + } ; cond_edge_start @@ -317,9 +359,27 @@ cond_edge_identifier timing_check_condition : port_interconnect + { free($1); } | '~' port_interconnect + { free($2); } | '!' port_interconnect + { free($2); } | port_interconnect equality_operator scalar_constant + { free($1); } + ; + + /* This is not complete! */ +conditional_port_expr + : port + { free($1); } + | scalar_constant + | '(' conditional_port_expr ')' + | conditional_port_expr K_LAND conditional_port_expr + | conditional_port_expr K_LOR conditional_port_expr + | conditional_port_expr K_EQ conditional_port_expr + | conditional_port_expr K_NE conditional_port_expr + | conditional_port_expr K_CEQ conditional_port_expr + | conditional_port_expr K_CNE conditional_port_expr ; equality_operator diff --git a/vpi/sdf_parse_priv.h b/vpi/sdf_parse_priv.h index 325071270..80a9f99ec 100644 --- a/vpi/sdf_parse_priv.h +++ b/vpi/sdf_parse_priv.h @@ -1,7 +1,7 @@ -#ifndef _sdf_parse_priv_h -#define _sdf_parse_priv_h +#ifndef IVL_sdf_parse_priv_h +#define IVL_sdf_parse_priv_h /* - * Copyright (c) 2007-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -38,4 +38,4 @@ extern char sdf_use_hchar; extern void start_edge_id(unsigned cond); extern void stop_edge_id(void); -#endif +#endif /* IVL_sdf_parse_priv_h */ diff --git a/vpi/sdf_priv.h b/vpi/sdf_priv.h index ceec94af8..9a0dc9882 100644 --- a/vpi/sdf_priv.h +++ b/vpi/sdf_priv.h @@ -1,7 +1,7 @@ -#ifndef _sdf_priv_h -#define _sdf_priv_h +#ifndef IVL_sdf_priv_h +#define IVL_sdf_priv_h /* - * Copyright (c) 2007-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2014 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 @@ -52,4 +52,4 @@ extern void sdf_select_instance(const char*celltype, const char*inst); extern void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, const struct sdf_delval_list_s*delval); -#endif +#endif /* IVL_sdf_priv_h */ diff --git a/vpi/stringheap.h b/vpi/stringheap.h index af34522d9..aa185365b 100644 --- a/vpi/stringheap.h +++ b/vpi/stringheap.h @@ -1,7 +1,7 @@ -#ifndef __stringheap_H -#define __stringheap_H +#ifndef IVL_stringheap_H +#define IVL_stringheap_H /* - * Copyright (c) 2003-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 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 @@ -33,4 +33,4 @@ const char*strdup_sh(struct stringheap_s*hp, const char*str); void string_heap_delete(struct stringheap_s*hp); -#endif +#endif /* IVL_stringheap_H */ diff --git a/vpi/sys_clog2.c b/vpi/sys_clog2.c index e19aeecc4..84a685271 100644 --- a/vpi/sys_clog2.c +++ b/vpi/sys_clog2.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2008-2014 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 @@ -71,7 +71,7 @@ static PLI_INT32 sys_clog2_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) assert(callh != 0); argv = vpi_iterate(vpiArgument, callh); - (void) name; /* Not used! */ + (void)name; /* Parameter is not used. */ /* We must have an argument. */ if (argv == 0) { @@ -120,7 +120,7 @@ static PLI_INT32 sys_clog2_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) vpiHandle arg; s_vpi_value val; s_vpi_vecval vec; - (void) name; /* Not used! */ + (void)name; /* Parameter is not used. */ /* Get the argument. */ arg = vpi_scan(argv); diff --git a/vpi/sys_convert.c b/vpi/sys_convert.c index 01f12013f..389e3c764 100644 --- a/vpi/sys_convert.c +++ b/vpi/sys_convert.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2013 Michael Ruff (mruff at chiaro.com) + * Copyright (c) 2003-2014 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 @@ -90,8 +90,16 @@ static void error_message(vpiHandle callh, const char* msg) vpi_control(vpiFinish, 1); } -static PLI_INT32 sizetf_32 (PLI_BYTE8*x) { return 32; } -static PLI_INT32 sizetf_64 (PLI_BYTE8*x) { return 64; } +static PLI_INT32 sizetf_32 (PLI_BYTE8*name) +{ + (void)name; /* Parameter is not used. */ + return 32; +} +static PLI_INT32 sizetf_64 (PLI_BYTE8*name) +{ + (void)name; /* Parameter is not used. */ + return 64; +} static PLI_INT32 sys_convert_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { @@ -123,7 +131,7 @@ static PLI_INT32 sys_convert_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -static PLI_INT32 sys_bitstoreal_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) +static PLI_INT32 sys_bitstoreal_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); @@ -131,6 +139,8 @@ static PLI_INT32 sys_bitstoreal_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) PLI_UINT32 bits[2]; + (void)name; /* Parameter is not used. */ + /* get value */ value.format = vpiVectorVal; vpi_get_value(arg, &value); @@ -147,12 +157,14 @@ static PLI_INT32 sys_bitstoreal_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) return 0; } -static PLI_INT32 sys_itor_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) +static PLI_INT32 sys_itor_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); s_vpi_value value; + (void)name; /* Parameter is not used. */ + /* get value */ value.format = vpiIntVal; vpi_get_value(arg, &value); @@ -167,7 +179,7 @@ static PLI_INT32 sys_itor_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) return 0; } -static PLI_INT32 sys_realtobits_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) +static PLI_INT32 sys_realtobits_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); @@ -176,6 +188,8 @@ static PLI_INT32 sys_realtobits_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) PLI_UINT32 bits[2]; + (void)name; /* Parameter is not used. */ + /* get value */ value.format = vpiRealVal; vpi_get_value(arg, &value); @@ -197,7 +211,7 @@ static PLI_INT32 sys_realtobits_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) return 0; } -static PLI_INT32 sys_rtoi_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) +static PLI_INT32 sys_rtoi_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); @@ -205,6 +219,8 @@ static PLI_INT32 sys_rtoi_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) static struct t_vpi_vecval res; double val; + (void)name; /* Parameter is not used. */ + /* get value */ value.format = vpiRealVal; vpi_get_value(arg, &value); @@ -231,7 +247,7 @@ static PLI_INT32 sys_rtoi_calltf(ICARUS_VPI_CONST PLI_BYTE8*user) return 0; } -void sys_convert_register() +void sys_convert_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_countdrivers.c b/vpi/sys_countdrivers.c index 304672ec8..3eedc431e 100644 --- a/vpi/sys_countdrivers.c +++ b/vpi/sys_countdrivers.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Martin Whitaker. (icarus@martin-whitaker.me.uk) + * Copyright (C) 2012-2014 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 @@ -102,7 +102,7 @@ static PLI_INT32 sys_countdrivers_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) /* The optional arguments must be variables. */ for (arg_num = 2; arg_num < 7; arg_num += 1) { - char *arg_name = NULL; + const char *arg_name = NULL; switch (arg_num) { case 2: arg_name = "second"; break; case 3: arg_name = "third"; break; @@ -137,6 +137,8 @@ static PLI_INT32 sys_countdrivers_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) unsigned num_drivers; s_vpi_value val; + (void)name; /* Parameter is not used. */ + /* All returned values are integers. */ val.format = vpiIntVal; @@ -196,7 +198,7 @@ args_done: /* * Routine to register the system tasks/functions provided in this file. */ -void sys_countdrivers_register() +void sys_countdrivers_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_darray.c b/vpi/sys_darray.c index 3031252a3..7038ab05e 100644 --- a/vpi/sys_darray.c +++ b/vpi/sys_darray.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 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 @@ -57,6 +57,8 @@ static PLI_INT32 size_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpiHandle argv; vpiHandle arg; + (void)name; /* Parameter is not used. */ + argv = vpi_iterate(vpiArgument, callh); assert(argv); arg = vpi_scan(argv); @@ -81,11 +83,11 @@ void sys_darray_register(void) tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; - tf_data.tfname = "$ivl_darray_method$size"; + tf_data.tfname = "$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"; + tf_data.user_data = "$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 f2f95f562..222f94487 100644 --- a/vpi/sys_deposit.c +++ b/vpi/sys_deposit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) * Copyright (c) 2000 Stephan Boettcher * * This source code is free software; you can redistribute it @@ -74,6 +74,8 @@ static PLI_INT32 sys_deposit_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) vpiHandle callh, argv, target, value; s_vpi_value val; + (void)name; /* Parameter is not used. */ + callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); target = vpi_scan(argv); @@ -90,7 +92,7 @@ static PLI_INT32 sys_deposit_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } -void sys_deposit_register() +void sys_deposit_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_display.c b/vpi/sys_display.c index ba6b2a4e0..4cfdfcbdb 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -38,7 +38,7 @@ static void check_command_line_args(void) vpi_get_vlog_info(&vlog_info); - for (unsigned idx = 0 ; idx < vlog_info.argc ; idx += 1) { + for (int idx = 0 ; idx < vlog_info.argc ; idx += 1) { if (strcmp(vlog_info.argv[idx],"-compatible") == 0) { compatible_flag = 1; @@ -690,7 +690,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", info->filename, info->lineno, info->name, fmtb); } else { - PLI_INT32 veclen, word, byte, bits; + PLI_INT32 veclen, word, byte; char *cp; veclen = (vpi_get(vpiSize, info->items[*idx])+31)/32; @@ -699,7 +699,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, if (size > ini_size) result = realloc(result, size*sizeof(char)); cp = result; for (word = 0; word < veclen; word += 1) { - bits = value.value.vector[word].aval & + PLI_INT32 bits = value.value.vector[word].aval & ~value.value.vector[word].bval; #ifdef WORDS_BIGENDIAN for (byte = 3; byte >= 0; byte -= 1) { @@ -1399,6 +1399,8 @@ static PLI_INT32 monitor_cb_2(p_cb_data cb) char* result; unsigned int size, location=0; + (void)cb; /* Parameter is not used. */ + /* Because %u and %z may put embedded NULL characters into the * returned string strlen() may not match the real size! */ result = get_display(&size, &monitor_info); @@ -1428,6 +1430,8 @@ static PLI_INT32 monitor_cb_1(p_cb_data cause) struct t_cb_data cb; struct t_vpi_time timerec; + (void)cause; /* Parameter is not used. */ + if (monitor_enabled == 0) return 0; if (monitor_scheduled) return 0; @@ -1465,6 +1469,8 @@ static PLI_INT32 sys_monitor_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) struct t_cb_data cb; struct t_vpi_time timerec; + (void)name; /* Parameter is not used. */ + callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -1544,6 +1550,7 @@ static PLI_INT32 sys_monitor_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static PLI_INT32 sys_monitoron_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void)name; /* Parameter is not used. */ monitor_enabled = 1; monitor_cb_1(0); return 0; @@ -1551,6 +1558,7 @@ static PLI_INT32 sys_monitoron_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static PLI_INT32 sys_monitoroff_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void)name; /* Parameter is not used. */ monitor_enabled = 0; return 0; } @@ -1722,6 +1730,7 @@ static PLI_INT32 sys_sformat_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) static PLI_INT32 sys_end_of_compile(p_cb_data cb_data) { + (void)cb_data; /* Parameter is not used. */ /* The default timeformat prints times in unit of simulation precision. */ free(timeformat_info.suff); @@ -1808,12 +1817,14 @@ static PLI_INT32 sys_timeformat_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -static PLI_INT32 sys_timeformat_calltf(ICARUS_VPI_CONST PLI_BYTE8*xx) +static PLI_INT32 sys_timeformat_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { s_vpi_value value; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); + (void)name; /* Parameter is not used. */ + if (argv) { vpiHandle units = vpi_scan(argv); vpiHandle prec = vpi_scan(argv); @@ -1920,11 +1931,14 @@ static PLI_INT32 sys_printtimescale_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -static PLI_INT32 sys_printtimescale_calltf(ICARUS_VPI_CONST PLI_BYTE8*xx) +static PLI_INT32 sys_printtimescale_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle item, scope; + + (void)name; /* Parameter is not used. */ + if (!argv) { item = sys_func_module(callh); } else { @@ -2049,6 +2063,7 @@ static PLI_INT32 sys_severity_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static PLI_INT32 sys_end_of_simulation(p_cb_data cb_data) { + (void)cb_data; /* Parameter is not used. */ free(monitor_callbacks); monitor_callbacks = 0; free(monitor_info.filename); @@ -2062,7 +2077,7 @@ static PLI_INT32 sys_end_of_simulation(p_cb_data cb_data) return 0; } -void sys_display_register() +void sys_display_register(void) { s_cb_data cb_data; s_vpi_systf_data tf_data; diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index b503d4f81..ec99c9f00 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -1056,7 +1056,7 @@ static PLI_INT32 sys_ferror_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } -void sys_fileio_register() +void sys_fileio_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_finish.c b/vpi/sys_finish.c index 642765621..cc3a88326 100644 --- a/vpi/sys_finish.c +++ b/vpi/sys_finish.c @@ -46,7 +46,7 @@ static PLI_INT32 sys_finish_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } -void sys_finish_register() +void sys_finish_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_fst.c b/vpi/sys_fst.c index 56f3f84c5..1ed7b7fa0 100644 --- a/vpi/sys_fst.c +++ b/vpi/sys_fst.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -112,8 +112,8 @@ static void show_this_item_x(struct vcd_info*info) * managed qsorted list of scope names/variables for duplicates bsearching */ -struct vcd_names_list_s fst_tab = { 0 }; -struct vcd_names_list_s fst_var = { 0 }; +struct vcd_names_list_s fst_tab = { 0, 0, 0, 0 }; +struct vcd_names_list_s fst_var = { 0, 0, 0, 0 }; static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ @@ -127,7 +127,7 @@ __inline__ static int dump_header_pending(void) * This function writes out all the traced variables, whether they * changed or not. */ -static void vcd_checkpoint() +static void vcd_checkpoint(void) { struct vcd_info*cur; @@ -135,7 +135,7 @@ static void vcd_checkpoint() show_this_item(cur); } -static void vcd_checkpoint_x() +static void vcd_checkpoint_x(void) { struct vcd_info*cur; @@ -282,6 +282,8 @@ static PLI_INT32 sys_dumpoff_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (dump_is_off) return 0; dump_is_off = 1; @@ -309,6 +311,8 @@ static PLI_INT32 sys_dumpon_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (!dump_is_off) return 0; dump_is_off = 0; @@ -336,6 +340,8 @@ static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (dump_is_off) return 0; if (dump_file == 0) return 0; if (dump_header_pending()) return 0; @@ -443,6 +449,7 @@ static PLI_INT32 sys_dumpfile_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static PLI_INT32 sys_dumpflush_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void)name; /* Parameter is not used. */ if (dump_file) fstWriterFlushContext(dump_file); return 0; @@ -454,6 +461,8 @@ static PLI_INT32 sys_dumplimit_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) vpiHandle argv = vpi_iterate(vpiArgument, callh); s_vpi_value val; + (void)name; /* Parameter is not used. */ + /* Get the value and set the dump limit. */ val.format = vpiIntVal; vpi_get_value(vpi_scan(argv), &val); @@ -787,6 +796,8 @@ static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_value value; unsigned depth = 0; + (void)name; /* Parameter is not used. */ + if (dump_file == 0) { open_dumpfile(callh); if (dump_file == 0) { @@ -879,7 +890,7 @@ static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -void sys_fst_register() +void sys_fst_register(void) { int idx; struct t_vpi_vlog_info vlog_info; diff --git a/vpi/sys_lxt.c b/vpi/sys_lxt.c index 66d5d5e24..86068a8ee 100644 --- a/vpi/sys_lxt.c +++ b/vpi/sys_lxt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2014 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 @@ -354,6 +354,8 @@ static PLI_INT32 sys_dumpoff_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (dump_is_off) return 0; dump_is_off = 1; @@ -381,6 +383,8 @@ static PLI_INT32 sys_dumpon_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (!dump_is_off) return 0; dump_is_off = 0; @@ -408,6 +412,8 @@ static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (dump_is_off) return 0; if (dump_file == 0) return 0; if (dump_header_pending()) return 0; @@ -501,6 +507,7 @@ static PLI_INT32 sys_dumpfile_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) */ static PLI_INT32 sys_dumpflush_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void)name; /* Parameter is not used. */ return 0; } @@ -510,6 +517,8 @@ static PLI_INT32 sys_dumplimit_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) vpiHandle argv = vpi_iterate(vpiArgument, callh); s_vpi_value val; + (void)name; /* Parameter is not used. */ + /* Get the value and set the dump limit. */ val.format = vpiIntVal; vpi_get_value(vpi_scan(argv), &val); @@ -727,6 +736,8 @@ static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_value value; unsigned depth = 0; + (void)name; /* Parameter is not used. */ + if (dump_file == 0) { open_dumpfile(callh); if (dump_file == 0) { diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index f2f1839e2..8babb0382 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 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 @@ -254,12 +254,12 @@ __inline__ static int dump_header_pending(void) * This function writes out all the traced variables, whether they * changed or not. */ -static void vcd_checkpoint() +static void vcd_checkpoint(void) { functor_all_vcd_info( show_this_item ); } -static void vcd_checkpoint_x() +static void vcd_checkpoint_x(void) { functor_all_vcd_info( show_this_item_x ); } @@ -392,6 +392,8 @@ static PLI_INT32 sys_dumpoff_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (dump_is_off) return 0; dump_is_off = 1; @@ -419,6 +421,8 @@ static PLI_INT32 sys_dumpon_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (!dump_is_off) return 0; dump_is_off = 0; @@ -446,6 +450,8 @@ static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (dump_is_off) return 0; if (dump_file == 0) return 0; if (dump_header_pending()) return 0; @@ -561,6 +567,7 @@ static PLI_INT32 sys_dumpfile_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) */ static PLI_INT32 sys_dumpflush_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void)name; /* Parameter is not used. */ if (dump_file) vcd_work_flush(); return 0; @@ -572,6 +579,8 @@ static PLI_INT32 sys_dumplimit_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) vpiHandle argv = vpi_iterate(vpiArgument, callh); s_vpi_value val; + (void)name; /* Parameter is not used. */ + /* Get the value and set the dump limit. */ assert(argv); val.format = vpiIntVal; @@ -782,6 +791,8 @@ static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_value value; unsigned depth = 0; + (void)name; /* Parameter is not used. */ + if (dump_file == 0) { open_dumpfile(callh); if (dump_file == 0) { @@ -834,6 +845,9 @@ static void* lxt2_thread(void*arg) function when the time changes. */ uint64_t cur_time = 0; int run_flag = 1; + + (void)arg; /* Parameter is not used. */ + while (run_flag) { struct vcd_work_item_s*cell = vcd_work_thread_peek(); @@ -873,7 +887,7 @@ static void* lxt2_thread(void*arg) return 0; } -void sys_lxt2_register() +void sys_lxt2_register(void) { int idx; struct t_vpi_vlog_info vlog_info; diff --git a/vpi/sys_plusargs.c b/vpi/sys_plusargs.c index 7f7935aee..f060277cd 100644 --- a/vpi/sys_plusargs.c +++ b/vpi/sys_plusargs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -35,6 +35,8 @@ static PLI_INT32 sys_test_plusargs_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) int flag = 0; size_t slen, len; + (void)name; /* Parameter is not used. */ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); @@ -381,7 +383,7 @@ static PLI_INT32 sys_value_plusargs_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -void sys_plusargs_register() +void sys_plusargs_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_priv.h b/vpi/sys_priv.h index ce08ba573..36553b250 100644 --- a/vpi/sys_priv.h +++ b/vpi/sys_priv.h @@ -1,7 +1,7 @@ -#ifndef __vpi_sys_priv_H -#define __vpi_sys_priv_H +#ifndef IVL_sys_priv_H +#define IVL_sys_priv_H /* - * Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2014 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 @@ -65,4 +65,4 @@ extern PLI_INT32 sys_one_opt_numeric_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *n extern PLI_INT32 sys_two_numeric_args_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); extern PLI_INT32 sys_one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); -#endif +#endif /* IVL_sys_priv_H */ diff --git a/vpi/sys_queue.c b/vpi/sys_queue.c index 4f1dc0e25..3d34c7b4a 100644 --- a/vpi/sys_queue.c +++ b/vpi/sys_queue.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2014 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 @@ -57,7 +57,7 @@ /* * Routine to add the given time to the the total time (high/low). */ -void add_to_wait_time(uint64_t *high, uint64_t *low, uint64_t c_time) +static void add_to_wait_time(uint64_t *high, uint64_t *low, uint64_t c_time) { uint64_t carry = 0U; @@ -71,7 +71,7 @@ void add_to_wait_time(uint64_t *high, uint64_t *low, uint64_t c_time) * Routine to divide the given total time (high/low) by the number of * items to get the average. */ -uint64_t calc_average_wait_time(uint64_t high, uint64_t low, uint64_t total) +static uint64_t calc_average_wait_time(uint64_t high, uint64_t low, uint64_t total) { int bit = 64; uint64_t result = 0U; @@ -433,7 +433,7 @@ static uint64_t get_average_wait_time(int64_t idx) uint64_t high = base[idx].wait_time_high; uint64_t low = base[idx].wait_time_low; s_vpi_time cur_time; - uint64_t c_time, add_time; + uint64_t c_time; /* Get the current simulation time. */ cur_time.type = vpiSimTime; @@ -445,7 +445,7 @@ static uint64_t get_average_wait_time(int64_t idx) /* For each element still in the queue, add its wait time to the * total wait time. */ for (count = 0; count < elems; count += 1) { - add_time = base[idx].queue[loc].time; + uint64_t add_time = base[idx].queue[loc].time; assert(c_time >= add_time); add_to_wait_time(&high, &low, c_time-add_time); @@ -587,7 +587,7 @@ static unsigned check_numeric_args(vpiHandle argv, unsigned count, /* Check that the first count arguments are numeric. Currently * only three are needed/supported. */ for (idx = 0; idx < count; idx += 1) { - char *loc = NULL; + const char *loc = NULL; vpiHandle arg = vpi_scan(argv); /* Get the name for this argument. */ @@ -720,7 +720,7 @@ static PLI_INT32 fill_variable_with_scaled_time(vpiHandle var, uint64_t c_time) uint64_t max_val = 0; uint64_t scale = 1; uint64_t frac; - PLI_INT32 rtn, idx, units, prec; + PLI_INT32 rtn, units, prec; p_vpi_vecval val_ptr = (p_vpi_vecval) malloc(words*sizeof(s_vpi_vecval)); assert(val_ptr); @@ -773,7 +773,7 @@ static PLI_INT32 fill_variable_with_scaled_time(vpiHandle var, uint64_t c_time) rtn = IVL_QUEUE_VALUE_OVERFLOWED; } else { /* Fill the vector with 0. */ - for (idx = 0; idx < words; idx += 1) { + for (PLI_INT32 idx = 0; idx < words; idx += 1) { val_ptr[idx].aval = 0x00000000; val_ptr[idx].bval = 0x00000000; } @@ -848,6 +848,8 @@ static PLI_INT32 sys_q_initialize_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; unsigned invalid_id, invalid_type, invalid_length; + (void)name; /* Parameter is not used. */ + /* Get the id. */ invalid_id = get_valid_32(vpi_scan(argv), &id); @@ -965,6 +967,8 @@ static PLI_INT32 sys_q_add_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; unsigned invalid_id; + (void)name; /* Parameter is not used. */ + /* Get the id. */ invalid_id = get_valid_32(vpi_scan(argv), &id); @@ -1086,6 +1090,8 @@ static PLI_INT32 sys_q_remove_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; unsigned invalid_id; + (void)name; /* Parameter is not used. */ + /* Get the id. */ invalid_id = get_valid_32(vpi_scan(argv), &id); @@ -1193,6 +1199,8 @@ static PLI_INT32 sys_q_full_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; unsigned invalid_id; + (void)name; /* Parameter is not used. */ + /* Get the id. */ invalid_id = get_valid_32(vpi_scan(argv), &id); @@ -1289,6 +1297,8 @@ static PLI_INT32 sys_q_exam_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; unsigned invalid_id, invalid_code; + (void)name; /* Parameter is not used. */ + /* Get the id. */ invalid_id = get_valid_32(vpi_scan(argv), &id); @@ -1393,7 +1403,7 @@ static PLI_INT32 sys_q_exam_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) /* * Routine to register the system tasks/functions provided in this file. */ -void sys_queue_register() +void sys_queue_register(void) { s_vpi_systf_data tf_data; s_cb_data cb; diff --git a/vpi/sys_random.c b/vpi/sys_random.c index b8c68e1ce..f774764a6 100644 --- a/vpi/sys_random.c +++ b/vpi/sys_random.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -41,7 +41,7 @@ static double chi_square(long *seed, long deg_of_free); static double t(long *seed, long deg_of_free); static double erlangian(long *seed, long k, long mean); -long rtl_dist_chi_square(long *seed, long df) +static long rtl_dist_chi_square(long *seed, long df) { double r; long i; @@ -64,7 +64,7 @@ long rtl_dist_chi_square(long *seed, long df) return i; } -long rtl_dist_erlang(long *seed, long k, long mean) +static long rtl_dist_erlang(long *seed, long k, long mean) { double r; long i; @@ -87,7 +87,7 @@ long rtl_dist_erlang(long *seed, long k, long mean) return i; } -long rtl_dist_exponential(long *seed, long mean) +static long rtl_dist_exponential(long *seed, long mean) { double r; long i; @@ -110,7 +110,7 @@ long rtl_dist_exponential(long *seed, long mean) return i; } -long rtl_dist_normal(long *seed, long mean, long sd) +static long rtl_dist_normal(long *seed, long mean, long sd) { double r; long i; @@ -127,7 +127,7 @@ long rtl_dist_normal(long *seed, long mean, long sd) return i; } -long rtl_dist_poisson(long *seed, long mean) +static long rtl_dist_poisson(long *seed, long mean) { long i; @@ -142,7 +142,7 @@ long rtl_dist_poisson(long *seed, long mean) return i; } -long rtl_dist_t(long *seed, long df) +static long rtl_dist_t(long *seed, long df) { double r; long i; @@ -166,7 +166,7 @@ long rtl_dist_t(long *seed, long df) } /* copied from IEEE1364-2001, with slight modifications for 64bit machines. */ -long rtl_dist_uniform(long *seed, long start, long end) +static long rtl_dist_uniform(long *seed, long start, long end) { double r; long i; @@ -527,6 +527,8 @@ static PLI_INT32 sys_random_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) static long i_seed = 0; long a_seed; + (void)name; /* Parameter is not used. */ + /* Get the argument list and look for a seed. If it is there, get the value and reseed the random number generator. */ callh = vpi_handle(vpiSysTfCall, 0); @@ -552,7 +554,7 @@ static PLI_INT32 sys_random_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } -/* From System Verilog 3.1a. */ +/* From SystemVerilog. */ static PLI_INT32 sys_urandom_range_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); @@ -561,20 +563,17 @@ static PLI_INT32 sys_urandom_range_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) /* Check that there are arguments. */ if (argv == 0) { - vpi_printf("ERROR: %s requires two arguments.\n", name); + vpi_printf("ERROR: %s requires one or two arguments.\n", name); vpi_control(vpiFinish, 1); return 0; } - /* Check that there are at least two arguments. */ + /* Check that there is at least one argument. */ arg = vpi_scan(argv); /* This should never be zero. */ assert(arg); arg = vpi_scan(argv); - if (arg == 0) { - vpi_printf("ERROR: %s requires two arguments.\n", name); - vpi_control(vpiFinish, 1); - return 0; - } + /* Is this a single argument function call? */ + if (arg == 0) return 0; /* These functions takes at most two argument. */ arg = vpi_scan(argv); @@ -588,7 +587,7 @@ static PLI_INT32 sys_urandom_range_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } -/* From System Verilog 3.1a. */ +/* From SystemVerilog. */ static unsigned long urandom(long *seed, unsigned long max, unsigned long min) { static long i_seed = 0; @@ -603,13 +602,15 @@ static unsigned long urandom(long *seed, unsigned long max, unsigned long min) return result; } -/* From System Verilog 3.1a. */ +/* From SystemVerilog. */ static PLI_INT32 sys_urandom_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh, argv, seed = 0; s_vpi_value val; long i_seed; + (void)name; /* Parameter is not used. */ + /* Get the argument list and look for a seed. If it is there, get the value and reseed the random number generator. */ callh = vpi_handle(vpiSysTfCall, 0); @@ -639,13 +640,15 @@ static PLI_INT32 sys_urandom_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } -/* From System Verilog 3.1a. */ +/* From SystemVerilog. */ static PLI_INT32 sys_urandom_range_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh, argv, maxval, minval; s_vpi_value val; unsigned long i_maxval, i_minval; + (void)name; /* Parameter is not used. */ + /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -656,8 +659,14 @@ static PLI_INT32 sys_urandom_range_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) vpi_get_value(maxval, &val); i_maxval = val.value.integer; - vpi_get_value(minval, &val); - i_minval = val.value.integer; + /* Is this a two or one argument function call? */ + if (minval) { + vpi_get_value(minval, &val); + i_minval = val.value.integer; + vpi_free_object(argv); + } else { + i_minval = 0; + } /* Swap the two arguments if they are out of order. */ if (i_minval > i_maxval) { @@ -669,7 +678,6 @@ static PLI_INT32 sys_urandom_range_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) /* Calculate and return the result. */ val.value.integer = urandom(0, i_maxval, i_minval); vpi_put_value(callh, &val, 0, vpiNoDelay); - vpi_free_object(argv); return 0; } @@ -679,6 +687,8 @@ static PLI_INT32 sys_dist_uniform_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; long i_seed, i_start, i_end; + (void)name; /* Parameter is not used. */ + /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -714,6 +724,8 @@ static PLI_INT32 sys_dist_normal_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; long i_seed, i_mean, i_sd; + (void)name; /* Parameter is not used. */ + /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -749,6 +761,8 @@ static PLI_INT32 sys_dist_exponential_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; long i_seed, i_mean; + (void)name; /* Parameter is not used. */ + /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -780,6 +794,8 @@ static PLI_INT32 sys_dist_poisson_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; long i_seed, i_mean; + (void)name; /* Parameter is not used. */ + /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -811,6 +827,8 @@ static PLI_INT32 sys_dist_chi_square_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; long i_seed, i_df; + (void)name; /* Parameter is not used. */ + /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -842,6 +860,8 @@ static PLI_INT32 sys_dist_t_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; long i_seed, i_df; + (void)name; /* Parameter is not used. */ + /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -873,6 +893,8 @@ static PLI_INT32 sys_dist_erlang_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) s_vpi_value val; long i_seed, i_k, i_mean; + (void)name; /* Parameter is not used. */ + /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -902,12 +924,13 @@ static PLI_INT32 sys_dist_erlang_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } -static PLI_INT32 sys_rand_func_sizetf(PLI_BYTE8 *x) +static PLI_INT32 sys_rand_func_sizetf(PLI_BYTE8 *name) { + (void)name; /* Parameter is not used. */ return 32; } -void sys_random_register() +void sys_random_register(void) { s_vpi_systf_data tf_data; vpiHandle res; @@ -922,7 +945,7 @@ void sys_random_register() res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - /* From System Verilog 3.1a. */ + /* From SystemVerilog. */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiSysFuncSized; tf_data.tfname = "$urandom"; @@ -933,7 +956,7 @@ void sys_random_register() res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - /* From System Verilog 3.1a. */ + /* From SystemVerilog. */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiSysFuncSized; tf_data.tfname = "$urandom_range"; diff --git a/vpi/sys_random.h b/vpi/sys_random.h index 90511702c..8753bdf84 100644 --- a/vpi/sys_random.h +++ b/vpi/sys_random.h @@ -1,7 +1,7 @@ -#ifndef __vpi_sys_rand_H -#define __vpi_sys_rand_H +#ifndef IVL_sys_random_H +#define IVL_sys_random_H /* - * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -27,4 +27,4 @@ extern PLI_INT32 sys_rand_three_args_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); extern PLI_INT32 sys_random_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); -#endif +#endif /* IVL_sys_random_H */ diff --git a/vpi/sys_random_mti.c b/vpi/sys_random_mti.c index 58753ac85..e326075a0 100644 --- a/vpi/sys_random_mti.c +++ b/vpi/sys_random_mti.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -37,16 +37,11 @@ /* Icarus seed cookie */ #define COOKIE 0x1ca1ca1c -static struct context_s global_context = { -#if defined(__GCC__) - .mti = -#else - /* For MSVC simply use the fact that mti is located first */ -#endif - NP1 }; +static struct context_s global_context = {NP1, {0} }; static long mti_dist_uniform(long*seed, long start, long end) { + (void)seed; /* Parameter is not used. */ if (start >= end) return start; if ((start > LONG_MIN) || (end < LONG_MAX)) { @@ -63,6 +58,8 @@ static PLI_INT32 sys_mti_dist_uniform_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_value val; long i_seed, i_start, i_end; + (void)name; /* Parameter is not used. */ + /* Get the argument handles and convert them. */ callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); @@ -99,6 +96,8 @@ static PLI_INT32 sys_mti_random_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) int i_seed = COOKIE; struct context_s *context; + (void)name; /* Parameter is not used. */ + /* Get the argument list and look for a seed. If it is there, get the value and reseed the random number generator. */ callh = vpi_handle(vpiSysTfCall, 0); @@ -142,7 +141,7 @@ static PLI_INT32 sys_mti_random_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -void sys_random_mti_register() +void sys_random_mti_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_readmem.c b/vpi/sys_readmem.c index b35154a03..a670a6317 100644 --- a/vpi/sys_readmem.c +++ b/vpi/sys_readmem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -411,6 +411,8 @@ static PLI_INT32 sys_readmem_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static PLI_INT32 free_readmempath(p_cb_data cb_data) { unsigned idx; + + (void)cb_data; /* Parameter is not used. */ for(idx = 0; idx < sl_count; idx += 1) { free(search_list[idx]); } @@ -569,7 +571,7 @@ static PLI_INT32 sys_writemem_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -void sys_readmem_register() +void sys_readmem_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_readmem_lex.h b/vpi/sys_readmem_lex.h index c638ec6d6..6531b8f1c 100644 --- a/vpi/sys_readmem_lex.h +++ b/vpi/sys_readmem_lex.h @@ -1,7 +1,7 @@ -#ifndef __sys_readmem_lex_H -#define __sys_readmem_lex_H +#ifndef IVL_sys_readmem_lex_H +#define IVL_sys_readmem_lex_H /* - * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -30,8 +30,8 @@ extern char *readmem_error_token; extern void sys_readmem_start_file(FILE*in, int bin_flag, unsigned width, struct t_vpi_vecval*val); -extern int readmemlex(); +extern int readmemlex(void); -extern void destroy_readmem_lexor(); +extern void destroy_readmem_lexor(void); -#endif +#endif /* IVL_sys_readmem_lex_H */ diff --git a/vpi/sys_readmem_lex.lex b/vpi/sys_readmem_lex.lex index c7b90f9ba..22e5b0e80 100644 --- a/vpi/sys_readmem_lex.lex +++ b/vpi/sys_readmem_lex.lex @@ -24,9 +24,9 @@ # include "sys_readmem_lex.h" # include -static void make_addr(); -static void make_hex_value(); -static void make_bin_value(); +static void make_addr(void); +static void make_hex_value(void); +static void make_bin_value(void); static int save_state; @@ -60,12 +60,12 @@ char *readmem_error_token = 0; static unsigned word_width = 0; static struct t_vpi_vecval*vecval = 0; -static void make_addr() +static void make_addr(void) { sscanf(yytext+1, "%x", (unsigned int*)&vecval->aval); } -static void make_hex_value() +static void make_hex_value(void) { char*beg = yytext; char*end = beg + strlen(beg); @@ -136,7 +136,7 @@ static void make_hex_value() } } -static void make_bin_value() +static void make_bin_value(void) { char*beg = yytext; char*end = beg + strlen(beg); @@ -195,7 +195,7 @@ void sys_readmem_start_file(FILE*in, int bin_flag, /* * Modern version of flex (>=2.5.9) can clean up the scanner data. */ -void destroy_readmem_lexor() +void destroy_readmem_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 diff --git a/vpi/sys_scanf.c b/vpi/sys_scanf.c index f9e500fcd..3e7534cdf 100644 --- a/vpi/sys_scanf.c +++ b/vpi/sys_scanf.c @@ -822,6 +822,7 @@ static int scan_format_two_state(vpiHandle callh, vpiHandle argv, bits |= (ch & 0xff) << byte*8; } /* Only save the words that are in range. */ + assert(varlen>=0); if (word < (unsigned)varlen) { val_ptr[word].aval = bits; val_ptr[word].bval = 0; @@ -836,8 +837,9 @@ static int scan_format_two_state(vpiHandle callh, vpiHandle argv, /* Not enough words were read to fill the variable so zero fill the * upper words. */ + assert(varlen>=0); if (words < (unsigned)varlen) { - for (word = words; word < varlen ; word += 1) { + for (word = words; word < (unsigned)varlen ; word += 1) { val_ptr[word].aval = 0; val_ptr[word].bval = 0; } @@ -978,8 +980,9 @@ static int scan_format_four_state(vpiHandle callh, vpiHandle argv, /* Not enough words were read to fill the variable so zero fill the * upper words. */ + assert(varlen>=0); if (words < (unsigned)varlen) { - for (word = words; word < varlen ; word += 1) { + for (word = words; word < (unsigned)varlen ; word += 1) { val_ptr[word].aval = 0; val_ptr[word].bval = 0; } @@ -1114,7 +1117,7 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv, /* Read a '%' character from the input. */ case '%': - assert(max_width == -1); + assert(max_width == -1U); assert(suppress_flag == 0); ch = byte_getc(src); if (ch != '%') { @@ -1432,7 +1435,7 @@ static PLI_INT32 sys_sscanf_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } -void sys_scanf_register() +void sys_scanf_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 506446912..5d69ff623 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2014 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 @@ -101,7 +101,7 @@ void sdf_select_instance(const char*celltype, const char*cellinst) vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, sdf_callh), (int)vpi_get(vpiLineNo, sdf_callh)); vpi_printf("Unable to find %s in scope %s.\n", - cellinst, vpi_get_str(vpiFullName, scope)); + src, vpi_get_str(vpiFullName, scope)); return; } @@ -110,16 +110,16 @@ void sdf_select_instance(const char*celltype, const char*cellinst) vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, sdf_callh), (int)vpi_get(vpiLineNo, sdf_callh)); vpi_printf("Scope %s in %s is not a module.\n", - cellinst, vpi_get_str(vpiFullName, sdf_scope)); + src, vpi_get_str(vpiFullName, scope)); } /* The matching scope (a module) should have the expected type. */ if (strcmp(celltype,vpi_get_str(vpiDefName,sdf_cur_cell)) != 0) { vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, sdf_callh), (int)vpi_get(vpiLineNo, sdf_callh)); - vpi_printf("Module %s in %s is not a %s; it is an %s\n", cellinst, - vpi_get_str(vpiFullName, sdf_scope), celltype, - vpi_get_str(vpiDefName, sdf_cur_cell)); + vpi_printf("Module %s in %s is not a %s; it is a ", src, + vpi_get_str(vpiFullName, scope), celltype); + vpi_printf("%s\n", vpi_get_str(vpiDefName, sdf_cur_cell)); } } @@ -318,7 +318,7 @@ static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -void sys_sdf_register() +void sys_sdf_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_table.c b/vpi/sys_table.c index 6e9a4326c..bb5e3ad7e 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -23,42 +23,42 @@ # include # 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(); -extern void sys_display_register(); -extern void sys_plusargs_register(); -extern void sys_queue_register(); -extern void sys_random_register(); -extern void sys_random_mti_register(); -extern void sys_readmem_register(); -extern void sys_scanf_register(); -extern void sys_sdf_register(); -extern void sys_time_register(); -extern void sys_vcd_register(); -extern void sys_vcdoff_register(); -extern void sys_special_register(); -extern void table_model_register(); -extern void vams_simparam_register(); +extern void sys_convert_register(void); +extern void sys_countdrivers_register(void); +extern void sys_darray_register(void); +extern void sys_fileio_register(void); +extern void sys_finish_register(void); +extern void sys_deposit_register(void); +extern void sys_display_register(void); +extern void sys_plusargs_register(void); +extern void sys_queue_register(void); +extern void sys_random_register(void); +extern void sys_random_mti_register(void); +extern void sys_readmem_register(void); +extern void sys_scanf_register(void); +extern void sys_sdf_register(void); +extern void sys_time_register(void); +extern void sys_vcd_register(void); +extern void sys_vcdoff_register(void); +extern void sys_special_register(void); +extern void table_model_register(void); +extern void vams_simparam_register(void); #ifdef HAVE_LIBZ #ifdef HAVE_LIBBZ2 -extern void sys_lxt_register(); +extern void sys_lxt_register(void); #else -static void sys_lxt_register() { fputs("LXT support disabled since libbzip2 not available\n",stderr); exit(1); } +static void sys_lxt_register(void) { fputs("LXT support disabled since libbzip2 not available\n",stderr); exit(1); } #endif -extern void sys_lxt2_register(); -extern void sys_fst_register(); +extern void sys_lxt2_register(void); +extern void sys_fst_register(void); #else -static void sys_lxt_register() { fputs("LXT support disabled since zlib not available\n",stderr); exit(1); } -static void sys_lxt2_register() { fputs("LXT2 support disabled since zlib not available\n",stderr); exit(1); } -static void sys_fst_register() { fputs("FST support disabled since zlib not available\n",stderr); exit(1); } +static void sys_lxt_register(void) { fputs("LXT support disabled since zlib not available\n",stderr); exit(1); } +static void sys_lxt2_register(void) { fputs("LXT2 support disabled since zlib not available\n",stderr); exit(1); } +static void sys_fst_register(void) { fputs("FST support disabled since zlib not available\n",stderr); exit(1); } #endif -static void sys_lxt_or_vcd_register() +static void sys_lxt_or_vcd_register(void) { int idx; struct t_vpi_vlog_info vlog_info; @@ -195,7 +195,7 @@ static void sys_lxt_or_vcd_register() } } -void (*vlog_startup_routines[])() = { +void (*vlog_startup_routines[])(void) = { sys_convert_register, sys_countdrivers_register, sys_darray_register, diff --git a/vpi/sys_time.c b/vpi/sys_time.c index e904d2718..18f248a4e 100644 --- a/vpi/sys_time.c +++ b/vpi/sys_time.c @@ -107,7 +107,7 @@ static PLI_INT32 sys_realtime_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -void sys_time_register() +void sys_time_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_vcd.c b/vpi/sys_vcd.c index 62a6f75b5..2a055da5d 100644 --- a/vpi/sys_vcd.c +++ b/vpi/sys_vcd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -144,8 +144,8 @@ static void show_this_item_x(struct vcd_info*info) * managed qsorted list of scope names/variables for duplicates bsearching */ -struct vcd_names_list_s vcd_tab = { 0 }; -struct vcd_names_list_s vcd_var = { 0 }; +struct vcd_names_list_s vcd_tab = { 0, 0, 0, 0 }; +struct vcd_names_list_s vcd_var = { 0, 0, 0, 0 }; static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ @@ -159,7 +159,7 @@ __inline__ static int dump_header_pending(void) * This function writes out all the traced variables, whether they * changed or not. */ -static void vcd_checkpoint() +static void vcd_checkpoint(void) { struct vcd_info*cur; @@ -167,7 +167,7 @@ static void vcd_checkpoint() show_this_item(cur); } -static void vcd_checkpoint_x() +static void vcd_checkpoint_x(void) { struct vcd_info*cur; @@ -317,6 +317,8 @@ static PLI_INT32 sys_dumpoff_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (dump_is_off) return 0; dump_is_off = 1; @@ -345,6 +347,8 @@ static PLI_INT32 sys_dumpon_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (!dump_is_off) return 0; dump_is_off = 0; @@ -373,6 +377,8 @@ static PLI_INT32 sys_dumpall_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_time now; PLI_UINT64 now64; + (void)name; /* Parameter is not used. */ + if (dump_is_off) return 0; if (dump_file == 0) return 0; if (dump_header_pending()) return 0; @@ -475,6 +481,7 @@ static PLI_INT32 sys_dumpfile_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static PLI_INT32 sys_dumpflush_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void)name; /* Parameter is not used. */ if (dump_file) fflush(dump_file); return 0; @@ -486,6 +493,8 @@ static PLI_INT32 sys_dumplimit_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) vpiHandle argv = vpi_iterate(vpiArgument, callh); s_vpi_value val; + (void)name; /* Parameter is not used. */ + /* Get the value and set the dump limit. */ val.format = vpiIntVal; vpi_get_value(vpi_scan(argv), &val); @@ -763,6 +772,8 @@ static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) s_vpi_value value; unsigned depth = 0; + (void)name; /* Parameter is not used. */ + if (dump_file == 0) { open_dumpfile(callh); if (dump_file == 0) { @@ -855,7 +866,7 @@ static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -void sys_vcd_register() +void sys_vcd_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/sys_vcdoff.c b/vpi/sys_vcdoff.c index 1ce71f709..97f9c71a9 100644 --- a/vpi/sys_vcdoff.c +++ b/vpi/sys_vcdoff.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -35,11 +35,13 @@ static int dump_flag = 0; static PLI_INT32 sys_dummy_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void)name; /* Parameter is not used. */ return 0; } static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void)name; /* Parameter is not used. */ if (dump_flag == 0) { vpi_printf("VCD info: dumping is suppressed.\n"); dump_flag = 1; @@ -48,7 +50,7 @@ static PLI_INT32 sys_dumpvars_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -void sys_vcdoff_register() +void sys_vcdoff_register(void) { s_vpi_systf_data tf_data; vpiHandle res; diff --git a/vpi/table_mod.c b/vpi/table_mod.c index 1867204e4..43609989b 100644 --- a/vpi/table_mod.c +++ b/vpi/table_mod.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2014 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 @@ -40,7 +40,8 @@ static unsigned table_count = 0; static PLI_INT32 cleanup_table_mod(p_cb_data cause) { unsigned idx; - (void) cause; /* Unused argument. */ + + (void)cause; /* Parameter is not used. */ for (idx = 0; idx < table_count; idx += 1) { free(tables[idx]->indep); @@ -64,7 +65,7 @@ static PLI_INT32 cleanup_table_mod(p_cb_data cause) * Create an empty table model object and add it to the list of table * model objects. */ -static p_table_mod create_table() +static p_table_mod create_table(void) { /* Create an empty table model object. */ p_table_mod obj = (p_table_mod) malloc(sizeof(s_table_mod)); @@ -91,7 +92,7 @@ static p_table_mod create_table() * Check to see if this is a constant string. It returns 1 if the argument * is a constant string otherwise it returns 0. */ -unsigned is_const_string_obj(vpiHandle arg) +static unsigned is_const_string_obj(vpiHandle arg) { unsigned rtn = 0; @@ -110,10 +111,9 @@ unsigned is_const_string_obj(vpiHandle arg) /* * Get any command line flags. For now we only have a debug flag. */ -static void check_command_line_flags() +static void check_command_line_flags(void) { struct t_vpi_vlog_info vlog_info; - unsigned idx; static unsigned command_line_processed = 0; /* If we have already processed the arguments then just return. */ @@ -121,7 +121,7 @@ static void check_command_line_flags() vpi_get_vlog_info(&vlog_info); - for (idx = 0; idx < vlog_info.argc; idx += 1) { + for (int idx = 0; idx < vlog_info.argc; idx += 1) { if (strcmp(vlog_info.argv[idx], "-table-model-debug") == 0) { table_model_debug = 1; } @@ -634,6 +634,8 @@ static unsigned initialize_table_model(vpiHandle callh, const char *name, static double eval_table_model(vpiHandle callh, p_table_mod table) { unsigned idx; + + (void)callh; /* Parameter is not used. */ fprintf(stderr, "Evaluating table \"%s\" with %u variables\n", table->file.name, table->dims); for (idx = 0; idx < table->dims; idx += 1) { @@ -685,7 +687,7 @@ static PLI_INT32 sys_table_model_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) /* * Routine to register the system function provided in this file. */ -void table_model_register() +void table_model_register(void) { s_vpi_systf_data tf_data; s_cb_data cb; diff --git a/vpi/table_mod.h b/vpi/table_mod.h index 35a513404..819626f7c 100644 --- a/vpi/table_mod.h +++ b/vpi/table_mod.h @@ -1,7 +1,7 @@ -#ifndef __table_mod_H -#define __table_mod_H +#ifndef IVL_table_mod_H +#define IVL_table_mod_H /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2014 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 @@ -94,8 +94,8 @@ typedef struct t_table_mod { extern unsigned parse_table_model(FILE *fp, vpiHandle callh, p_table_mod table); -extern int tblmodlex(); -extern void destroy_tblmod_lexor(); +extern int tblmodlex(void); +extern void destroy_tblmod_lexor(void); extern void init_tblmod_lexor(FILE *fp); -#endif +#endif /* IVL_table_mod_H */ diff --git a/vpi/table_mod_lexor.lex b/vpi/table_mod_lexor.lex index 738c644fe..bd518ee7e 100644 --- a/vpi/table_mod_lexor.lex +++ b/vpi/table_mod_lexor.lex @@ -150,7 +150,7 @@ void init_tblmod_lexor(FILE *fp) /* * Modern version of flex (>=2.5.9) can clean up the scanner data. */ -void destroy_tblmod_lexor() +void destroy_tblmod_lexor(void) { # ifdef FLEX_SCANNER # if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 diff --git a/vpi/table_mod_parse.y b/vpi/table_mod_parse.y index fb1ff4f18..1ded2cae3 100644 --- a/vpi/table_mod_parse.y +++ b/vpi/table_mod_parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2014 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 @@ -90,7 +90,7 @@ static p_table_mod table_def; extern int tblmodlex(void); static void yyerror(const char *fmt, ...); -static void process_point() +static void process_point(void) { assert(cur_value == indep_values); #if 0 @@ -231,6 +231,7 @@ void yyerror(const char *fmt, ...) fprintf(stderr, "%s:%u: TABLE ERROR: ", in_file_name, yylloc.first_line-1); vfprintf(stderr, fmt, ap); + va_end(ap); fprintf(stderr, "\n"); errors += 1; } diff --git a/vpi/v2005_math.c b/vpi/v2005_math.c index 4306faccf..aec4d9d52 100644 --- a/vpi/v2005_math.c +++ b/vpi/v2005_math.c @@ -2,7 +2,7 @@ * Verilog-2005 math library for Icarus Verilog * http://www.icarus.com/eda/verilog/ * - * Copyright (C) 2007-2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2007-2014 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 @@ -101,6 +101,8 @@ static PLI_INT32 sys_end_of_simulation(p_cb_data cb_data) { unsigned idx; + (void)cb_data; /* Parameter is not used. */ + for (idx = 0; idx < single_funcs_count; idx += 1) { free(single_funcs[idx]); } @@ -135,7 +137,7 @@ static void va_error_message(vpiHandle callh, const char *format, /* * Process an argument. */ -vpiHandle va_process_argument(vpiHandle callh, const char *name, +static vpiHandle va_process_argument(vpiHandle callh, const char *name, vpiHandle arg, const char *post) { PLI_INT32 type; @@ -217,7 +219,7 @@ static PLI_INT32 va_single_argument_calltf(ICARUS_VPI_CONST PLI_BYTE8 *ud) s_vpi_value val; va_single_t* fun_data; - (void) ud; /* Not used! */ + (void)ud; /* Parameter is not used. */ /* Retrieve the function and argument data. */ fun_data = vpi_get_userdata(callh); @@ -302,7 +304,7 @@ static PLI_INT32 va_double_argument_calltf(ICARUS_VPI_CONST PLI_BYTE8 *ud) double first_arg; va_double_t* fun_data; - (void) ud; /* Not used! */ + (void)ud; /* Parameter is not used. */ /* Retrieve the function and argument data. */ fun_data = vpi_get_userdata(callh); @@ -371,7 +373,7 @@ static void sys_v2005_math_register(void) /* * Hook to get Icarus Verilog to find the registration function. */ -extern void sys_clog2_register(); +extern void sys_clog2_register(void); void (*vlog_startup_routines[])(void) = { sys_v2005_math_register, diff --git a/vpi/v2009_array.c b/vpi/v2009_array.c index f362b5b8f..805773e63 100644 --- a/vpi/v2009_array.c +++ b/vpi/v2009_array.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2014 Stephen Williams (steve@icarus.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 @@ -16,7 +17,38 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "sys_priv.h" +# include "sys_priv.h" +# include + +static PLI_INT32 one_array_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 an array 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 func_not_implemented_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name) { @@ -29,6 +61,110 @@ static PLI_INT32 func_not_implemented_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name return 0; } +static void high_array(const char*name, vpiHandle callh, vpiHandle arg) +{ + s_vpi_value value; + int array_type; + int size; + + switch ( (array_type = vpi_get(vpiArrayType, arg)) ) { + case vpiDynamicArray: + case vpiQueueArray: + size = vpi_get(vpiSize, arg); + value.format = vpiIntVal; + value.value.integer = size - 1; + vpi_put_value(callh, &value, 0, vpiNoDelay); + break; + + default: + vpi_printf("SORRY: %s:%d: function %s() argument object code is %d\n", + vpi_get_str(vpiFile,callh), (int)vpi_get(vpiLineNo, callh), + name, array_type); + break; + } +} + +static PLI_INT32 high_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + int object_code; + + (void)name; /* Parameter is not used. */ + + argv = vpi_iterate(vpiArgument, callh); + assert(argv); + arg = vpi_scan(argv); + assert(arg); + vpi_free_object(argv); + + switch ( (object_code = vpi_get(vpiType, arg)) ) { + case vpiArrayVar: + high_array(name, callh, arg); + break; + + default: + vpi_printf("SORRY: %s:%d: function %s() argument object code is %d\n", + vpi_get_str(vpiFile,callh), (int)vpi_get(vpiLineNo, callh), + name, object_code); + return 0; + } + + return 0; +} + +static void low_array(const char*name, vpiHandle callh, vpiHandle arg) +{ + s_vpi_value value; + int array_type; + + switch ( (array_type = vpi_get(vpiArrayType, arg)) ) { + case vpiDynamicArray: + case vpiQueueArray: + value.format = vpiIntVal; + value.value.integer = 0; + vpi_put_value(callh, &value, 0, vpiNoDelay); + break; + + default: + vpi_printf("SORRY: %s:%d: function %s() argument object code is %d\n", + vpi_get_str(vpiFile,callh), (int)vpi_get(vpiLineNo, callh), + name, array_type); + break; + } +} + +static PLI_INT32 low_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + int object_code; + + (void)name; /* Parameter is not used. */ + + argv = vpi_iterate(vpiArgument, callh); + assert(argv); + arg = vpi_scan(argv); + assert(arg); + vpi_free_object(argv); + + switch ( (object_code = vpi_get(vpiType, arg)) ) { + case vpiArrayVar: + low_array(name, callh, arg); + break; + + default: + vpi_printf("SORRY: %s:%d: function %s() argument object code is %d\n", + vpi_get_str(vpiFile,callh), (int)vpi_get(vpiLineNo, callh), + name, object_code); + return 0; + } + + return 0; +} + void v2009_array_register(void) { s_vpi_systf_data tf_data; @@ -61,23 +197,22 @@ void v2009_array_register(void) res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - tf_data.tfname = "$low"; - tf_data.user_data = "$low"; - res = vpi_register_systf(&tf_data); - vpip_make_systf_system_defined(res); - - tf_data.tfname = "$high"; - tf_data.user_data = "$high"; - res = vpi_register_systf(&tf_data); - vpip_make_systf_system_defined(res); - tf_data.tfname = "$increment"; tf_data.user_data = "$increment"; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - tf_data.tfname = "$size"; - tf_data.user_data = "$size"; + tf_data.tfname = "$high"; + tf_data.user_data = "$high"; + tf_data.compiletf = one_array_arg_compiletf; + tf_data.calltf = high_calltf; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.tfname = "$low"; + tf_data.user_data = "$low"; + tf_data.compiletf = one_array_arg_compiletf; + tf_data.calltf = low_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); } diff --git a/vpi/v2009_enum.c b/vpi/v2009_enum.c index 3c8645c4b..be9aaa9fa 100644 --- a/vpi/v2009_enum.c +++ b/vpi/v2009_enum.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2014 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 @@ -444,6 +444,8 @@ static PLI_INT32 ivl_enum_method_name_calltf(PLI_BYTE8*name) s_vpi_value cur_val, var_val; + (void)name; /* Parameter is not used. */ + /* Free the argument iterator. */ vpi_free_object(argv); diff --git a/vpi/v2009_string.c b/vpi/v2009_string.c index 035d6b316..bb7bed623 100644 --- a/vpi/v2009_string.c +++ b/vpi/v2009_string.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2014 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 @@ -56,6 +56,8 @@ static PLI_INT32 len_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpiHandle argv; vpiHandle arg; + (void)name; /* Parameter is not used. */ + argv = vpi_iterate(vpiArgument, callh); assert(argv); arg = vpi_scan(argv); diff --git a/vpi/v2009_table.c b/vpi/v2009_table.c index 1b1b3d226..4e3328779 100644 --- a/vpi/v2009_table.c +++ b/vpi/v2009_table.c @@ -21,7 +21,7 @@ extern void v2009_array_register(void); extern void v2009_enum_register(void); extern void v2009_string_register(void); -void (*vlog_startup_routines[])() = { +void (*vlog_startup_routines[])(void) = { v2009_array_register, v2009_enum_register, v2009_string_register, diff --git a/vpi/va_math.c b/vpi/va_math.c index 8ca38e190..5c5e4105a 100644 --- a/vpi/va_math.c +++ b/vpi/va_math.c @@ -2,7 +2,7 @@ * Verilog-A math library for Icarus Verilog * http://www.icarus.com/eda/verilog/ * - * Copyright (C) 2007-2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2007-2014 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 @@ -128,6 +128,8 @@ static PLI_INT32 sys_end_of_simulation(p_cb_data cb_data) { unsigned idx; + (void)cb_data; /* Parameter is not used. */ + for (idx = 0; idx < single_funcs_count; idx += 1) { free(single_funcs[idx]); } @@ -162,7 +164,7 @@ static void va_error_message(vpiHandle callh, const char *format, /* * Process an argument. */ -vpiHandle va_process_argument(vpiHandle callh, const char *name, +static vpiHandle va_process_argument(vpiHandle callh, const char *name, vpiHandle arg, const char *post) { PLI_INT32 type; @@ -244,7 +246,7 @@ static PLI_INT32 va_single_argument_calltf(ICARUS_VPI_CONST PLI_BYTE8 *ud) s_vpi_value val; va_single_t* fun_data; - (void) ud; /* Not used! */ + (void)ud; /* Parameter is not used. */ /* Retrieve the function and argument data. */ fun_data = vpi_get_userdata(callh); @@ -329,7 +331,7 @@ static PLI_INT32 va_double_argument_calltf(ICARUS_VPI_CONST PLI_BYTE8 *ud) double first_arg; va_double_t* fun_data; - (void) ud; /* Not used! */ + (void)ud; /* Parameter is not used. */ /* Retrieve the function and argument data. */ fun_data = vpi_get_userdata(callh); diff --git a/vpi/vams_simparam.c b/vpi/vams_simparam.c index 74fa6772d..6d5e8b30d 100644 --- a/vpi/vams_simparam.c +++ b/vpi/vams_simparam.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2008-2014 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 @@ -225,7 +225,7 @@ static PLI_INT32 simparam_str_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name_ext) retval = strdup(vpi_get_str(vpiFullName, vpi_handle(vpiScope,callh))); } else { - if (defval == 0) { + if (defval == NULL) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("$simparam%s unknown parameter name \"%s\".\n", @@ -241,6 +241,7 @@ static PLI_INT32 simparam_str_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name_ext) val.format = vpiStringVal; val.value.str = retval; vpi_put_value(callh, &val, 0, vpiNoDelay); + if (defval != retval) free(defval); free(retval); return 0; @@ -248,8 +249,7 @@ static PLI_INT32 simparam_str_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name_ext) static PLI_INT32 simparam_str_sizetf(PLI_BYTE8 *name_ext) { - (void) name_ext; /* Not used! */ - + (void) name_ext; /* Parameter is not used. */ return MAX_STRING_RESULT; /* 128 characters max! */ } diff --git a/vpi/vcd_priv.h b/vpi/vcd_priv.h index ea96642b3..43430c490 100644 --- a/vpi/vcd_priv.h +++ b/vpi/vcd_priv.h @@ -1,7 +1,7 @@ -#ifndef __vcd_priv_H -#define __vcd_priv_H +#ifndef IVL_vcd_priv_H +#define IVL_vcd_priv_H /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2014 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 @@ -45,7 +45,7 @@ EXTERN const char *vcd_names_search(struct vcd_names_list_s*tab, EXTERN void vcd_names_sort(struct vcd_names_list_s*tab); -EXTERN void vcd_names_delete(); +EXTERN void vcd_names_delete(struct vcd_names_list_s*tab); /* * Keep a map of nexus ident's to help with alias detection. @@ -53,7 +53,7 @@ EXTERN void vcd_names_delete(); EXTERN const char*find_nexus_ident(int nex); EXTERN void set_nexus_ident(int nex, const char *id); -EXTERN void nexus_ident_delete(); +EXTERN void nexus_ident_delete(void); /* * Keep a set of scope names to help with duplicate detection. @@ -131,4 +131,4 @@ EXTERN PLI_INT32 sys_dumpvars_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); #undef EXTERN -#endif +#endif /* IVL_vcd_priv_H */ diff --git a/vpi/vcd_priv2.cc b/vpi/vcd_priv2.cc index fb01ce5a8..a41c5b5a4 100644 --- a/vpi/vcd_priv2.cc +++ b/vpi/vcd_priv2.cc @@ -230,7 +230,7 @@ extern "C" void vcd_work_sync(void) } } -extern "C" extern "C" void vcd_work_flush(void) +extern "C" void vcd_work_flush(void) { struct vcd_work_item_s*cell = grab_item(); cell->type = WT_FLUSH; diff --git a/vpi/vhdl_table.c b/vpi/vhdl_table.c index 4e80e1444..657ffd76b 100644 --- a/vpi/vhdl_table.c +++ b/vpi/vhdl_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -40,7 +40,8 @@ static unsigned mdata_count = 0; static PLI_INT32 cleanup_mdata(p_cb_data cause) { unsigned idx; - (void) cause; /* Unused argument. */ + + (void) cause; /* Parameter is not used. */ for (idx= 0; idx < mdata_count; idx += 1) { free(mdata[idx]); @@ -123,7 +124,8 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpiHandle sys = vpi_handle(vpiSysTfCall, 0); struct t_vpi_value rval; struct monitor_data*mon; - (void) name; + + (void) name; /* Parameter is not used. */ rval.format = vpiScalarVal; @@ -151,7 +153,7 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) static PLI_INT32 ivlh_attribute_event_sizetf(ICARUS_VPI_CONST PLI_BYTE8*name) { - (void) name; + (void) name; /* Parameter is not used. */ return 1; } @@ -182,7 +184,7 @@ static void vhdl_register(void) vpi_register_cb(&cb); } -void (*vlog_startup_routines[])() = { +void (*vlog_startup_routines[])(void) = { vhdl_register, 0 }; diff --git a/vpi/vpi_config.h.in b/vpi/vpi_config.h.in index 1f29e3fbe..9c7601731 100644 --- a/vpi/vpi_config.h.in +++ b/vpi/vpi_config.h.in @@ -1,7 +1,7 @@ -#ifndef __vpi_config_H -#define __vpi_config_H +#ifndef IVL_vpi_config_H +#define IVL_vpi_config_H /* - * Copyright (c) 2004-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -32,4 +32,4 @@ # define _FILE_OFFSET_BITS 64 #endif -#endif /* __config_H */ +#endif /* IVL_vpi_config_H */ diff --git a/vpi/vpi_debug.c b/vpi/vpi_debug.c index 4a4515b43..278b8dbc8 100644 --- a/vpi/vpi_debug.c +++ b/vpi/vpi_debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2014 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 @@ -72,6 +72,7 @@ static void dump_object(vpiHandle item) static PLI_INT32 vpi_tree_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void)name; /* Parameter is not used. */ return 0; } @@ -81,6 +82,8 @@ static PLI_INT32 vpi_tree_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle item; + (void)name; /* Parameter is not used. */ + if (argv == 0) { item = vpi_handle(vpiScope, callh); dump_object(item); @@ -93,7 +96,7 @@ static PLI_INT32 vpi_tree_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -void sys_register() +void sys_register(void) { s_vpi_systf_data tf_data; vpiHandle res; @@ -108,7 +111,7 @@ void sys_register() vpip_make_systf_system_defined(res); } -void (*vlog_startup_routines[])() = { +void (*vlog_startup_routines[])(void) = { sys_register, 0 }; diff --git a/vpi/wavealloca.h b/vpi/wavealloca.h index ac2416d62..4be2e4937 100644 --- a/vpi/wavealloca.h +++ b/vpi/wavealloca.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Tony Bybell 1999. * * This program is free software; you can redistribute it and/or @@ -10,7 +10,7 @@ #ifndef WAVE_ALLOCA_H #define WAVE_ALLOCA_H #include -#if HAVE_ALLOCA_H +#ifdef HAVE_ALLOCA_H #include #elif defined(__GNUC__) #ifndef __MINGW32__ @@ -25,5 +25,5 @@ #define alloca _alloca #endif #define wave_alloca alloca -#endif +#endif diff --git a/vpi_user.h b/vpi_user.h index 4b17ae2f0..7bef96669 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -1,7 +1,7 @@ -#ifndef __vpi_user_H -#define __vpi_user_H +#ifndef VPI_USER_H +#define VPI_USER_H /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -334,6 +334,8 @@ typedef struct t_vpi_delay { #define vpiTimePrecision 12 #define vpiDefFile 15 #define vpiDefLineNo 16 +#define vpiScalar 17 +#define vpiVector 18 #define vpiDirection 20 /* direction of port: */ # define vpiInput 1 @@ -655,4 +657,4 @@ extern void vpip_count_drivers(vpiHandle ref, unsigned idx, EXTERN_C_END -#endif +#endif /* VPI_USER_H */ diff --git a/vvp/Makefile.in b/vvp/Makefile.in index b9e260adb..16a0ecbc2 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -33,7 +33,7 @@ includedir = @includedir@ # For a cross compile these defines will need to be set accordingly. HOSTCC = @CC@ -HOSTCFLAGS = @WARNING_FLAGS@ @CFLAGS@ +HOSTCFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ CC = @CC@ CXX = @CXX@ @@ -56,7 +56,7 @@ INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ -CFLAGS = @WARNING_FLAGS@ @CFLAGS@ +CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @rdynamic@ @LDFLAGS@ LIBS = @LIBS@ @EXTRALIBS@ @@ -74,7 +74,9 @@ V = vpi_modules.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \ O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.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 \ + sfunc.o stop.o \ + substitute.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 \ vvp_object.o vvp_cobject.o vvp_darray.o event.o logic.o delay.o \ words.o island_tran.o $V @@ -106,6 +108,9 @@ distclean: clean cppcheck: $(O:.o=.cc) libvpi.c draw_tt.c cppcheck --enable=all -f --suppressions-list=$(srcdir)/cppcheck.sup \ + -UMODULE_DIR1 -UMODULE_DIR2 -UYY_USER_INIT \ + -UYYPARSE_PARAM -UYYPRINT -Ushort -Usize_t -Uyyoverflow \ + -UYYTYPE_INT8 -UYYTYPE_INT16 -UYYTYPE_UINT8 -UYYTYPE_UINT16 \ --relative-paths=$(srcdir) $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in diff --git a/vvp/README.txt b/vvp/README.txt index d23401c2c..27827d9eb 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -192,16 +192,18 @@ The Verilog language itself does not have a DFF primitive, but post synthesis readily creates DFF devices that are best simulated with a common device. Thus, there is the DFF statement to create DFF devices: -