mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-25 23:36:19 +02:00
Compare commits
68
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1daf6733f | ||
|
|
007056d671 | ||
|
|
2dcb1514a2 | ||
|
|
d71a1cb9c1 | ||
|
|
4c3d764a86 | ||
|
|
3189efacbc | ||
|
|
96ec4b7eba | ||
|
|
07c8fce530 | ||
|
|
9a00829ee4 | ||
|
|
680d3c8a3e | ||
|
|
6632e4c33b | ||
|
|
42913e46b8 | ||
|
|
e2ad59466a | ||
|
|
0cd946a7af | ||
|
|
102cbb67b4 | ||
|
|
3113392594 | ||
|
|
72b4256872 | ||
|
|
ca880c73fc | ||
|
|
cef0d0071b | ||
|
|
2934ceb548 | ||
|
|
6b908aeec3 | ||
|
|
a6dd97a5a6 | ||
|
|
2b4f7f8aed | ||
|
|
add84b153c | ||
|
|
3c5bf034ca | ||
|
|
84a7efdb4f | ||
|
|
dfb7bf5211 | ||
|
|
a33619a0f5 | ||
|
|
a1495bb007 | ||
|
|
8e1f22cd82 | ||
|
|
db10de1a6a | ||
|
|
bbed408d68 | ||
|
|
ba3660b948 | ||
|
|
73dcace781 | ||
|
|
fd3ca037aa | ||
|
|
2d068ca89f | ||
|
|
dea1161c7e | ||
|
|
3a61b94e98 | ||
|
|
3a8a6976e1 | ||
|
|
6cc244766c | ||
|
|
6e3ec755e2 | ||
|
|
ca517b5519 | ||
|
|
10ab5cf698 | ||
|
|
523de1b69c | ||
|
|
3e591f730e | ||
|
|
34e90bb3a6 | ||
|
|
4f8b91e65c | ||
|
|
e91243e1c6 | ||
|
|
5484ee1732 | ||
|
|
a43f336c6c | ||
|
|
cc7187c172 | ||
|
|
d60df2d75b | ||
|
|
6d433364ac | ||
|
|
bbc80a84a6 | ||
|
|
c993fb8325 | ||
|
|
f662d76b2e | ||
|
|
0c29e540ea | ||
|
|
1a8be6d28c | ||
|
|
6491c5d43c | ||
|
|
a319939573 | ||
|
|
9db9aa4ccb | ||
|
|
cb5260b2ce | ||
|
|
c0d3bb370f | ||
|
|
b99206ac8e | ||
|
|
149bfa05d8 | ||
|
|
86a4025b58 | ||
|
|
2a5948d704 | ||
|
|
f5263c9447 |
+24
-21
@@ -217,43 +217,46 @@ endif
|
||||
|
||||
XNF_INSTALL = $(libdir)/ivl/xnf.conf $(libdir)/ivl/xnf-s.conf
|
||||
|
||||
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
|
||||
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/include/constants.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
|
||||
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
|
||||
for dir in vpi ivlpp driver; \
|
||||
do (cd $$dir ; $(MAKE) $@); done
|
||||
|
||||
$(bindir)/iverilog-vpi: ./iverilog-vpi
|
||||
$(INSTALL_SCRIPT) ./iverilog-vpi $(bindir)/iverilog-vpi
|
||||
$(INSTALL_SCRIPT) ./iverilog-vpi $(DESTDIR)$(bindir)/iverilog-vpi
|
||||
|
||||
$(libdir)/ivl/ivl@EXEEXT@: ./ivl@EXEEXT@
|
||||
$(INSTALL_PROGRAM) ./ivl@EXEEXT@ $(libdir)/ivl/ivl@EXEEXT@
|
||||
$(INSTALL_PROGRAM) ./ivl@EXEEXT@ $(DESTDIR)$(libdir)/ivl/ivl@EXEEXT@
|
||||
|
||||
$(libdir)/ivl/include/constants.vams: $(srcdir)/constants.vams
|
||||
$(INSTALL_DATA) $(srcdir)/constants.vams $@
|
||||
|
||||
$(libdir)/ivl/xnf-s.conf: $(srcdir)/xnf-s.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf-s.conf $(libdir)/ivl/xnf-s.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf-s.conf $(DESTDIR)$(libdir)/ivl/xnf-s.conf
|
||||
|
||||
$(libdir)/ivl/xnf.conf: $(srcdir)/xnf.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf.conf $(libdir)/ivl/xnf.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf.conf $(DESTDIR)$(libdir)/ivl/xnf.conf
|
||||
|
||||
$(includedir)/ivl_target.h: $(srcdir)/ivl_target.h
|
||||
$(INSTALL_DATA) $(srcdir)/ivl_target.h $(includedir)/ivl_target.h
|
||||
$(INSTALL_DATA) $(srcdir)/ivl_target.h $(DESTDIR)$(includedir)/ivl_target.h
|
||||
|
||||
$(includedir)/_pli_types.h: _pli_types.h
|
||||
$(INSTALL_DATA) $< $(includedir)/_pli_types.h
|
||||
$(INSTALL_DATA) $< $(DESTDIR)$(includedir)/_pli_types.h
|
||||
|
||||
$(includedir)/vpi_user.h: $(srcdir)/vpi_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(includedir)/vpi_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(DESTDIR)$(includedir)/vpi_user.h
|
||||
|
||||
$(includedir)/acc_user.h: $(srcdir)/acc_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/acc_user.h $(includedir)/acc_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/acc_user.h $(DESTDIR)$(includedir)/acc_user.h
|
||||
|
||||
$(includedir)/veriuser.h: $(srcdir)/veriuser.h
|
||||
$(INSTALL_DATA) $(srcdir)/veriuser.h $(includedir)/veriuser.h
|
||||
$(INSTALL_DATA) $(srcdir)/veriuser.h $(DESTDIR)$(includedir)/veriuser.h
|
||||
|
||||
$(mandir)/man1/iverilog-vpi.1: $(srcdir)/iverilog-vpi.man
|
||||
$(INSTALL_DATA) $(srcdir)/iverilog-vpi.man $(mandir)/man1/iverilog-vpi.1
|
||||
$(INSTALL_DATA) $(srcdir)/iverilog-vpi.man $(DESTDIR)$(mandir)/man1/iverilog-vpi.1
|
||||
|
||||
$(prefix)/iverilog-vpi.pdf: iverilog-vpi.pdf
|
||||
$(INSTALL_DATA) iverilog-vpi.pdf $(prefix)/iverilog-vpi.pdf
|
||||
$(INSTALL_DATA) iverilog-vpi.pdf $(DESTDIR)$(prefix)/iverilog-vpi.pdf
|
||||
|
||||
# In windows installations, put a few examples and the quick_start
|
||||
# into the destination directory.
|
||||
@@ -276,22 +279,22 @@ $(prefix)/QUICK_START.txt: $(srcdir)/QUICK_START.txt
|
||||
endif
|
||||
|
||||
installdirs: mkinstalldirs
|
||||
$(srcdir)/mkinstalldirs $(bindir) $(includedir) $(libdir)/ivl \
|
||||
$(libdir)/ivl/include $(mandir) $(mandir)/man1
|
||||
$(srcdir)/mkinstalldirs $(DESTDIR)$(bindir) $(DESTDIR)$(includedir) $(DESTDIR)$(libdir)/ivl \
|
||||
$(DESTDIR)$(libdir)/ivl/include $(DESTDIR)$(mandir) $(DESTDIR)$(mandir)/man1
|
||||
|
||||
uninstall:
|
||||
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
|
||||
for dir in vpi ivlpp driver; \
|
||||
do (cd $$dir ; $(MAKE) $@); done
|
||||
for f in xnf.conf xnf-s.conf ivl@EXEEXT@; \
|
||||
do rm -f $(libdir)/ivl/$$f; done
|
||||
-rmdir $(libdir)/ivl/include
|
||||
-rmdir $(libdir)/ivl
|
||||
for f in xnf.conf xnf-s.conf ivl@EXEEXT@ include/constants.vams; \
|
||||
do rm -f $(DESTDIR)$(libdir)/ivl/$$f; done
|
||||
-rmdir $(DESTDIR)$(libdir)/ivl/include
|
||||
-rmdir $(DESTDIR)$(libdir)/ivl
|
||||
for f in verilog iverilog-vpi gverilog@EXEEXT@; \
|
||||
do rm -f $(bindir)/$$f; done
|
||||
do rm -f $(DESTDIR)$(bindir)/$$f; done
|
||||
for f in ivl_target.h vpi_user.h _pli_types.h acc_user.h veriuser.h; \
|
||||
do rm -f $(includedir)/$$f; done
|
||||
rm -f $(mandir)/man1/iverilog-vpi.1 $(prefix)/iverilog-vpi.pdf
|
||||
do rm -f $(DESTDIR)$(includedir)/$$f; done
|
||||
rm -f $(DESTDIR)$(mandir)/man1/iverilog-vpi.1 $(DESTDIR)$(prefix)/iverilog-vpi.pdf
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
||||
@@ -82,6 +82,8 @@ class Module : public PScope, public LineInfo {
|
||||
PExpr*expr;
|
||||
PExpr*msb;
|
||||
PExpr*lsb;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
bool signed_flag;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
@@ -119,7 +121,7 @@ class Module : public PScope, public LineInfo {
|
||||
|
||||
/* The module has a list of genvars that may be used in
|
||||
various generate schemes. */
|
||||
list<perm_string> genvars;
|
||||
map<perm_string,LineInfo*> genvars;
|
||||
|
||||
/* the module has a list of generate schemes that appear in
|
||||
the module definition. These are used at elaboration time. */
|
||||
@@ -156,7 +158,8 @@ class Module : public PScope, public LineInfo {
|
||||
map<perm_string,PFunction*> funcs_;
|
||||
|
||||
static void elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
Design*des, NetScope*scope);
|
||||
Design*des, NetScope*scope,
|
||||
perm_string file, unsigned lineno);
|
||||
|
||||
private: // Not implemented
|
||||
Module(const Module&);
|
||||
|
||||
@@ -191,7 +191,7 @@ PEIdent::~PEIdent()
|
||||
|
||||
/*
|
||||
* An identifier can be in a constant expression if (and only if) it is
|
||||
* a parameter.
|
||||
* a parameter or genvar.
|
||||
*
|
||||
* NOTE: This test does not work if the name is hierarchical!
|
||||
*/
|
||||
@@ -212,6 +212,11 @@ bool PEIdent::is_constant(Module*mod) const
|
||||
if (cur != mod->localparams.end()) return true;
|
||||
}
|
||||
|
||||
{ map<perm_string,LineInfo*>::const_iterator cur;
|
||||
cur = mod->genvars.find(tmp);
|
||||
if (cur != mod->genvars.end()) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -387,7 +387,7 @@ class PEIdent : public PExpr {
|
||||
NetNet*make_implicit_net_(Design*des, NetScope*scope) const;
|
||||
|
||||
bool eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
unsigned&midx, unsigned&lidx) const;
|
||||
long&midx, long&lidx) const;
|
||||
NetNet*process_select_(Design*des, NetScope*scope, NetNet*sig) const;
|
||||
|
||||
};
|
||||
|
||||
+3
-93
@@ -1,7 +1,7 @@
|
||||
#ifndef __Statement_H
|
||||
#define __Statement_H
|
||||
/*
|
||||
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
|
||||
* Copyright (c) 1998-2008 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -18,9 +18,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: Statement.h,v 1.44 2007/05/24 04:07:11 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
# include "svector.h"
|
||||
@@ -417,6 +414,7 @@ class PRepeat : public Statement {
|
||||
|
||||
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:
|
||||
@@ -462,6 +460,7 @@ class PWhile : public Statement {
|
||||
|
||||
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:
|
||||
@@ -469,93 +468,4 @@ class PWhile : public Statement {
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: Statement.h,v $
|
||||
* Revision 1.44 2007/05/24 04:07:11 steve
|
||||
* Rework the heirarchical identifier parse syntax and pform
|
||||
* to handle more general combinations of heirarch and bit selects.
|
||||
*
|
||||
* Revision 1.43 2007/03/05 05:59:10 steve
|
||||
* Handle processes within generate loops.
|
||||
*
|
||||
* Revision 1.42 2005/12/05 21:21:18 steve
|
||||
* Fixes for stubborn compilers.
|
||||
*
|
||||
* Revision 1.41 2004/12/11 02:31:25 steve
|
||||
* Rework of internals to carry vectors through nexus instead
|
||||
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
||||
* down this path.
|
||||
*
|
||||
* Revision 1.40 2004/02/20 18:53:33 steve
|
||||
* Addtrbute keys are perm_strings.
|
||||
*
|
||||
* Revision 1.39 2004/02/18 17:11:54 steve
|
||||
* Use perm_strings for named langiage items.
|
||||
*
|
||||
* Revision 1.38 2003/05/19 02:50:58 steve
|
||||
* Implement the wait statement behaviorally instead of as nets.
|
||||
*
|
||||
* Revision 1.37 2003/01/30 16:23:07 steve
|
||||
* Spelling fixes.
|
||||
*
|
||||
* Revision 1.36 2002/08/12 01:34:58 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.35 2002/06/04 05:38:44 steve
|
||||
* Add support for memory words in l-value of
|
||||
* blocking assignments, and remove the special
|
||||
* NetAssignMem class.
|
||||
*
|
||||
* Revision 1.34 2002/05/26 01:39:02 steve
|
||||
* Carry Verilog 2001 attributes with processes,
|
||||
* all the way through to the ivl_target API.
|
||||
*
|
||||
* Divide signal reference counts between rval
|
||||
* and lval references.
|
||||
*
|
||||
* Revision 1.33 2002/04/21 22:31:02 steve
|
||||
* Redo handling of assignment internal delays.
|
||||
* Leave it possible for them to be calculated
|
||||
* at run time.
|
||||
*
|
||||
* Revision 1.32 2002/04/21 04:59:07 steve
|
||||
* Add support for conbinational events by finding
|
||||
* the inputs to expressions and some statements.
|
||||
* Get case and assignment statements working.
|
||||
*
|
||||
* Revision 1.31 2001/12/03 04:47:14 steve
|
||||
* Parser and pform use hierarchical names as hname_t
|
||||
* objects instead of encoded strings.
|
||||
*
|
||||
* Revision 1.30 2001/11/22 06:20:59 steve
|
||||
* Use NetScope instead of string for scope path.
|
||||
*
|
||||
* Revision 1.29 2000/09/09 15:21:26 steve
|
||||
* move lval elaboration to PExpr virtual methods.
|
||||
*
|
||||
* Revision 1.28 2000/09/03 17:58:35 steve
|
||||
* Change elaborate_lval to return NetAssign_ objects.
|
||||
*
|
||||
* Revision 1.27 2000/07/26 05:08:07 steve
|
||||
* Parse disable statements to pform.
|
||||
*
|
||||
* Revision 1.26 2000/05/11 23:37:26 steve
|
||||
* Add support for procedural continuous assignment.
|
||||
*
|
||||
* Revision 1.25 2000/04/22 04:20:19 steve
|
||||
* Add support for force assignment.
|
||||
*
|
||||
* Revision 1.24 2000/04/12 04:23:57 steve
|
||||
* Named events really should be expressed with PEIdent
|
||||
* objects in the pform,
|
||||
*
|
||||
* Handle named events within the mix of net events
|
||||
* and edges. As a unified lot they get caught together.
|
||||
* wait statements are broken into more complex statements
|
||||
* that include a conditional.
|
||||
*
|
||||
* Do not generate NetPEvent or NetNEvent objects in
|
||||
* elaboration. NetEvent, NetEvWait and NetEvProbe
|
||||
* take over those functions in the netlist.
|
||||
*/
|
||||
#endif
|
||||
|
||||
+20
-4
@@ -100,26 +100,42 @@ extern int build_library_index(const char*path, bool key_case_sensitive);
|
||||
enum generation_t {
|
||||
GN_VER1995 = 1,
|
||||
GN_VER2001 = 2,
|
||||
GN_VER2001X = 3,
|
||||
GN_VER2005 = 3,
|
||||
GN_DEFAULT = 3
|
||||
};
|
||||
|
||||
extern generation_t generation_flag;
|
||||
|
||||
/* If this flag is true, enable extended types support. */
|
||||
extern bool gn_cadence_types_flag;
|
||||
|
||||
/* These functions test that specific features are enabled. */
|
||||
inline bool gn_cadence_types_enabled()
|
||||
{ return gn_cadence_types_flag && generation_flag==GN_VER2001X; }
|
||||
/* If this flag is true, enable miscellaneous extensions. */
|
||||
extern bool gn_icarus_misc_flag;
|
||||
|
||||
/* If this flag is true, then elaborate specify blocks. If this flag
|
||||
is false, then skip elaboration of specify behavior. */
|
||||
extern bool gn_specify_blocks_flag;
|
||||
|
||||
/* If this flag is true, then support/elaborate Verilog-AMS. */
|
||||
extern bool gn_verilog_ams_flag;
|
||||
|
||||
/* If this flag is false a warning is printed when the port declaration
|
||||
is scalar and the net/register definition is vectored. */
|
||||
extern bool gn_io_range_error_flag;
|
||||
|
||||
/* The bits of these GN_KEYWORDS_* constants define non-intersecting
|
||||
sets of keywords. The compiler enables groups of keywords by setting
|
||||
lexor_keyword_mask with the OR of the bits for the keywords to be
|
||||
enabled. */
|
||||
enum { GN_KEYWORDS_1364_1995 = 0x0001,
|
||||
GN_KEYWORDS_1364_2001 = 0x0002,
|
||||
GN_KEYWORDS_1364_2001_CONFIG = 0x0004,
|
||||
GN_KEYWORDS_1364_2005 = 0x0008,
|
||||
GN_KEYWORDS_VAMS_2_3 = 0x0010,
|
||||
GN_KEYWORDS_ICARUS = 0x8000
|
||||
};
|
||||
extern int lexor_keyword_mask;
|
||||
|
||||
/* This is the string to use to invoke the preprocessor. */
|
||||
extern char*ivlpp_string;
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// Mathematical and physical constants
|
||||
|
||||
`ifdef CONSTANTS_VAMS
|
||||
`else
|
||||
`define CONSTANTS_VAMS 1
|
||||
|
||||
// M_ is a mathematical constant
|
||||
`define M_E 2.7182818284590452354
|
||||
`define M_LOG2E 1.4426950408889634074
|
||||
`define M_LOG10E 0.43429448190325182765
|
||||
`define M_LN2 0.69314718055994530942
|
||||
`define M_LN10 2.30258509299404568402
|
||||
`define M_PI 3.14159265358979323846
|
||||
`define M_TWO_PI 6.28318530717958647693
|
||||
`define M_PI_2 1.57079632679489661923
|
||||
`define M_PI_4 0.78539816339744830962
|
||||
`define M_1_PI 0.31830988618379067154
|
||||
`define M_2_PI 0.63661977236758134308
|
||||
`define M_2_SQRTPI 1.12837916709551257390
|
||||
`define M_SQRT2 1.41421356237309504880
|
||||
`define M_SQRT1_2 0.70710678118654752440
|
||||
|
||||
/*
|
||||
* Do we need these? For now they are not available.
|
||||
*
|
||||
// The following constants have been taken from http://physics.nist.gov
|
||||
// P_ is a physical constant
|
||||
// charge of electron in coulombs
|
||||
`define P_Q 1.602176462e-19
|
||||
// speed of light in vacuum in meters/sec
|
||||
`define P_C 2.99792458e8
|
||||
// Boltzmann's constant in joules/kelvin
|
||||
`define P_K 1.3806503e-23
|
||||
// Planck's constant in joules*sec
|
||||
`define P_H 6.62606876e-34
|
||||
// permittivity of vacuum in farads/meter
|
||||
`define P_EPS0 8.854187817e-12
|
||||
// permeability of vacuum in henrys/meter
|
||||
`define P_U0 (4.0e-7 * `M_PI)
|
||||
// zero celsius in kelvin
|
||||
`define P_CELSIUS0 273.15
|
||||
*/
|
||||
`endif
|
||||
+28
-1
@@ -112,9 +112,10 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const
|
||||
o << setw(ind) << "" << "specify delay";
|
||||
if (posedge_) o << " posedge";
|
||||
if (negedge_) o << " negedge";
|
||||
if (is_condit())
|
||||
if (is_condit()) {
|
||||
if (has_condit()) o << " if";
|
||||
else o << " ifnone";
|
||||
}
|
||||
o << " src "
|
||||
<< "(" << transition_delays_[IVL_PE_01]
|
||||
<< "," << transition_delays_[IVL_PE_10]
|
||||
@@ -246,6 +247,15 @@ void NetObj::dump_obj_attr(ostream&o, unsigned ind) const
|
||||
}
|
||||
}
|
||||
|
||||
void NetAbs::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Absolute value (NetAbs): " << name()
|
||||
<< " width=" << width() << " pin_count=" << pin_count()
|
||||
<< endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetAddSub::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Adder (NetAddSub): " << name()
|
||||
@@ -1081,6 +1091,20 @@ void NetExpr::dump(ostream&o) const
|
||||
|
||||
void NetEBinary::dump(ostream&o) const
|
||||
{
|
||||
if (op_ == 'm' || op_ == 'M') {
|
||||
if (op_ == 'm')
|
||||
o << "min";
|
||||
else
|
||||
o << "max";
|
||||
|
||||
o << "(";
|
||||
left_->dump(o);
|
||||
o << ", ";
|
||||
right_->dump(o);
|
||||
o << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
o << "(";
|
||||
left_->dump(o);
|
||||
o << ")";
|
||||
@@ -1266,6 +1290,9 @@ void NetEUFunc::dump(ostream&o) const
|
||||
void NetEUnary::dump(ostream&o) const
|
||||
{
|
||||
switch (op_) {
|
||||
case 'm':
|
||||
o << "abs";
|
||||
break;
|
||||
case 'N':
|
||||
o << "~|";
|
||||
break;
|
||||
|
||||
+13
-5
@@ -5,7 +5,7 @@ iverilog - Icarus Verilog compiler
|
||||
.SH SYNOPSIS
|
||||
.B iverilog
|
||||
[-ESVv] [-Bpath] [-ccmdfile|-fcmdfile] [-Dmacro[=defn]] [-pflag=value]
|
||||
[-dname] [-g1|-g2|-g2x|-gspecify|-gxtypes|-gio-range-error]
|
||||
[-dname] [-g1995|-g2001|-g2005|-g<feature>]
|
||||
[-Iincludedir] [-mmodule] [-Mfile] [-Nfile] [-ooutputfilename]
|
||||
[-stopmodule] [-ttype] [-Tmin/typ/max] [-Wclass] [-ypath] sourcefile
|
||||
|
||||
@@ -55,15 +55,18 @@ is the Verilog input, but with file inclusions and macro references
|
||||
expanded and removed. This is useful, for example, to preprocess
|
||||
Verilog source for use by other compilers.
|
||||
.TP 8
|
||||
.B -g1\fI|\fP-g2\fI|\fP-g2x
|
||||
.B -g1995\fI|\fP-g2001\fI|\fP-g2005
|
||||
Select the Verilog language \fIgeneration\fP to support in the
|
||||
compiler. This selects between \fIIEEE1364-1995\fP(1),
|
||||
\fIIEEE1364-2001\fP(2), or \fIVerilog with extension\fP(2x). Normally,
|
||||
compiler. This selects between \fIIEEE1364-1995\fP,
|
||||
\fIIEEE1364-2001\fP(2), or \fIIEEE1364-2005\fP. Normally,
|
||||
Icarus Verilog defaults to the latest known generation of the
|
||||
language. This flag is most useful to restrict the language to a set
|
||||
supported by tools of specific generations, for compatibility with
|
||||
other tools.
|
||||
.TP 8
|
||||
.B -gverilog-ams\fI|-fP-gno-verilog-ams
|
||||
Enable or disable (default) support for Verilog-AMS.
|
||||
.TP 8
|
||||
.B -gspecify\fI|\fP-gno-specify
|
||||
Enable (default) or disable specify block support. When enabled,
|
||||
specify block code is elaborated. When disabled, specify blocks are
|
||||
@@ -384,9 +387,14 @@ from preprocessor defines elsewhere in the file or the command line.
|
||||
|
||||
.SH PREDEFINED MACROS
|
||||
|
||||
The following macro is predefined by the compiler:
|
||||
The following macros are predefined by the compiler:
|
||||
.TP 8
|
||||
.B __ICARUS__ = 1\fP
|
||||
This is defined always when compiling with Icarus Verilog.
|
||||
|
||||
.TP 8
|
||||
.B __VAMS_ENABLE__ = 1\fp
|
||||
This is defined if Verilog-AMS is enabled.
|
||||
|
||||
.SH EXAMPLES
|
||||
These examples assume that you have a Verilog source file called hello.v in
|
||||
|
||||
+52
-10
@@ -109,7 +109,9 @@ const char*depfile = 0;
|
||||
const char*generation = "2x";
|
||||
const char*gen_specify = "specify";
|
||||
const char*gen_xtypes = "xtypes";
|
||||
const char*gen_icarus = "icarus-misc";
|
||||
const char*gen_io_range_error = "io-range-error";
|
||||
const char*gen_verilog_ams = "no-verilog-ams";
|
||||
|
||||
/* Boolean: true means use a default include dir, false means don't */
|
||||
int gen_std_include = 1;
|
||||
@@ -430,21 +432,42 @@ void process_file_name(const char*name, int lib_flag)
|
||||
|
||||
int process_generation(const char*name)
|
||||
{
|
||||
if (strcmp(name,"1") == 0)
|
||||
generation = "1";
|
||||
if (strcmp(name,"1995") == 0)
|
||||
generation = "1995";
|
||||
|
||||
else if (strcmp(name,"2") == 0)
|
||||
generation = "2";
|
||||
else if (strcmp(name,"2001") == 0)
|
||||
generation = "2001";
|
||||
|
||||
else if (strcmp(name,"2x") == 0)
|
||||
generation = "2x";
|
||||
else if (strcmp(name,"2005") == 0)
|
||||
generation = "2005";
|
||||
|
||||
else if (strcmp(name,"xtypes") == 0)
|
||||
else if (strcmp(name,"1") == 0) { /* Deprecated: use 1995 */
|
||||
generation = "1995";
|
||||
gen_xtypes = "no-xtypes";
|
||||
gen_icarus = "no-icarus-misc";
|
||||
|
||||
} else if (strcmp(name,"2") == 0) { /* Deprecated: use 2001 */
|
||||
generation = "2001";
|
||||
gen_xtypes = "no-xtypes";
|
||||
gen_icarus = "no-icarus-misc";
|
||||
|
||||
} else if (strcmp(name,"2x") == 0) { /* Deprecated: use 2005/xtypes */
|
||||
generation = "2005";
|
||||
gen_xtypes = "xtypes";
|
||||
gen_icarus = "icarus-misc";
|
||||
|
||||
} else if (strcmp(name,"xtypes") == 0)
|
||||
gen_xtypes = "xtypes";
|
||||
|
||||
else if (strcmp(name,"no-xtypes") == 0)
|
||||
gen_xtypes = "no-xtypes";
|
||||
|
||||
else if (strcmp(name,"icarus-misc") == 0)
|
||||
gen_icarus = "icarus-misc";
|
||||
|
||||
else if (strcmp(name,"no-icarus-misc") == 0)
|
||||
gen_icarus = "no-icarus-misc";
|
||||
|
||||
else if (strcmp(name,"specify") == 0)
|
||||
gen_specify = "specify";
|
||||
|
||||
@@ -463,17 +486,25 @@ int process_generation(const char*name)
|
||||
else if (strcmp(name,"no-io-range-error") == 0)
|
||||
gen_io_range_error = "no-io-range-error";
|
||||
|
||||
else if (strcmp(name,"verilog-ams") == 0)
|
||||
gen_verilog_ams = "verilog-ams";
|
||||
|
||||
else if (strcmp(name,"no-verilog-ams") == 0)
|
||||
gen_verilog_ams = "no-verilog-ams";
|
||||
|
||||
else {
|
||||
fprintf(stderr, "Unknown/Unsupported Language generation "
|
||||
"%s\n\n", name);
|
||||
fprintf(stderr, "Supported generations are:\n");
|
||||
fprintf(stderr, " 1 -- IEEE1364-1995 (Verilog 1)\n"
|
||||
" 2 -- IEEE1364-2001 (Verilog 2001)\n"
|
||||
" 2x -- Verilog with extensions\n"
|
||||
fprintf(stderr, " 1995 -- IEEE1364-1995\n"
|
||||
" 2001 -- IEEE1364-2001\n"
|
||||
" 2005 -- IEEE1364-2005\n"
|
||||
"Other generation flags:\n"
|
||||
" specify | no-specify\n"
|
||||
" verilog-ams | no-verinlog-ams\n"
|
||||
" std-include | no-std-include\n"
|
||||
" xtypes | no-xtypes\n"
|
||||
" icarus-misc | no-icarus-misc\n"
|
||||
" io-range-error | no-io-range-error\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -563,6 +594,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
fprintf(defines_file, "D:__ICARUS__=1\n");
|
||||
if (strcmp(gen_verilog_ams,"verilog-ams") == 0)
|
||||
fprintf(defines_file, "D:__VAMS_ENABLE__=1\n");
|
||||
|
||||
/* Create another temporary file for passing configuration
|
||||
information to ivl. */
|
||||
@@ -727,11 +760,20 @@ int main(int argc, char **argv)
|
||||
how to handle them. */
|
||||
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
||||
|
||||
/* If verilog-ams is enabled, then include the va_math module
|
||||
as well. */
|
||||
if (strcmp(gen_verilog_ams,"verilog-ams") == 0) {
|
||||
fprintf(iconfig_file, "sys_func:%s%cva_math.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "module:va_math\n");
|
||||
}
|
||||
|
||||
if (mtm != 0) fprintf(iconfig_file, "-T:%s\n", mtm);
|
||||
fprintf(iconfig_file, "generation:%s\n", generation);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_specify);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_xtypes);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_io_range_error);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_verilog_ams);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_icarus);
|
||||
fprintf(iconfig_file, "warnings:%s\n", warning_flags);
|
||||
fprintf(iconfig_file, "out:%s\n", opath);
|
||||
if (depfile) fprintf(iconfig_file, "depfile:%s\n", depfile);
|
||||
|
||||
+34
-7
@@ -187,7 +187,7 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
|
||||
/* The % operator does not support real arguments in
|
||||
baseline Verilog. But we allow it in our extended
|
||||
form of Verilog. */
|
||||
if (generation_flag < GN_VER2001X) {
|
||||
if (! gn_icarus_misc_flag) {
|
||||
if (lp->expr_type()==IVL_VT_REAL ||
|
||||
rp->expr_type()==IVL_VT_REAL) {
|
||||
cerr << get_fileline() << ": error: Modulus operator "
|
||||
@@ -311,6 +311,12 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
|
||||
des->errors += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': // min(l,r)
|
||||
case 'M': // max(l,r)
|
||||
tmp = new NetEBMinMax(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
@@ -680,10 +686,13 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Keep track of the concatenation/repeat depth.
|
||||
static int concat_depth = 0;
|
||||
|
||||
NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_wid, bool) const
|
||||
{
|
||||
concat_depth += 1;
|
||||
NetExpr* repeat = 0;
|
||||
|
||||
if (debug_elaborate) {
|
||||
@@ -712,6 +721,15 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
<< "may not be negative (" << rep->value().as_long()
|
||||
<< ")." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rep->value().is_zero() && concat_depth < 2) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be zero in this context." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -752,6 +770,15 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
|
||||
tmp->set_width(wid_sum * tmp->repeat());
|
||||
|
||||
if (wid_sum == 0 && concat_depth < 2) {
|
||||
cerr << get_fileline() << ": error: Concatenation may not "
|
||||
<< "have zero width in this context." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
concat_depth -= 1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -1422,7 +1449,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
}
|
||||
|
||||
|
||||
if (net->sig()->sb_to_idx(msv) >= net->vector_width()) {
|
||||
if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
<< msv << ":" << lsv << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
@@ -1531,7 +1558,8 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
|
||||
// If the part select covers exactly the entire
|
||||
// vector, then do not bother with it. Return the
|
||||
// signal itself.
|
||||
if (net->sig()->sb_to_idx(lsv) == (wid-1) && wid == net->vector_width())
|
||||
if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
|
||||
wid == net->vector_width())
|
||||
return net;
|
||||
|
||||
// Otherwise, make a part select that covers the right range.
|
||||
@@ -1839,16 +1867,15 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
|
||||
if (expr_wid > 0)
|
||||
val = pad_to_width(val, expr_wid);
|
||||
|
||||
/* When taking the - of a number, turn it into a
|
||||
signed expression and extend it one bit to
|
||||
accommodate a possible sign bit. */
|
||||
/* When taking the - of a number, extend it one
|
||||
bit to accommodate a possible sign bit. */
|
||||
verinum zero (verinum::V0, val.len()+1, val.has_len());
|
||||
zero.has_sign(val.has_sign());
|
||||
verinum nval = zero - val;
|
||||
|
||||
if (val.has_len())
|
||||
nval = verinum(nval, val.len());
|
||||
nval.has_sign(true);
|
||||
nval.has_sign(val.has_sign());
|
||||
tmp = new NetEConst(nval);
|
||||
tmp->set_line(*this);
|
||||
delete ip;
|
||||
|
||||
+163
-22
@@ -808,7 +808,7 @@ NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope,
|
||||
|
||||
/* The % operator does not support real arguments in baseline
|
||||
Verilog. But we allow it in our extended form of Verilog. */
|
||||
if (generation_flag < GN_VER2001X && lsig->data_type() == IVL_VT_REAL) {
|
||||
if (gn_icarus_misc_flag==false && lsig->data_type() == IVL_VT_REAL) {
|
||||
cerr << get_fileline() << ": error: Modulus operator may not "
|
||||
"have REAL operands." << endl;
|
||||
des->errors += 1;
|
||||
@@ -1591,7 +1591,7 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
|
||||
|
||||
if (repeat == 0) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
"may not be 0."
|
||||
"may not be zero."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
@@ -1689,7 +1689,6 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
osig->local_flag(true);
|
||||
return osig;
|
||||
}
|
||||
@@ -1895,10 +1894,11 @@ NetNet* PEIdent::process_select_(Design*des, NetScope*scope,
|
||||
// dimensions, then treat them as word part selects. For
|
||||
// example, if this is a memory array, then array dimensions
|
||||
// is the first and part select the remainder.
|
||||
unsigned midx, lidx;
|
||||
long midx, lidx;
|
||||
if (! eval_part_select_(des, scope, sig, midx, lidx))
|
||||
return sig;
|
||||
|
||||
ivl_assert(*this, lidx >= 0);
|
||||
unsigned part_count = midx-lidx+1;
|
||||
|
||||
// Maybe this is a full-width constant part select? If
|
||||
@@ -1964,12 +1964,70 @@ NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope,
|
||||
delete mval;
|
||||
}
|
||||
|
||||
unsigned midx, lidx;
|
||||
long midx, lidx;
|
||||
if (! eval_part_select_(des, scope, sig, midx, lidx))
|
||||
return 0;
|
||||
|
||||
unsigned part_count = midx-lidx+1;
|
||||
unsigned output_width = part_count;
|
||||
|
||||
/* Detect and handle the special case that the entire part
|
||||
select is outside the range of the signal. Return a
|
||||
constant xxx. */
|
||||
if (midx < 0 || lidx >= (long)sig->vector_width()) {
|
||||
ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC);
|
||||
verinum xxx (verinum::Vx, part_count);
|
||||
NetConst*con = new NetConst(scope, scope->local_symbol(), xxx);
|
||||
con->set_line(*sig);
|
||||
des->add_node(con);
|
||||
|
||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, part_count-1, 0);
|
||||
tmp->data_type( sig->data_type() );
|
||||
tmp->local_flag(true);
|
||||
connect(tmp->pin(0), con->pin(0));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetNet*below = 0;
|
||||
if (lidx < 0) {
|
||||
ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC);
|
||||
unsigned xxx_wid = 0-lidx;
|
||||
verinum xxx (verinum::Vx, xxx_wid);
|
||||
NetConst*con = new NetConst(scope, scope->local_symbol(), xxx);
|
||||
con->set_line(*sig);
|
||||
des->add_node(con);
|
||||
|
||||
below = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, xxx_wid);
|
||||
below->data_type( sig->data_type() );
|
||||
below->local_flag(true);
|
||||
connect(below->pin(0), con->pin(0));
|
||||
|
||||
lidx = 0;
|
||||
part_count = midx-lidx+1;
|
||||
}
|
||||
|
||||
NetNet*above = 0;
|
||||
if (midx >= (long)sig->vector_width()) {
|
||||
ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC);
|
||||
unsigned xxx_wid = midx - sig->vector_width() + 1;
|
||||
verinum xxx (verinum::Vx, xxx_wid);
|
||||
NetConst*con = new NetConst(scope, scope->local_symbol(), xxx);
|
||||
con->set_line(*sig);
|
||||
des->add_node(con);
|
||||
|
||||
above = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, xxx_wid);
|
||||
above->data_type( sig->data_type() );
|
||||
above->local_flag(true);
|
||||
connect(above->pin(0), con->pin(0));
|
||||
|
||||
midx = sig->vector_width()-1;
|
||||
part_count = midx-lidx+1;
|
||||
}
|
||||
|
||||
ivl_assert(*this, lidx >= 0);
|
||||
if (part_count != sig->vector_width()) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Elaborate part select "
|
||||
@@ -1991,7 +2049,36 @@ NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope,
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
unsigned segment_count = 1;
|
||||
if (below) segment_count += 1;
|
||||
if (above) segment_count += 1;
|
||||
if (segment_count > 1) {
|
||||
NetConcat*cc = new NetConcat(scope, scope->local_symbol(),
|
||||
output_width, segment_count);
|
||||
cc->set_line(*sig);
|
||||
des->add_node(cc);
|
||||
|
||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, output_width);
|
||||
tmp->data_type( sig->data_type() );
|
||||
tmp->local_flag(true);
|
||||
connect(tmp->pin(0), cc->pin(0));
|
||||
|
||||
unsigned pdx = 1;
|
||||
if (below) {
|
||||
connect(cc->pin(pdx), below->pin(0));
|
||||
pdx += 1;
|
||||
}
|
||||
connect(cc->pin(pdx), sig->pin(0));
|
||||
pdx += 1;
|
||||
if (above) {
|
||||
connect(cc->pin(pdx), above->pin(0));
|
||||
pdx += 1;
|
||||
}
|
||||
ivl_assert(*sig, segment_count == pdx-1);
|
||||
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
@@ -2386,7 +2473,7 @@ NetNet* PEIdent::make_implicit_net_(Design*des, NetScope*scope) const
|
||||
* anything in between. The values are in canonical indices.
|
||||
*/
|
||||
bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
unsigned&midx, unsigned&lidx) const
|
||||
long&midx, long&lidx) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
// Only treat as part/bit selects any index that is beyond the
|
||||
@@ -2450,31 +2537,36 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
long msb, lsb;
|
||||
/* bool flag = */ calculate_parts_(des, scope, msb, lsb);
|
||||
|
||||
lidx = sig->sb_to_idx(lsb);
|
||||
midx = sig->sb_to_idx(msb);
|
||||
long lidx_tmp = sig->sb_to_idx(lsb);
|
||||
long midx_tmp = sig->sb_to_idx(msb);
|
||||
/* Detect reversed indices of a part select. */
|
||||
if (lidx > midx) {
|
||||
if (lidx_tmp > midx_tmp) {
|
||||
cerr << get_fileline() << ": error: Part select "
|
||||
<< sig->name() << "[" << msb << ":"
|
||||
<< lsb << "] indices reversed." << endl;
|
||||
cerr << get_fileline() << ": : Did you mean "
|
||||
<< sig->name() << "[" << lsb << ":"
|
||||
<< msb << "]?" << endl;
|
||||
unsigned tmp = midx;
|
||||
midx = lidx;
|
||||
lidx = tmp;
|
||||
long tmp = midx_tmp;
|
||||
midx_tmp = lidx_tmp;
|
||||
lidx_tmp = tmp;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
/* Detect a part select out of range. */
|
||||
if (midx >= sig->vector_width()) {
|
||||
cerr << get_fileline() << ": error: Part select "
|
||||
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
|
||||
cerr << get_fileline() << ": warning: Part select "
|
||||
<< sig->name() << "[" << msb << ":"
|
||||
<< lsb << "] out of range." << endl;
|
||||
midx = sig->vector_width() - 1;
|
||||
lidx = 0;
|
||||
#if 0
|
||||
midx_tmp = sig->vector_width() - 1;
|
||||
lidx_tmp = 0;
|
||||
des->errors += 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
midx = midx_tmp;
|
||||
lidx = lidx_tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2495,7 +2587,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
assert(mval);
|
||||
|
||||
midx = sig->sb_to_idx(mval->as_long());
|
||||
if (midx >= sig->vector_width()) {
|
||||
if (midx >= (long)sig->vector_width()) {
|
||||
cerr << get_fileline() << ": error: Index " << sig->name()
|
||||
<< "[" << mval->as_long() << "] out of range."
|
||||
<< endl;
|
||||
@@ -2611,12 +2703,21 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
|
||||
/* The array has a part/bit select at the end. */
|
||||
if (name_tail.index.size() > sig->array_dimensions()) {
|
||||
if (! eval_part_select_(des, scope, sig, midx, lidx))
|
||||
long midx_tmp, lidx_tmp;
|
||||
if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
|
||||
return 0;
|
||||
ivl_assert(*this, lidx_tmp >= 0);
|
||||
midx = midx_tmp;
|
||||
lidx = lidx_tmp;
|
||||
}
|
||||
} else if (!name_tail.index.empty()) {
|
||||
if (! eval_part_select_(des, scope, sig, midx, lidx))
|
||||
long midx_tmp, lidx_tmp;
|
||||
if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
|
||||
return 0;
|
||||
|
||||
ivl_assert(*this, lidx_tmp >= 0);
|
||||
midx = midx_tmp;
|
||||
lidx = lidx_tmp;
|
||||
}
|
||||
|
||||
unsigned subnet_wid = midx-lidx+1;
|
||||
@@ -2738,8 +2839,8 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned midx;
|
||||
unsigned lidx;
|
||||
long midx;
|
||||
long lidx;
|
||||
|
||||
/* Evaluate the part/bit select expressions, to get the part
|
||||
select of the signal that attaches to the port. Also handle
|
||||
@@ -3213,6 +3314,33 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
|
||||
connect(gate->pin(0), sig->pin(0));
|
||||
break;
|
||||
|
||||
case 'm': // abs(sub_sig)
|
||||
// If this expression is self determined, get its width
|
||||
// from the sub_expression.
|
||||
if (owidth == 0)
|
||||
owidth = sub_sig->vector_width();
|
||||
|
||||
if (sub_sig->vector_width() < owidth)
|
||||
sub_sig = pad_to_width(des, sub_sig, owidth);
|
||||
|
||||
sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, owidth);
|
||||
sig->set_line(*this);
|
||||
sig->data_type(sub_sig->data_type());
|
||||
sig->local_flag(true);
|
||||
|
||||
{ NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub_sig->vector_width());
|
||||
tmp->set_line(*this);
|
||||
des->add_node(tmp);
|
||||
tmp->rise_time(rise);
|
||||
tmp->fall_time(fall);
|
||||
tmp->decay_time(decay);
|
||||
|
||||
connect(tmp->pin(1), sub_sig->pin(0));
|
||||
connect(tmp->pin(0), sig->pin(0));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N': // Reduction NOR
|
||||
case '!': // Reduction NOT
|
||||
reduction=true; rtype = NetUReduce::NOR; break;
|
||||
@@ -3291,7 +3419,7 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << "internal error: Unhandled UNARY '" << op_ << "'" << endl;
|
||||
cerr << get_fileline() << ": internal error: Unhandled UNARY '" << op_ << "'" << endl;
|
||||
sig = 0;
|
||||
}
|
||||
|
||||
@@ -3466,6 +3594,19 @@ NetNet* PEUnary::elab_net_unary_real_(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
break;
|
||||
|
||||
case 'm': { // abs()
|
||||
NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), 1);
|
||||
tmp->set_line(*this);
|
||||
tmp->rise_time(rise);
|
||||
tmp->fall_time(fall);
|
||||
tmp->decay_time(decay);
|
||||
des->add_node(tmp);
|
||||
|
||||
connect(tmp->pin(0), sig->pin(0));
|
||||
connect(tmp->pin(1), sub_sig->pin(0));
|
||||
break;
|
||||
}
|
||||
|
||||
case '-':
|
||||
NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(), 1);
|
||||
sub->attribute(perm_string::literal("LPM_Direction"),
|
||||
|
||||
+41
-8
@@ -45,7 +45,8 @@
|
||||
# include <assert.h>
|
||||
|
||||
void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
Design*des, NetScope*scope)
|
||||
Design*des, NetScope*scope,
|
||||
perm_string file, unsigned lineno)
|
||||
{
|
||||
PExpr*ex = cur.expr;
|
||||
assert(ex);
|
||||
@@ -81,7 +82,7 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
}
|
||||
|
||||
val = scope->set_parameter(name, val,
|
||||
msb, lsb, signed_flag);
|
||||
msb, lsb, signed_flag, file, lineno);
|
||||
assert(val);
|
||||
delete val;
|
||||
}
|
||||
@@ -119,7 +120,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
tmp->set_line(*((*cur).second.expr));
|
||||
tmp->cast_signed( (*cur).second.signed_flag );
|
||||
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false);
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
}
|
||||
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
@@ -130,7 +132,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
if ((*cur).second.msb)
|
||||
tmp->cast_signed( (*cur).second.signed_flag );
|
||||
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false);
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +145,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
for (mparm_it_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
}
|
||||
|
||||
/* run parameter replacements that were collected from the
|
||||
@@ -174,7 +178,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
; cur != localparams.end() ; cur ++) {
|
||||
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
}
|
||||
|
||||
// Run through the defparams for this module, elaborate the
|
||||
@@ -240,6 +245,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
}
|
||||
NetScope*task_scope = new NetScope(scope, use_name,
|
||||
NetScope::TASK);
|
||||
task_scope->set_line((*cur).second);
|
||||
(*cur).second->elaborate_scope(des, task_scope);
|
||||
}
|
||||
|
||||
@@ -263,6 +269,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
}
|
||||
NetScope*func_scope = new NetScope(scope, use_name,
|
||||
NetScope::FUNC);
|
||||
func_scope->set_line((*cur).second);
|
||||
(*cur).second->elaborate_scope(des, func_scope);
|
||||
}
|
||||
|
||||
@@ -337,6 +344,11 @@ bool PGenerate::generate_scope(Design*des, NetScope*container)
|
||||
*/
|
||||
bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
{
|
||||
// Check that the loop_index variable was declared in a
|
||||
// genvar statement.
|
||||
|
||||
// MISSING CODE!
|
||||
|
||||
// We're going to need a genvar...
|
||||
int genvar;
|
||||
|
||||
@@ -352,12 +364,24 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Since we will be adding the genvar value as a local parameter
|
||||
// to each instances scope. We need to make sure a parameter does
|
||||
// not already exist.
|
||||
const NetExpr*tmsb;
|
||||
const NetExpr*tlsb;
|
||||
const NetExpr*texpr = container->get_parameter(loop_index, tmsb, tlsb);
|
||||
if (texpr != 0) {
|
||||
cerr << get_fileline() << ": error: Cannot have a genvar "
|
||||
<< "and parameter with the same name: " << loop_index << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
genvar = init->value().as_long();
|
||||
delete init_ex;
|
||||
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: genvar init = " << genvar << endl;
|
||||
|
||||
container->genvar_tmp = loop_index;
|
||||
container->genvar_tmp_val = genvar;
|
||||
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
@@ -383,6 +407,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
|
||||
NetScope*scope = new NetScope(container, use_name,
|
||||
NetScope::GENBLOCK);
|
||||
scope->set_line(get_file(), get_lineno());
|
||||
|
||||
// Set in the scope a localparam for the value of the
|
||||
// genvar within this instance of the generate
|
||||
@@ -394,7 +419,10 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
NetEConstParam*gp = new NetEConstParam(scope,
|
||||
loop_index,
|
||||
genvar_verinum);
|
||||
scope->set_localparam(loop_index, gp);
|
||||
// The file and line information should really come
|
||||
// from the genvar statement, not the for loop.
|
||||
scope->set_localparam(loop_index, gp, get_file(),
|
||||
get_lineno());
|
||||
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
@@ -463,6 +491,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
|
||||
|
||||
NetScope*scope = new NetScope(container, use_name,
|
||||
NetScope::GENBLOCK);
|
||||
scope->set_line(get_file(), get_lineno());
|
||||
|
||||
elaborate_subscope_(des, scope);
|
||||
|
||||
@@ -529,6 +558,7 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
||||
|
||||
NetScope*scope = new NetScope(container, use_name,
|
||||
NetScope::GENBLOCK);
|
||||
scope->set_line(get_file(), get_lineno());
|
||||
item->elaborate_subscope_(des, scope);
|
||||
|
||||
return true;
|
||||
@@ -661,6 +691,8 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
||||
|
||||
// Create the new scope as a MODULE with my name.
|
||||
NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE);
|
||||
my_scope->set_line(get_file(), mod->get_file(),
|
||||
get_lineno(), mod->get_lineno());
|
||||
my_scope->set_module_name(mod->mod_name());
|
||||
my_scope->default_nettype(mod->default_nettype);
|
||||
|
||||
@@ -811,6 +843,7 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
|
||||
my_scope = new NetScope(scope, use_name, bl_type_==BL_PAR
|
||||
? NetScope::FORK_JOIN
|
||||
: NetScope::BEGIN_END);
|
||||
my_scope->set_line(get_file(), get_lineno());
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1)
|
||||
|
||||
+13
-1
@@ -323,7 +323,7 @@ bool PGAssign::elaborate_sig(Design*des, NetScope*scope) const
|
||||
to implicitly declare nets. However, so many tools do allow
|
||||
it that Icarus Verilog will allow it, at least if extensions
|
||||
are enabled. */
|
||||
if (generation_flag == GN_VER2001X)
|
||||
if (gn_icarus_misc_flag)
|
||||
return pin(0)->elaborate_sig(des, scope);
|
||||
|
||||
return true;
|
||||
@@ -758,6 +758,18 @@ void PForStatement::elaborate_sig(Design*des, NetScope*scope) const
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
void PRepeat::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
void PWhile::elaborate_sig(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (statement_)
|
||||
statement_->elaborate_sig(des, scope);
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate a source wire. The "wire" is the declaration of wires,
|
||||
* registers, ports and memories. The parser has already merged the
|
||||
|
||||
+2
-1
@@ -1711,7 +1711,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
||||
netlist. The compound statement is exactly equivalent. */
|
||||
|
||||
if (delay || event_) {
|
||||
unsigned wid = lv->lwidth();
|
||||
unsigned wid = count_lval_width(lv);
|
||||
|
||||
rv->set_width(wid);
|
||||
rv = pad_to_width(rv, wid);
|
||||
@@ -3707,6 +3707,7 @@ Design* elaborate(list<perm_string>roots)
|
||||
|
||||
// Make the root scope.
|
||||
NetScope*scope = des->make_root_scope(*root);
|
||||
scope->set_line(rmod);
|
||||
scope->time_unit(rmod->time_unit);
|
||||
scope->time_precision(rmod->time_precision);
|
||||
scope->default_nettype(rmod->default_nettype);
|
||||
|
||||
@@ -49,6 +49,12 @@ bool NetUDP::emit_node(struct target_t*tgt) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetAbs::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_abs(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetAddSub::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_add_sub(this);
|
||||
|
||||
+6
-1
@@ -1217,7 +1217,12 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
|
||||
// The result can be saved as the value of the parameter for
|
||||
// future reference, and return a copy to the caller.
|
||||
scope_->replace_parameter(name_, res);
|
||||
bool flag = scope_->replace_parameter(name_, res);
|
||||
if (!flag) {
|
||||
cerr << get_fileline() << ": internal error: Could not "
|
||||
<< "replace parameter expression for " << name_ << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return as a result a NetEConstParam or NetECRealParam
|
||||
object, depending on the type of the expression. */
|
||||
|
||||
+8
-1
@@ -235,6 +235,8 @@ NetNet* NetEBComp::synthesize(Design*des)
|
||||
osig->local_flag(true);
|
||||
osig->data_type(IVL_VT_LOGIC);
|
||||
|
||||
bool signed_compare = lsig->get_signed() && rsig->get_signed();
|
||||
|
||||
/* Handle the special case of a single bit equality
|
||||
operation. Make an XNOR gate instead of a comparator. */
|
||||
if ((width == 1) && ((op_ == 'e') || (op_ == 'E')) && !real_args) {
|
||||
@@ -274,9 +276,11 @@ NetNet* NetEBComp::synthesize(Design*des)
|
||||
switch (op_) {
|
||||
case '<':
|
||||
connect(dev->pin_ALB(), osig->pin(0));
|
||||
dev->set_signed(signed_compare);
|
||||
break;
|
||||
case '>':
|
||||
connect(dev->pin_AGB(), osig->pin(0));
|
||||
dev->set_signed(signed_compare);
|
||||
break;
|
||||
case 'E': // === ?
|
||||
if (real_args) {
|
||||
@@ -290,9 +294,11 @@ NetNet* NetEBComp::synthesize(Design*des)
|
||||
break;
|
||||
case 'G': // >=
|
||||
connect(dev->pin_AGEB(), osig->pin(0));
|
||||
dev->set_signed(signed_compare);
|
||||
break;
|
||||
case 'L': // <=
|
||||
connect(dev->pin_ALEB(), osig->pin(0));
|
||||
dev->set_signed(signed_compare);
|
||||
break;
|
||||
case 'N': // !==
|
||||
if (real_args) {
|
||||
@@ -432,7 +438,7 @@ NetNet* NetEBDiv::synthesize(Design*des)
|
||||
case '%': {
|
||||
/* Baseline Verilog does not support the % operator with
|
||||
real arguments, but we allow it in our extended form. */
|
||||
if (real_args && generation_flag < GN_VER2001X) {
|
||||
if (real_args && !gn_icarus_misc_flag) {
|
||||
cerr << get_fileline() << ": error: Modulus operator "
|
||||
"may not have REAL operands." << endl;
|
||||
des->errors += 1;
|
||||
@@ -923,6 +929,7 @@ NetNet* NetESelect::synthesize(Design *des)
|
||||
|
||||
connect(pad->pin(1), sub->pin(0));
|
||||
connect(pad->pin(0), net->pin(0));
|
||||
net->set_signed(true);
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
@@ -40,6 +40,10 @@ void functor_t::process(class Design*, class NetProcTop*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_abs(class Design*, class NetAbs*)
|
||||
{
|
||||
}
|
||||
|
||||
void functor_t::lpm_add_sub(class Design*, class NetAddSub*)
|
||||
{
|
||||
}
|
||||
@@ -174,6 +178,11 @@ void NetNode::functor_node(Design*, functor_t*)
|
||||
{
|
||||
}
|
||||
|
||||
void NetAbs::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_abs(des, this);
|
||||
}
|
||||
|
||||
void NetAddSub::functor_node(Design*des, functor_t*fun)
|
||||
{
|
||||
fun->lpm_add_sub(des, this);
|
||||
|
||||
@@ -48,6 +48,9 @@ struct functor_t {
|
||||
/* This method is called for each process in the design. */
|
||||
virtual void process(class Design*des, class NetProcTop*);
|
||||
|
||||
/* This method is called for each structural abs(). */
|
||||
virtual void lpm_abs(class Design*des, class NetAbs*);
|
||||
|
||||
/* This method is called for each structural adder. */
|
||||
virtual void lpm_add_sub(class Design*des, class NetAddSub*);
|
||||
|
||||
|
||||
@@ -118,6 +118,8 @@ ivl_nexus_ptr_sig
|
||||
|
||||
ivl_parameter_basename
|
||||
ivl_parameter_expr
|
||||
ivl_parameter_file
|
||||
ivl_parameter_lineno
|
||||
|
||||
ivl_path_condit
|
||||
ivl_path_delay
|
||||
@@ -132,8 +134,12 @@ ivl_scope_attr_val
|
||||
ivl_scope_basename
|
||||
ivl_scope_children
|
||||
ivl_scope_def
|
||||
ivl_scope_def_file
|
||||
ivl_scope_def_lineno
|
||||
ivl_scope_event
|
||||
ivl_scope_events
|
||||
ivl_scope_file
|
||||
ivl_scope_lineno
|
||||
ivl_scope_logs
|
||||
ivl_scope_log
|
||||
ivl_scope_lpms
|
||||
@@ -159,7 +165,9 @@ ivl_signal_attr_val
|
||||
ivl_signal_basename
|
||||
ivl_signal_data_type
|
||||
ivl_signal_dimensions
|
||||
ivl_signal_file
|
||||
ivl_signal_integer
|
||||
ivl_signal_lineno
|
||||
ivl_signal_local
|
||||
ivl_signal_lsb
|
||||
ivl_signal_msb
|
||||
|
||||
@@ -228,6 +228,7 @@ typedef enum ivl_logic_e {
|
||||
|
||||
/* This is the type of an LPM object. */
|
||||
typedef enum ivl_lpm_type_e {
|
||||
IVL_LPM_ABS = 32,
|
||||
IVL_LPM_ADD = 0,
|
||||
IVL_LPM_ARRAY = 30,
|
||||
IVL_LPM_CONCAT = 16,
|
||||
@@ -1339,11 +1340,18 @@ extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net);
|
||||
* ivl_parameter_expr
|
||||
* Return the value of the parameter. This should be a simple
|
||||
* constant expression, an IVL_EX_STRING or IVL_EX_NUMBER.
|
||||
*
|
||||
* ivl_parameter_file
|
||||
* ivl_parameter_lineno
|
||||
* Returns the file and line where this parameter is define
|
||||
*/
|
||||
extern const char* ivl_parameter_basename(ivl_parameter_t net);
|
||||
extern ivl_scope_t ivl_parameter_scope(ivl_parameter_t net);
|
||||
extern ivl_expr_t ivl_parameter_expr(ivl_parameter_t net);
|
||||
|
||||
extern const char* ivl_parameter_file(ivl_parameter_t net);
|
||||
extern unsigned ivl_parameter_lineno(ivl_parameter_t net);
|
||||
|
||||
|
||||
/* SCOPE
|
||||
* Scopes of various sort have these properties. Use these methods to
|
||||
@@ -1391,10 +1399,18 @@ extern ivl_expr_t ivl_parameter_expr(ivl_parameter_t net);
|
||||
* ivl_scope_def function must return a statement for scopes that
|
||||
* are type FUNCTION or TASK, and must return nil otherwise.
|
||||
*
|
||||
* ivl_scope_def_file
|
||||
* ivl_scope_def_lineno
|
||||
* Returns the file and line where this scope is defined.
|
||||
*
|
||||
* ivl_scope_event
|
||||
* ivl_scope_events
|
||||
* Scopes have 0 or more event objects in them.
|
||||
*
|
||||
* ivl_scope_file
|
||||
* ivl_scope_lineno
|
||||
* Returns the instantiation file and line for this scope.
|
||||
*
|
||||
* ivl_scope_var
|
||||
* ivl_scope_vars
|
||||
* REMOVED
|
||||
@@ -1465,9 +1481,13 @@ extern int ivl_scope_children(ivl_scope_t net,
|
||||
ivl_scope_f func, void*cd);
|
||||
|
||||
extern ivl_statement_t ivl_scope_def(ivl_scope_t net);
|
||||
extern const char* ivl_scope_def_file(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_def_lineno(ivl_scope_t net);
|
||||
|
||||
extern unsigned ivl_scope_events(ivl_scope_t net);
|
||||
extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx);
|
||||
extern const char* ivl_scope_file(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_lineno(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_logs(ivl_scope_t net);
|
||||
extern ivl_net_logic_t ivl_scope_log(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_lpms(ivl_scope_t net);
|
||||
@@ -1574,6 +1594,10 @@ extern int ivl_scope_time_units(ivl_scope_t net);
|
||||
* the attribute value (a string) associated with a key. This
|
||||
* function returns the attribute value for the given key. If the
|
||||
* key does not exist, the function returns 0.
|
||||
*
|
||||
* ivl_signal_file
|
||||
* ivl_signal_lineno
|
||||
* Returns the file and line where this signal is defined.
|
||||
*/
|
||||
|
||||
extern ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word);
|
||||
@@ -1595,6 +1619,9 @@ extern const char* ivl_signal_name(ivl_signal_t net);
|
||||
extern const char* ivl_signal_basename(ivl_signal_t net);
|
||||
extern const char* ivl_signal_attr(ivl_signal_t net, const char*key);
|
||||
|
||||
extern const char* ivl_signal_file(ivl_signal_t net);
|
||||
extern unsigned ivl_signal_lineno(ivl_signal_t net);
|
||||
|
||||
extern unsigned ivl_signal_attr_cnt(ivl_signal_t net);
|
||||
extern ivl_attribute_t ivl_signal_attr_val(ivl_signal_t net, unsigned idx);
|
||||
|
||||
|
||||
+35
-22
@@ -42,7 +42,7 @@ static void do_define();
|
||||
static int def_is_done();
|
||||
static int is_defined(const char*name);
|
||||
|
||||
static int macro_needs_args();
|
||||
static int macro_needs_args(const char*name);
|
||||
static void macro_start_args();
|
||||
static void macro_add_to_arg();
|
||||
static void macro_finish_arg();
|
||||
@@ -72,6 +72,8 @@ struct include_stack_t
|
||||
*/
|
||||
int ebs;
|
||||
|
||||
int stringify_flag;
|
||||
|
||||
unsigned lineno;
|
||||
YY_BUFFER_STATE yybs;
|
||||
|
||||
@@ -86,6 +88,8 @@ static void emit_pathline(struct include_stack_t* isp);
|
||||
*/
|
||||
static struct include_stack_t* file_queue = 0;
|
||||
|
||||
static int do_expand_stringify_flag = 0;
|
||||
|
||||
/*
|
||||
* The istack is the inclusion stack.
|
||||
*/
|
||||
@@ -245,7 +249,7 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
||||
}
|
||||
|
||||
<PCOMENT>`[a-zA-Z][a-zA-Z0-9_$]* {
|
||||
if (macro_needs_args()) yy_push_state(MA_START); else do_expand(0);
|
||||
if (macro_needs_args(yytext+1)) yy_push_state(MA_START); else do_expand(0);
|
||||
}
|
||||
|
||||
/* Strings do not contain preprocessor directives, but can expand
|
||||
@@ -262,21 +266,6 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
||||
<CSTRING>\" { BEGIN(string_enter); ECHO; }
|
||||
<CSTRING>. { ECHO; }
|
||||
|
||||
<CSTRING>`{keywords} {
|
||||
emit_pathline(istack);
|
||||
error_count += 1;
|
||||
fprintf
|
||||
(
|
||||
stderr,
|
||||
"error: macro names cannot be directive keywords ('%s'); replaced with nothing.\n",
|
||||
yytext
|
||||
);
|
||||
}
|
||||
|
||||
<CSTRING>`[a-zA-Z][a-zA-Z0-9_$]* {
|
||||
if (macro_needs_args()) yy_push_state(MA_START); else do_expand(0);
|
||||
}
|
||||
|
||||
/* This set of patterns matches the include directive and the name
|
||||
* that follows it. when the directive ends, the do_include function
|
||||
* performs the include operation.
|
||||
@@ -295,7 +284,7 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
||||
}
|
||||
|
||||
<PPINCLUDE>`[a-zA-Z][a-zA-Z0-9_]* {
|
||||
if (macro_needs_args()) yy_push_state(MA_START); else do_expand(0);
|
||||
if (macro_needs_args(yytext+1)) yy_push_state(MA_START); else do_expand(0);
|
||||
}
|
||||
|
||||
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
|
||||
@@ -551,12 +540,23 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
|
||||
|
||||
/* This pattern notices macros and arranges for them to be replaced. */
|
||||
`[a-zA-Z_][a-zA-Z0-9_$]* {
|
||||
if (macro_needs_args())
|
||||
if (macro_needs_args(yytext+1))
|
||||
yy_push_state(MA_START);
|
||||
else
|
||||
do_expand(0);
|
||||
}
|
||||
|
||||
/* Stringified version of macro expansion. */
|
||||
``[a-zA-Z_][a-zA-Z0-9_$]* {
|
||||
assert(do_expand_stringify_flag == 0);
|
||||
do_expand_stringify_flag = 1;
|
||||
fputc('"', yyout);
|
||||
if (macro_needs_args(yytext+2))
|
||||
yy_push_state(MA_START);
|
||||
else
|
||||
do_expand(0);
|
||||
}
|
||||
|
||||
<MA_START>\( { BEGIN(MA_ADD); macro_start_args(); }
|
||||
|
||||
<MA_START>{W} {}
|
||||
@@ -1171,16 +1171,16 @@ static void def_undefine()
|
||||
*/
|
||||
static struct define_t* cur_macro = 0;
|
||||
|
||||
static int macro_needs_args()
|
||||
static int macro_needs_args(const char*text)
|
||||
{
|
||||
cur_macro = def_lookup(yytext+1);
|
||||
cur_macro = def_lookup(text);
|
||||
|
||||
if (cur_macro)
|
||||
return (cur_macro->argc > 1);
|
||||
else
|
||||
{
|
||||
emit_pathline(istack);
|
||||
fprintf(stderr, "warning: macro %s undefined (and assumed null) at this point.\n", yytext);
|
||||
fprintf(stderr, "warning: macro %s undefined (and assumed null) at this point.\n", text);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1348,6 +1348,8 @@ static void do_expand(int use_args)
|
||||
|
||||
isp = (struct include_stack_t*) calloc(1, sizeof(struct include_stack_t));
|
||||
|
||||
isp->stringify_flag = do_expand_stringify_flag;
|
||||
do_expand_stringify_flag = 0;
|
||||
if (use_args)
|
||||
{
|
||||
isp->str = &exp_buf[head];
|
||||
@@ -1364,6 +1366,11 @@ static void do_expand(int use_args)
|
||||
istack = isp;
|
||||
|
||||
yy_switch_to_buffer(yy_create_buffer(istack->file, YY_BUF_SIZE));
|
||||
} else {
|
||||
if (do_expand_stringify_flag) {
|
||||
do_expand_stringify_flag = 0;
|
||||
fputc('"', yyout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1464,6 +1471,7 @@ static void do_include()
|
||||
fprintf(yyout, "\n`line %u \"%s\" 1\n", istack->lineno+1, standby->path);
|
||||
|
||||
standby->next = istack;
|
||||
standby->stringify_flag = 0;
|
||||
|
||||
istack->yybs = YY_CURRENT_BUFFER;
|
||||
istack = standby;
|
||||
@@ -1537,6 +1545,10 @@ static int load_next_input()
|
||||
exp_buf_free += isp->ebs;
|
||||
}
|
||||
|
||||
if (isp->stringify_flag) {
|
||||
fputc('"', yyout);
|
||||
}
|
||||
|
||||
free(isp);
|
||||
|
||||
/* If I am out of include stack, the main input is
|
||||
@@ -1699,6 +1711,7 @@ void reset_lexor(FILE* out, char* paths[])
|
||||
isp->str = 0;
|
||||
isp->ebs = 0;
|
||||
isp->lineno = 0;
|
||||
isp->stringify_flag = 0;
|
||||
|
||||
if (isp->file == 0)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
# include <ctype.h>
|
||||
# include <string.h>
|
||||
# include "lexor_keyword.h"
|
||||
|
||||
# include <list>
|
||||
|
||||
# define YY_USER_INIT reset_lexor();
|
||||
# define yylval VLlval
|
||||
@@ -83,6 +83,8 @@ static int dec_buf_div2(char *buf);
|
||||
|
||||
static void process_timescale(const char*txt);
|
||||
|
||||
static list<int> keyword_mask_stack;
|
||||
|
||||
static int comment_enter;
|
||||
%}
|
||||
|
||||
@@ -93,10 +95,14 @@ static int comment_enter;
|
||||
%s UDPTABLE
|
||||
%x PPTIMESCALE
|
||||
%x PPDEFAULT_NETTYPE
|
||||
%x PPBEGIN_KEYWORDS
|
||||
%s EDGES
|
||||
%x REAL_SCALE
|
||||
|
||||
W [ \t\b\f\r]+
|
||||
|
||||
S [afpnumkKMGT]
|
||||
|
||||
%%
|
||||
|
||||
^"#line"[ ]+\"[^\"]*\"[ ]+[0-9]+.* { line_directive(); }
|
||||
@@ -215,17 +221,6 @@ W [ \t\b\f\r]+
|
||||
rc = PATHPULSE_IDENTIFIER;
|
||||
break;
|
||||
|
||||
case K_bool:
|
||||
case K_logic:
|
||||
case K_wone:
|
||||
if (! gn_cadence_types_enabled()) {
|
||||
yylval.text = strdupnew(yytext);
|
||||
rc = IDENTIFIER;
|
||||
} else {
|
||||
yylval.text = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case K_edge:
|
||||
BEGIN(EDGES);
|
||||
break;
|
||||
@@ -280,6 +275,46 @@ W [ \t\b\f\r]+
|
||||
based_size = yylval.number->as_ulong();
|
||||
return DEC_NUMBER; }
|
||||
|
||||
/* These rules handle the scaled real literals from Verilog-AMS. The
|
||||
value is a number with a single letter scale factor. If
|
||||
verilog-ams is not enabled, then reject this rule. If it is
|
||||
enabled, then collect the scale and use it to scale the value. */
|
||||
[0-9][0-9_]*\.[0-9][0-9_]*/{S} {
|
||||
if (!gn_verilog_ams_flag) REJECT;
|
||||
BEGIN(REAL_SCALE);
|
||||
yymore(); }
|
||||
|
||||
[0-9][0-9_]*/{S} {
|
||||
if (!gn_verilog_ams_flag) REJECT;
|
||||
BEGIN(REAL_SCALE);
|
||||
yymore(); }
|
||||
|
||||
<REAL_SCALE>{S} {
|
||||
size_t token_len = strlen(yytext);
|
||||
char*tmp = new char[token_len + 5];
|
||||
int scale = 0;
|
||||
strcpy(tmp, yytext);
|
||||
switch (tmp[token_len-1]) {
|
||||
case 'a': scale = -18; break; /* atto- */
|
||||
case 'f': scale = -15; break; /* femto- */
|
||||
case 'p': scale = -12; break; /* pico- */
|
||||
case 'n': scale = -9; break; /* nano- */
|
||||
case 'u': scale = -6; break; /* micro- */
|
||||
case 'm': scale = -3; break; /* milli- */
|
||||
case 'k': scale = 3; break; /* kilo- */
|
||||
case 'K': scale = 3; break; /* kilo- */
|
||||
case 'M': scale = 6; break; /* mega- */
|
||||
case 'G': scale = 9; break; /* giga- */
|
||||
case 'T': scale = 12; break; /* tera- */
|
||||
default: assert(0); break;
|
||||
}
|
||||
snprintf(tmp+token_len-1, 5, "e%d", scale);
|
||||
yylval.realtime = new verireal(tmp);
|
||||
delete[]tmp;
|
||||
|
||||
BEGIN(0);
|
||||
return REALTIME; }
|
||||
|
||||
[0-9][0-9_]*\.[0-9][0-9_]*([Ee][+-]?[0-9][0-9_]*)? {
|
||||
yylval.realtime = new verireal(yytext);
|
||||
return REALTIME; }
|
||||
@@ -321,6 +356,57 @@ W [ \t\b\f\r]+
|
||||
^{W}?`unconnected_drive{W}?.* { }
|
||||
^{W}?`uselib{W}?.* { }
|
||||
|
||||
^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); }
|
||||
|
||||
<PPBEGIN_KEYWORDS>\"[a-zA-Z0-9 -]*\".* {
|
||||
keyword_mask_stack.push_front(lexor_keyword_mask);
|
||||
|
||||
char*word = yytext+1;
|
||||
char*tail = strchr(word, '"');
|
||||
tail[0] = 0;
|
||||
if (strcmp(word,"1364-1995") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995;
|
||||
} else if (strcmp(word,"1364-2001") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
||||
|GN_KEYWORDS_1364_2001
|
||||
|GN_KEYWORDS_1364_2001_CONFIG;
|
||||
} else if (strcmp(word,"1364-2001-noconfig") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
||||
|GN_KEYWORDS_1364_2001;
|
||||
} else if (strcmp(word,"1364-2005") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
||||
|GN_KEYWORDS_1364_2001
|
||||
|GN_KEYWORDS_1364_2001_CONFIG
|
||||
|GN_KEYWORDS_1364_2005;
|
||||
} else if (strcmp(word,"VAMS-2.3") == 0) {
|
||||
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
||||
|GN_KEYWORDS_1364_2001
|
||||
|GN_KEYWORDS_1364_2001_CONFIG
|
||||
|GN_KEYWORDS_1364_2005
|
||||
|GN_KEYWORDS_VAMS_2_3;
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d: Ignoring unknown keywords string: %s\n",
|
||||
yylloc.text, yylloc.first_line, word);
|
||||
}
|
||||
BEGIN(0);
|
||||
}
|
||||
|
||||
<PPBEGIN_KEYWORDS>.* {
|
||||
fprintf(stderr, "%s:%d: Malformed keywords specification: %s\n",
|
||||
yylloc.text, yylloc.first_line, yytext);
|
||||
BEGIN(0);
|
||||
}
|
||||
|
||||
^{W}?`end_keywords{W}?.* {
|
||||
if (!keyword_mask_stack.empty()) {
|
||||
lexor_keyword_mask = keyword_mask_stack.front();
|
||||
keyword_mask_stack.pop_front();
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d: Mismatched end_keywords directive\n",
|
||||
yylloc.text, yylloc.first_line);
|
||||
}
|
||||
}
|
||||
|
||||
/* Notice and handle the default_nettype directive. The lexor
|
||||
detects the default_nettype keyword, and the second part of the
|
||||
rule collects the rest of the line and processes it. We only need
|
||||
|
||||
+140
-111
@@ -6,127 +6,156 @@
|
||||
#include "parse.h"
|
||||
#include <string.h>
|
||||
#include "lexor_keyword.h"
|
||||
#include "compiler.h"
|
||||
|
||||
%}
|
||||
struct lexor_keyword { const char*name; int tokenType; };
|
||||
struct lexor_keyword { const char*name; int mask; int tokenType; };
|
||||
%%
|
||||
always, K_always
|
||||
and, K_and
|
||||
assign, K_assign
|
||||
begin, K_begin
|
||||
bool, K_bool
|
||||
buf, K_buf
|
||||
bufif0, K_bufif0
|
||||
bufif1, K_bufif1
|
||||
case, K_case
|
||||
casex, K_casex
|
||||
casez, K_casez
|
||||
cmos, K_cmos
|
||||
deassign, K_deassign
|
||||
default, K_default
|
||||
defparam, K_defparam
|
||||
disable, K_disable
|
||||
edge, K_edge
|
||||
else, K_else
|
||||
end, K_end
|
||||
endcase, K_endcase
|
||||
endfunction, K_endfunction
|
||||
endgenerate, K_endgenerate
|
||||
endmodule, K_endmodule
|
||||
endprimitive, K_endprimitive
|
||||
endspecify, K_endspecify
|
||||
endtable, K_endtable
|
||||
endtask, K_endtask
|
||||
event, K_event
|
||||
for, K_for
|
||||
force, K_force
|
||||
forever, K_forever
|
||||
fork, K_fork
|
||||
function, K_function
|
||||
generate, K_generate
|
||||
genvar, K_genvar
|
||||
highz0, K_highz0
|
||||
highz1, K_highz1
|
||||
if, K_if
|
||||
ifnone, K_ifnone
|
||||
initial, K_initial
|
||||
inout, K_inout
|
||||
input, K_input
|
||||
integer, K_integer
|
||||
join, K_join
|
||||
large, K_large
|
||||
localparam, K_localparam
|
||||
logic, K_logic
|
||||
macromodule, K_macromodule
|
||||
medium, K_medium
|
||||
module, K_module
|
||||
nand, K_nand
|
||||
negedge, K_negedge
|
||||
nmos, K_nmos
|
||||
nor, K_nor
|
||||
not, K_not
|
||||
notif0, K_notif0
|
||||
notif1, K_notif1
|
||||
or, K_or
|
||||
output, K_output
|
||||
parameter, K_parameter
|
||||
pmos, K_pmos
|
||||
posedge, K_posedge
|
||||
primitive, K_primitive
|
||||
pull0, K_pull0
|
||||
pull1, K_pull1
|
||||
pulldown, K_pulldown
|
||||
pullup, K_pullup
|
||||
rcmos, K_rcmos
|
||||
real, K_real
|
||||
realtime, K_realtime
|
||||
reg, K_reg
|
||||
release, K_release
|
||||
repeat, K_repeat
|
||||
rnmos, K_rnmos
|
||||
rpmos, K_rpmos
|
||||
rtran, K_rtran
|
||||
rtranif0, K_rtranif0
|
||||
rtranif1, K_rtranif1
|
||||
scalared, K_scalared
|
||||
signed, K_signed
|
||||
small, K_small
|
||||
specify, K_specify
|
||||
specparam, K_specparam
|
||||
strong0, K_strong0
|
||||
strong1, K_strong1
|
||||
supply0, K_supply0
|
||||
supply1, K_supply1
|
||||
table, K_table
|
||||
task, K_task
|
||||
time, K_time
|
||||
tran, K_tran
|
||||
tranif0, K_tranif0
|
||||
tranif1, K_tranif1
|
||||
tri, K_tri
|
||||
tri0, K_tri0
|
||||
tri1, K_tri1
|
||||
triand, K_triand
|
||||
trior, K_trior
|
||||
trireg, K_trireg
|
||||
vectored, K_vectored
|
||||
wait, K_wait
|
||||
wand, K_wand
|
||||
weak0, K_weak0
|
||||
weak1, K_weak1
|
||||
while, K_while
|
||||
wire, K_wire
|
||||
wone, K_wone
|
||||
wor, K_wor
|
||||
xnor, K_xnor
|
||||
xor, K_xor
|
||||
abs, GN_KEYWORDS_VAMS_2_3, K_abs
|
||||
acos, GN_KEYWORDS_VAMS_2_3, K_acos
|
||||
acosh, GN_KEYWORDS_VAMS_2_3, K_acosh
|
||||
always, GN_KEYWORDS_1364_1995, K_always
|
||||
and, GN_KEYWORDS_1364_1995, K_and
|
||||
asin, GN_KEYWORDS_VAMS_2_3, K_asin
|
||||
asinh, GN_KEYWORDS_VAMS_2_3, K_asinh
|
||||
assign, GN_KEYWORDS_1364_1995, K_assign
|
||||
atan, GN_KEYWORDS_VAMS_2_3, K_atan
|
||||
atan2, GN_KEYWORDS_VAMS_2_3, K_atan2
|
||||
atanh, GN_KEYWORDS_VAMS_2_3, K_atanh
|
||||
begin, GN_KEYWORDS_1364_1995, K_begin
|
||||
bool, GN_KEYWORDS_ICARUS, K_bool
|
||||
buf, GN_KEYWORDS_1364_1995, K_buf
|
||||
bufif0, GN_KEYWORDS_1364_1995, K_bufif0
|
||||
bufif1, GN_KEYWORDS_1364_1995, K_bufif1
|
||||
case, GN_KEYWORDS_1364_1995, K_case
|
||||
casex, GN_KEYWORDS_1364_1995, K_casex
|
||||
casez, GN_KEYWORDS_1364_1995, K_casez
|
||||
ceil, GN_KEYWORDS_VAMS_2_3, K_ceil
|
||||
cmos, GN_KEYWORDS_1364_1995, K_cmos
|
||||
cos, GN_KEYWORDS_VAMS_2_3, K_cos
|
||||
cosh, GN_KEYWORDS_VAMS_2_3, K_cosh
|
||||
deassign, GN_KEYWORDS_1364_1995, K_deassign
|
||||
default, GN_KEYWORDS_1364_1995, K_default
|
||||
defparam, GN_KEYWORDS_1364_1995, K_defparam
|
||||
disable, GN_KEYWORDS_1364_1995, K_disable
|
||||
edge, GN_KEYWORDS_1364_1995, K_edge
|
||||
else, GN_KEYWORDS_1364_1995, K_else
|
||||
end, GN_KEYWORDS_1364_1995, K_end
|
||||
endcase, GN_KEYWORDS_1364_1995, K_endcase
|
||||
endfunction, GN_KEYWORDS_1364_1995, K_endfunction
|
||||
endgenerate, GN_KEYWORDS_1364_1995, K_endgenerate
|
||||
endmodule, GN_KEYWORDS_1364_1995, K_endmodule
|
||||
endprimitive, GN_KEYWORDS_1364_1995, K_endprimitive
|
||||
endspecify, GN_KEYWORDS_1364_1995, K_endspecify
|
||||
endtable, GN_KEYWORDS_1364_1995, K_endtable
|
||||
endtask, GN_KEYWORDS_1364_1995, K_endtask
|
||||
event, GN_KEYWORDS_1364_1995, K_event
|
||||
exp, GN_KEYWORDS_VAMS_2_3, K_exp
|
||||
floor, GN_KEYWORDS_VAMS_2_3, K_floor
|
||||
for, GN_KEYWORDS_1364_1995, K_for
|
||||
force, GN_KEYWORDS_1364_1995, K_force
|
||||
forever, GN_KEYWORDS_1364_1995, K_forever
|
||||
fork, GN_KEYWORDS_1364_1995, K_fork
|
||||
function, GN_KEYWORDS_1364_1995, K_function
|
||||
generate, GN_KEYWORDS_1364_2001, K_generate
|
||||
genvar, GN_KEYWORDS_1364_2001, K_genvar
|
||||
highz0, GN_KEYWORDS_1364_1995, K_highz0
|
||||
highz1, GN_KEYWORDS_1364_1995, K_highz1
|
||||
hypot, GN_KEYWORDS_VAMS_2_3, K_hypot
|
||||
if, GN_KEYWORDS_1364_1995, K_if
|
||||
ifnone, GN_KEYWORDS_1364_1995, K_ifnone
|
||||
initial, GN_KEYWORDS_1364_1995, K_initial
|
||||
inout, GN_KEYWORDS_1364_1995, K_inout
|
||||
input, GN_KEYWORDS_1364_1995, K_input
|
||||
integer, GN_KEYWORDS_1364_1995, K_integer
|
||||
join, GN_KEYWORDS_1364_1995, K_join
|
||||
large, GN_KEYWORDS_1364_1995, K_large
|
||||
ln, GN_KEYWORDS_VAMS_2_3, K_ln
|
||||
localparam, GN_KEYWORDS_1364_2001, K_localparam
|
||||
log, GN_KEYWORDS_VAMS_2_3, K_log
|
||||
logic, GN_KEYWORDS_ICARUS, K_logic
|
||||
macromodule, GN_KEYWORDS_1364_1995, K_macromodule
|
||||
max, GN_KEYWORDS_VAMS_2_3, K_max
|
||||
medium, GN_KEYWORDS_1364_1995, K_medium
|
||||
min, GN_KEYWORDS_VAMS_2_3, K_min
|
||||
module, GN_KEYWORDS_1364_1995, K_module
|
||||
nand, GN_KEYWORDS_1364_1995, K_nand
|
||||
negedge, GN_KEYWORDS_1364_1995, K_negedge
|
||||
nmos, GN_KEYWORDS_1364_1995, K_nmos
|
||||
nor, GN_KEYWORDS_1364_1995, K_nor
|
||||
not, GN_KEYWORDS_1364_1995, K_not
|
||||
notif0, GN_KEYWORDS_1364_1995, K_notif0
|
||||
notif1, GN_KEYWORDS_1364_1995, K_notif1
|
||||
or, GN_KEYWORDS_1364_1995, K_or
|
||||
output, GN_KEYWORDS_1364_1995, K_output
|
||||
parameter, GN_KEYWORDS_1364_1995, K_parameter
|
||||
pmos, GN_KEYWORDS_1364_1995, K_pmos
|
||||
posedge, GN_KEYWORDS_1364_1995, K_posedge
|
||||
pow, GN_KEYWORDS_VAMS_2_3, K_pow
|
||||
primitive, GN_KEYWORDS_1364_1995, K_primitive
|
||||
pull0, GN_KEYWORDS_1364_1995, K_pull0
|
||||
pull1, GN_KEYWORDS_1364_1995, K_pull1
|
||||
pulldown, GN_KEYWORDS_1364_1995, K_pulldown
|
||||
pullup, GN_KEYWORDS_1364_1995, K_pullup
|
||||
rcmos, GN_KEYWORDS_1364_1995, K_rcmos
|
||||
real, GN_KEYWORDS_1364_1995, K_real
|
||||
realtime, GN_KEYWORDS_1364_1995, K_realtime
|
||||
reg, GN_KEYWORDS_1364_1995, K_reg
|
||||
release, GN_KEYWORDS_1364_1995, K_release
|
||||
repeat, GN_KEYWORDS_1364_1995, K_repeat
|
||||
rnmos, GN_KEYWORDS_1364_1995, K_rnmos
|
||||
rpmos, GN_KEYWORDS_1364_1995, K_rpmos
|
||||
rtran, GN_KEYWORDS_1364_1995, K_rtran
|
||||
rtranif0, GN_KEYWORDS_1364_1995, K_rtranif0
|
||||
rtranif1, GN_KEYWORDS_1364_1995, K_rtranif1
|
||||
scalared, GN_KEYWORDS_1364_1995, K_scalared
|
||||
signed, GN_KEYWORDS_1364_2001, K_signed
|
||||
sin, GN_KEYWORDS_VAMS_2_3, K_sin
|
||||
sinh, GN_KEYWORDS_VAMS_2_3, K_sinh
|
||||
small, GN_KEYWORDS_1364_1995, K_small
|
||||
specify, GN_KEYWORDS_1364_1995, K_specify
|
||||
specparam, GN_KEYWORDS_1364_1995, K_specparam
|
||||
sqrt, GN_KEYWORDS_VAMS_2_3, K_sqrt
|
||||
strong0, GN_KEYWORDS_1364_1995, K_strong0
|
||||
strong1, GN_KEYWORDS_1364_1995, K_strong1
|
||||
supply0, GN_KEYWORDS_1364_1995, K_supply0
|
||||
supply1, GN_KEYWORDS_1364_1995, K_supply1
|
||||
table, GN_KEYWORDS_1364_1995, K_table
|
||||
tan, GN_KEYWORDS_VAMS_2_3, K_tan
|
||||
tanh, GN_KEYWORDS_VAMS_2_3, K_tanh
|
||||
task, GN_KEYWORDS_1364_1995, K_task
|
||||
time, GN_KEYWORDS_1364_1995, K_time
|
||||
tran, GN_KEYWORDS_1364_1995, K_tran
|
||||
tranif0, GN_KEYWORDS_1364_1995, K_tranif0
|
||||
tranif1, GN_KEYWORDS_1364_1995, K_tranif1
|
||||
tri, GN_KEYWORDS_1364_1995, K_tri
|
||||
tri0, GN_KEYWORDS_1364_1995, K_tri0
|
||||
tri1, GN_KEYWORDS_1364_1995, K_tri1
|
||||
triand, GN_KEYWORDS_1364_1995, K_triand
|
||||
trior, GN_KEYWORDS_1364_1995, K_trior
|
||||
trireg, GN_KEYWORDS_1364_1995, K_trireg
|
||||
vectored, GN_KEYWORDS_1364_1995, K_vectored
|
||||
wait, GN_KEYWORDS_1364_1995, K_wait
|
||||
wand, GN_KEYWORDS_1364_1995, K_wand
|
||||
weak0, GN_KEYWORDS_1364_1995, K_weak0
|
||||
weak1, GN_KEYWORDS_1364_1995, K_weak1
|
||||
while, GN_KEYWORDS_1364_1995, K_while
|
||||
wire, GN_KEYWORDS_1364_1995, K_wire
|
||||
wone, GN_KEYWORDS_1364_1995, K_wone
|
||||
wor, GN_KEYWORDS_1364_1995, K_wor
|
||||
xnor, GN_KEYWORDS_1364_1995, K_xnor
|
||||
xor, GN_KEYWORDS_1364_1995, K_xor
|
||||
%%
|
||||
|
||||
int lexor_keyword_mask = 0;
|
||||
|
||||
int lexor_keyword_code(const char*str, unsigned nstr)
|
||||
{
|
||||
const struct lexor_keyword*rc = check_identifier(str, nstr);
|
||||
if (rc == 0)
|
||||
return IDENTIFIER;
|
||||
else if ((rc->mask & lexor_keyword_mask) == 0)
|
||||
return IDENTIFIER;
|
||||
else
|
||||
return rc->tokenType;
|
||||
}
|
||||
|
||||
@@ -85,9 +85,11 @@ const char*target = "null";
|
||||
* is a major mode, and the gn_* flags control specific sub-features.
|
||||
*/
|
||||
generation_t generation_flag = GN_DEFAULT;
|
||||
bool gn_icarus_misc_flag = true;
|
||||
bool gn_cadence_types_flag = true;
|
||||
bool gn_specify_blocks_flag = true;
|
||||
bool gn_io_range_error_flag = true;
|
||||
bool gn_verilog_ams_flag = false;
|
||||
|
||||
map<string,const char*> flags;
|
||||
char*vpi_module_list = 0;
|
||||
@@ -197,14 +199,30 @@ const char *net_func_to_name(const net_func func)
|
||||
|
||||
static void process_generation_flag(const char*gen)
|
||||
{
|
||||
if (strcmp(gen,"1") == 0) {
|
||||
if (strcmp(gen,"1") == 0) { // FIXME: Deprecated for 1995
|
||||
generation_flag = GN_VER1995;
|
||||
|
||||
} else if (strcmp(gen,"2") == 0) {
|
||||
} else if (strcmp(gen,"2") == 0) { // FIXME: Deprecated for 2001
|
||||
generation_flag = GN_VER2001;
|
||||
|
||||
} else if (strcmp(gen,"2x") == 0) {
|
||||
generation_flag = GN_VER2001X;
|
||||
} else if (strcmp(gen,"2x") == 0) { // FIXME: Deprecated for 2001
|
||||
generation_flag = GN_VER2001;
|
||||
gn_icarus_misc_flag = true;
|
||||
|
||||
} else if (strcmp(gen,"1995") == 0) {
|
||||
generation_flag = GN_VER1995;
|
||||
|
||||
} else if (strcmp(gen,"2001") == 0) {
|
||||
generation_flag = GN_VER2001;
|
||||
|
||||
} else if (strcmp(gen,"2005") == 0) {
|
||||
generation_flag = GN_VER2005;
|
||||
|
||||
} else if (strcmp(gen,"icarus-misc") == 0) {
|
||||
gn_icarus_misc_flag = true;
|
||||
|
||||
} else if (strcmp(gen,"no-icarus-misc") == 0) {
|
||||
gn_icarus_misc_flag = false;
|
||||
|
||||
} else if (strcmp(gen,"xtypes") == 0) {
|
||||
gn_cadence_types_flag = true;
|
||||
@@ -218,6 +236,12 @@ static void process_generation_flag(const char*gen)
|
||||
} else if (strcmp(gen,"no-specify") == 0) {
|
||||
gn_specify_blocks_flag = false;
|
||||
|
||||
} else if (strcmp(gen,"verilog-ams") == 0) {
|
||||
gn_verilog_ams_flag = true;
|
||||
|
||||
} else if (strcmp(gen,"no-verilog-ams") == 0) {
|
||||
gn_verilog_ams_flag = false;
|
||||
|
||||
} else if (strcmp(gen,"io-range-error") == 0) {
|
||||
gn_io_range_error_flag = true;
|
||||
|
||||
@@ -592,6 +616,29 @@ int main(int argc, char*argv[])
|
||||
}
|
||||
}
|
||||
|
||||
lexor_keyword_mask = 0;
|
||||
switch (generation_flag) {
|
||||
case GN_VER1995:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
|
||||
break;
|
||||
case GN_VER2001:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG;
|
||||
break;
|
||||
case GN_VER2005:
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG;
|
||||
lexor_keyword_mask |= GN_KEYWORDS_1364_2005;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gn_cadence_types_flag)
|
||||
lexor_keyword_mask |= GN_KEYWORDS_ICARUS;
|
||||
|
||||
if (gn_verilog_ams_flag)
|
||||
lexor_keyword_mask |= GN_KEYWORDS_VAMS_2_3;
|
||||
|
||||
if (verbose_flag) {
|
||||
if (times_flag)
|
||||
@@ -605,11 +652,14 @@ int main(int argc, char*argv[])
|
||||
case GN_VER2001:
|
||||
cout << "IEEE1364-2001";
|
||||
break;
|
||||
case GN_VER2001X:
|
||||
cout << "IEEE1364-2001+Extensions";
|
||||
case GN_VER2005:
|
||||
cout << "IEEE1364-2005";
|
||||
break;
|
||||
}
|
||||
|
||||
if (gn_verilog_ams_flag)
|
||||
cout << ",verilog-ams";
|
||||
|
||||
if (gn_specify_blocks_flag)
|
||||
cout << ",specify";
|
||||
else
|
||||
@@ -620,6 +670,11 @@ int main(int argc, char*argv[])
|
||||
else
|
||||
cout << ",no-xtypes";
|
||||
|
||||
if (gn_icarus_misc_flag)
|
||||
cout << ",icarus-misc";
|
||||
else
|
||||
cout << ",no-icarus-misc";
|
||||
|
||||
cout << endl << "PARSING INPUT" << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ critical, but these are the versions I use.
|
||||
msys-1.0 <http://www.mingw/org>
|
||||
msysDTK-1.0 <http://www.mingw.org>
|
||||
Mingw32-5.x <http://www.mingw.org>
|
||||
... including the sub-packages binutils, gcc-core and gcc-g++
|
||||
if you are given the option.
|
||||
readline-4.2-20010727.zip <http://mingwrep.sourceforge.net>
|
||||
bzip2-1.0.3 <http://gnuwin32.sourceforge.net>
|
||||
zlib-1.2.3 <http://gnuwin32.sourceforge.net>
|
||||
|
||||
+22
-2
@@ -81,6 +81,7 @@ NetEBAdd::NetEBAdd(char op, NetExpr*l, NetExpr*r, bool lossless_flag)
|
||||
}
|
||||
|
||||
unsigned pad_width = lossless_flag? 1 : 0;
|
||||
cast_signed(l->has_sign() && r->has_sign());
|
||||
|
||||
/* Now that we have the operand sizes the way we like, or as
|
||||
good as we are going to get them, set the size of myself. */
|
||||
@@ -91,8 +92,6 @@ NetEBAdd::NetEBAdd(char op, NetExpr*l, NetExpr*r, bool lossless_flag)
|
||||
} else {
|
||||
expr_width(l->expr_width() + pad_width);
|
||||
}
|
||||
|
||||
cast_signed(l->has_sign() && r->has_sign());
|
||||
}
|
||||
|
||||
NetEBAdd::~NetEBAdd()
|
||||
@@ -219,6 +218,27 @@ ivl_variable_type_t NetEBDiv::expr_type() const
|
||||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBMinMax::NetEBMinMax(char op, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op, l, r)
|
||||
{
|
||||
expr_width( max(l->expr_width(), r->expr_width()) );
|
||||
cast_signed(l->has_sign() || r->has_sign());
|
||||
}
|
||||
|
||||
NetEBMinMax::~NetEBMinMax()
|
||||
{
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEBMinMax::expr_type() const
|
||||
{
|
||||
if (left_->expr_type() == IVL_VT_REAL)
|
||||
return IVL_VT_REAL;
|
||||
if (right_->expr_type() == IVL_VT_REAL)
|
||||
return IVL_VT_REAL;
|
||||
|
||||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBMult::NetEBMult(char op, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op, l, r)
|
||||
{
|
||||
|
||||
+45
-14
@@ -78,8 +78,34 @@ NetScope::~NetScope()
|
||||
/* name_ and module_name_ are perm-allocated. */
|
||||
}
|
||||
|
||||
void NetScope::set_line(const LineInfo*info)
|
||||
{
|
||||
file_ = info->get_file();
|
||||
def_file_ = file_;
|
||||
lineno_ = info->get_lineno();
|
||||
def_lineno_ = lineno_;
|
||||
}
|
||||
|
||||
void NetScope::set_line(perm_string file, unsigned lineno)
|
||||
{
|
||||
file_ = file;
|
||||
def_file_ = file;
|
||||
lineno_ = lineno;
|
||||
def_lineno_ = lineno;
|
||||
}
|
||||
|
||||
void NetScope::set_line(perm_string file, perm_string def_file,
|
||||
unsigned lineno, unsigned def_lineno)
|
||||
{
|
||||
file_ = file;
|
||||
def_file_ = def_file;
|
||||
lineno_ = lineno;
|
||||
def_lineno_ = def_lineno;
|
||||
}
|
||||
|
||||
NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag)
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
perm_string file, unsigned lineno)
|
||||
{
|
||||
param_expr_t&ref = parameters[key];
|
||||
NetExpr* res = ref.expr;
|
||||
@@ -87,6 +113,8 @@ NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
|
||||
ref.msb = msb;
|
||||
ref.lsb = lsb;
|
||||
ref.signed_flag = signed_flag;
|
||||
ref.file = file;
|
||||
ref.lineno = lineno;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -109,29 +137,30 @@ bool NetScope::auto_name(const char*prefix, char pad, const char* suffix)
|
||||
}
|
||||
|
||||
/*
|
||||
* Return false if this creates a new parameter.
|
||||
* Return false if the parameter does not already exist.
|
||||
* A parameter is not automatically created.
|
||||
*/
|
||||
bool NetScope::replace_parameter(perm_string key, NetExpr*expr)
|
||||
{
|
||||
bool flag = true;
|
||||
param_expr_t&ref = parameters[key];
|
||||
bool flag = false;
|
||||
|
||||
NetExpr* res = ref.expr;
|
||||
if (parameters.find(key) != parameters.end()) {
|
||||
param_expr_t&ref = parameters[key];
|
||||
|
||||
if (res) {
|
||||
delete res;
|
||||
} else {
|
||||
flag = false;
|
||||
ref.msb = 0;
|
||||
ref.lsb = 0;
|
||||
ref.signed_flag = false;
|
||||
delete ref.expr;
|
||||
ref.expr = expr;
|
||||
flag = true;
|
||||
}
|
||||
|
||||
ref.expr = expr;
|
||||
return flag;
|
||||
}
|
||||
|
||||
NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr)
|
||||
/*
|
||||
* This is not really complete (msb, lsb, sign). It is currently only
|
||||
* used to add a genver to the local parameter list.
|
||||
*/
|
||||
NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
|
||||
perm_string file, unsigned lineno)
|
||||
{
|
||||
param_expr_t&ref = localparams[key];
|
||||
NetExpr* res = ref.expr;
|
||||
@@ -139,6 +168,8 @@ NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr)
|
||||
ref.msb = 0;
|
||||
ref.lsb = 0;
|
||||
ref.signed_flag = false;
|
||||
ref.file = file;
|
||||
ref.lineno = lineno;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
+20
-1
@@ -648,7 +648,7 @@ bool NetNet::sb_is_valid(long sb) const
|
||||
return (sb <= lsb_) && (sb >= msb_);
|
||||
}
|
||||
|
||||
unsigned NetNet::sb_to_idx(long sb) const
|
||||
long NetNet::sb_to_idx(long sb) const
|
||||
{
|
||||
if (msb_ >= lsb_)
|
||||
return sb - lsb_;
|
||||
@@ -1046,6 +1046,24 @@ const verinum& NetFF::sset_value() const
|
||||
}
|
||||
|
||||
|
||||
NetAbs::NetAbs(NetScope*s, perm_string n, unsigned w)
|
||||
: NetNode(s, n, 2), width_(w)
|
||||
{
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(0).set_name(perm_string::literal("Result"), 0);
|
||||
pin(1).set_dir(Link::INPUT);
|
||||
pin(1).set_name(perm_string::literal("DataA"), 0);
|
||||
}
|
||||
|
||||
NetAbs::~NetAbs()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned NetAbs::width() const
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NetAddSub class represents an LPM_ADD_SUB device. The pinout is
|
||||
* assigned like so:
|
||||
@@ -2294,6 +2312,7 @@ NetEUnary::NetEUnary(char op, NetExpr*ex)
|
||||
switch (op_) {
|
||||
case '-':
|
||||
case '+':
|
||||
case 'm': // abs()
|
||||
cast_signed(ex->has_sign());
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -510,7 +510,7 @@ class NetNet : public NetObj {
|
||||
/* This method converts a signed index (the type that might be
|
||||
found in the Verilog source) to a pin number. It accounts
|
||||
for variation in the definition of the reg/wire/whatever. */
|
||||
unsigned sb_to_idx(long sb) const;
|
||||
long sb_to_idx(long sb) const;
|
||||
|
||||
/* This method checks that the signed index is valid for this
|
||||
signal. If it is, the above sb_to_idx can be used to get
|
||||
@@ -578,6 +578,27 @@ class NetNet : public NetObj {
|
||||
vector<class NetDelaySrc*> delay_paths_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class implements the LPM_ABS component. The node has a single
|
||||
* input, a signe expression, that it converts to the absolute
|
||||
* value. The gate is simple: pin(0) is the output and pin(1) is the input.
|
||||
*/
|
||||
class NetAbs : public NetNode {
|
||||
|
||||
public:
|
||||
NetAbs(NetScope*s, perm_string n, unsigned width);
|
||||
~NetAbs();
|
||||
|
||||
unsigned width() const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual bool emit_node(struct target_t*) const;
|
||||
virtual void functor_node(Design*des, functor_t*fun);
|
||||
|
||||
private:
|
||||
unsigned width_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class implements the LPM_ADD_SUB component as described in the
|
||||
* EDIF LPM Version 2 1 0 standard. It is used as a structural
|
||||
@@ -2664,6 +2685,8 @@ class NetProcTop : public LineInfo, public Attrib {
|
||||
* r -- Right shift (>>)
|
||||
* R -- signed right shift (>>>)
|
||||
* X -- Bitwise exclusive NOR (~^)
|
||||
* m -- min(a,b)
|
||||
* M -- max(a,b)
|
||||
*/
|
||||
class NetEBinary : public NetExpr {
|
||||
|
||||
@@ -2831,6 +2854,24 @@ class NetEBLogic : public NetEBinary {
|
||||
private:
|
||||
};
|
||||
|
||||
/*
|
||||
* Support the binary min(l,r) and max(l,r) operators. The opcodes
|
||||
* supported are:
|
||||
*
|
||||
* m -- min
|
||||
* M -- max
|
||||
*/
|
||||
class NetEBMinMax : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBMinMax(char op, NetExpr*l, NetExpr*r);
|
||||
~NetEBMinMax();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Support the binary multiplication (*) operator.
|
||||
@@ -3143,6 +3184,7 @@ class NetETernary : public NetExpr {
|
||||
* A -- Reduction NAND (~&)
|
||||
* N -- Reduction NOR (~|)
|
||||
* X -- Reduction NXOR (~^ or ^~)
|
||||
* m -- abs(x) (i.e. "magnitude")
|
||||
*/
|
||||
class NetEUnary : public NetExpr {
|
||||
|
||||
@@ -3273,8 +3315,10 @@ class NetScope : public Attrib {
|
||||
previous expression, if there was one. */
|
||||
|
||||
NetExpr* set_parameter(perm_string name, NetExpr*val,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag);
|
||||
NetExpr* set_localparam(perm_string name, NetExpr*val);
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
perm_string file, unsigned lineno);
|
||||
NetExpr* set_localparam(perm_string name, NetExpr*val,
|
||||
perm_string file, unsigned lineno);
|
||||
|
||||
const NetExpr*get_parameter(const char* name,
|
||||
const NetExpr*&msb,
|
||||
@@ -3319,6 +3363,15 @@ class NetScope : public Attrib {
|
||||
NetTaskDef* task_def();
|
||||
NetFuncDef* func_def();
|
||||
|
||||
void set_line(perm_string file, perm_string def_file,
|
||||
unsigned lineno, unsigned def_lineno);
|
||||
void set_line(perm_string file, unsigned lineno);
|
||||
void set_line(const LineInfo *info);
|
||||
perm_string get_file() const { return file_; };
|
||||
perm_string get_def_file() const { return def_file_; };
|
||||
unsigned get_lineno() const { return lineno_; };
|
||||
unsigned get_def_lineno() const { return def_lineno_; };
|
||||
|
||||
bool in_func();
|
||||
|
||||
const NetTaskDef* task_def() const;
|
||||
@@ -3380,6 +3433,8 @@ class NetScope : public Attrib {
|
||||
NetExpr*expr;
|
||||
NetExpr*msb;
|
||||
NetExpr*lsb;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
bool signed_flag;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
@@ -3409,6 +3464,11 @@ class NetScope : public Attrib {
|
||||
TYPE type_;
|
||||
hname_t name_;
|
||||
|
||||
perm_string file_;
|
||||
perm_string def_file_;
|
||||
unsigned lineno_;
|
||||
unsigned def_lineno_;
|
||||
|
||||
signed char time_unit_, time_prec_;
|
||||
NetNet::Type default_nettype_;
|
||||
|
||||
|
||||
@@ -113,6 +113,27 @@ static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
return copy;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a shorthand for making a PECallFunction that takes a single
|
||||
* arg. This is used by some of the code that detects built-ins.
|
||||
*/
|
||||
static PECallFunction*make_call_function(perm_string tn, PExpr*arg)
|
||||
{
|
||||
svector<PExpr*> parms(1);
|
||||
parms[0] = arg;
|
||||
PECallFunction*tmp = new PECallFunction(tn, parms);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||
{
|
||||
svector<PExpr*> parms(2);
|
||||
parms[0] = arg1;
|
||||
parms[1] = arg2;
|
||||
PECallFunction*tmp = new PECallFunction(tn, parms);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
@@ -182,22 +203,25 @@ static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
%token K_PO_POS K_PO_NEG K_POW
|
||||
%token K_PSTAR K_STARP
|
||||
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER
|
||||
%token K_abs K_acos K_acosh K_asin K_asinh K_atan K_atanh K_atan2
|
||||
%token K_always K_and K_assign K_begin K_bool K_buf K_bufif0 K_bufif1 K_case
|
||||
%token K_casex K_casez K_cmos K_deassign K_default K_defparam K_disable
|
||||
%token K_casex K_casez K_ceil K_cmos K_cos K_cosh
|
||||
%token K_deassign K_default K_defparam K_disable
|
||||
%token K_edge K_edge_descriptor
|
||||
%token K_else K_end K_endcase K_endfunction K_endgenerate K_endmodule
|
||||
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_for
|
||||
%token K_force K_forever K_fork K_function K_generate K_genvar
|
||||
%token K_highz0 K_highz1 K_if K_ifnone
|
||||
%token K_initial K_inout K_input K_integer K_join K_large K_localparam
|
||||
%token K_logic K_macromodule
|
||||
%token K_medium K_module K_nand K_negedge K_nmos K_nor K_not K_notif0
|
||||
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_primitive
|
||||
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_exp K_floor
|
||||
%token K_for K_force K_forever K_fork K_function K_generate K_genvar
|
||||
%token K_highz0 K_highz1 K_hypot K_if K_ifnone
|
||||
%token K_initial K_inout K_input K_integer K_join K_large K_ln K_localparam
|
||||
%token K_log K_logic K_macromodule K_max
|
||||
%token K_medium K_min K_module K_nand K_negedge K_nmos K_nor K_not K_notif0
|
||||
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_pow K_primitive
|
||||
%token K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_real K_realtime
|
||||
%token K_reg K_release K_repeat
|
||||
%token K_rnmos K_rpmos K_rtran K_rtranif0 K_rtranif1 K_scalared
|
||||
%token K_signed K_small K_specify
|
||||
%token K_specparam K_strong0 K_strong1 K_supply0 K_supply1 K_table K_task
|
||||
%token K_signed K_sin K_sinh K_small K_specify
|
||||
%token K_specparam K_sqrt K_strong0 K_strong1 K_supply0 K_supply1 K_table
|
||||
%token K_tan K_tanh K_task
|
||||
%token K_time K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand
|
||||
%token K_trior K_trireg K_vectored K_wait K_wand K_weak0 K_weak1
|
||||
%token K_while K_wire
|
||||
@@ -1066,19 +1090,191 @@ expr_primary
|
||||
function call. If a system identifier, then a system function
|
||||
call. */
|
||||
|
||||
| hierarchy_identifier '(' expression_list_proper ')'
|
||||
{ PECallFunction*tmp = new PECallFunction(*$1, *$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' expression_list_proper ')'
|
||||
{ perm_string tn = lex_strings.make($1);
|
||||
PECallFunction*tmp = new PECallFunction(tn, *$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete[]$1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| hierarchy_identifier '(' expression_list_proper ')'
|
||||
{ PECallFunction*tmp = new PECallFunction(*$1, *$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' expression_list_proper ')'
|
||||
{ perm_string tn = lex_strings.make($1);
|
||||
PECallFunction*tmp = new PECallFunction(tn, *$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete[]$1;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* Many of the VAMS built-in functions are available as builtin
|
||||
functions with $system_function equivilents. */
|
||||
|
||||
| K_acos '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$acos");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_acosh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$acosh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_asin '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$asin");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_asinh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$asinh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_atan '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$atan");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_atanh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$atanh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_atan2 '(' expression ',' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$atan2");
|
||||
PECallFunction*tmp = make_call_function(tn, $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_ceil '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$ceil");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_cos '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$cos");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_cosh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$cosh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_exp '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$exp");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_floor '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$floor");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_hypot '(' expression ',' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$hypot");
|
||||
PECallFunction*tmp = make_call_function(tn, $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_ln '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$ln");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_log '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$log10");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_pow '(' expression ',' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$pow");
|
||||
PECallFunction*tmp = make_call_function(tn, $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_sin '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$sin");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_sinh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$sinh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_sqrt '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$sqrt");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_tan '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$tan");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_tanh '(' expression ')'
|
||||
{ perm_string tn = perm_string::literal("$tanh");
|
||||
PECallFunction*tmp = make_call_function(tn, $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* These mathematical functions are conveniently expressed as unary
|
||||
and binary expressions. They behave much like unary/binary
|
||||
operators, even though they are parsed as functions. */
|
||||
|
||||
| K_abs '(' expression ')'
|
||||
{ PEUnary*tmp = new PEUnary('m', $3);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_max '(' expression ',' expression ')'
|
||||
{ PEBinary*tmp = new PEBinary('M', $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| K_min '(' expression ',' expression ')'
|
||||
{ PEBinary*tmp = new PEBinary('m', $3, $5);
|
||||
FILE_NAME(tmp,@1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* Parenthesized expressions are primaries. */
|
||||
|
||||
@@ -1891,7 +2087,7 @@ module_item
|
||||
| K_generate module_item_list_opt K_endgenerate
|
||||
|
||||
| K_genvar list_of_identifiers ';'
|
||||
{ pform_genvars($2); }
|
||||
{ pform_genvars(@1, $2); }
|
||||
|
||||
| K_for '(' IDENTIFIER '=' expression ';'
|
||||
expression ';'
|
||||
@@ -2113,7 +2309,8 @@ parameter_assign
|
||||
} else {
|
||||
pform_set_parameter(lex_strings.make($1),
|
||||
active_signed,
|
||||
active_range, tmp);
|
||||
active_range, tmp,
|
||||
@1.text, @1.first_line);
|
||||
}
|
||||
delete[]$1;
|
||||
}
|
||||
@@ -2135,7 +2332,8 @@ localparam_assign
|
||||
} else {
|
||||
pform_set_localparam(lex_strings.make($1),
|
||||
active_signed,
|
||||
active_range, tmp);
|
||||
active_range, tmp,
|
||||
@1.text, @1.first_line);
|
||||
}
|
||||
delete[]$1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -363,11 +363,13 @@ void pform_endmodule(const char*name)
|
||||
pform_cur_module = 0;
|
||||
}
|
||||
|
||||
void pform_genvars(list<perm_string>*names)
|
||||
void pform_genvars(const struct vlltype&li, list<perm_string>*names)
|
||||
{
|
||||
list<perm_string>::const_iterator cur;
|
||||
for (cur = names->begin(); cur != names->end() ; *cur++) {
|
||||
pform_cur_module->genvars.push_back( *cur );
|
||||
LineInfo*lni = new LineInfo();
|
||||
FILE_NAME(lni, li);
|
||||
pform_cur_module->genvars[*cur] = lni;
|
||||
}
|
||||
|
||||
delete names;
|
||||
@@ -1639,7 +1641,8 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
|
||||
}
|
||||
|
||||
void pform_set_parameter(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr)
|
||||
svector<PExpr*>*range, PExpr*expr,
|
||||
const char*file, unsigned lineno)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->parameters[name].expr = expr;
|
||||
@@ -1655,12 +1658,15 @@ void pform_set_parameter(perm_string name, bool signed_flag,
|
||||
pform_cur_module->parameters[name].lsb = 0;
|
||||
}
|
||||
pform_cur_module->parameters[name].signed_flag = signed_flag;
|
||||
pform_cur_module->parameters[name].file = filename_strings.make(file);
|
||||
pform_cur_module->parameters[name].lineno = lineno;
|
||||
|
||||
pform_cur_module->param_names.push_back(name);
|
||||
}
|
||||
|
||||
void pform_set_localparam(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr)
|
||||
svector<PExpr*>*range, PExpr*expr,
|
||||
const char*file, unsigned lineno)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->localparams[name].expr = expr;
|
||||
@@ -1676,6 +1682,8 @@ void pform_set_localparam(perm_string name, bool signed_flag,
|
||||
pform_cur_module->localparams[name].lsb = 0;
|
||||
}
|
||||
pform_cur_module->localparams[name].signed_flag = signed_flag;
|
||||
pform_cur_module->localparams[name].file = filename_strings.make(file);
|
||||
pform_cur_module->localparams[name].lineno = lineno;
|
||||
}
|
||||
|
||||
void pform_set_specparam(perm_string name, PExpr*expr)
|
||||
@@ -1925,4 +1933,3 @@ void pform_error_nested_modules()
|
||||
cerr << pform_cur_module->get_fileline() << ": error: original module "
|
||||
"(" << pform_cur_module->mod_name() << ") defined here." << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __pform_H
|
||||
#define __pform_H
|
||||
/*
|
||||
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -18,9 +18,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: pform.h,v 1.91 2007/05/24 04:07:12 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include "HName.h"
|
||||
@@ -175,13 +172,13 @@ extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt);
|
||||
|
||||
|
||||
extern verinum* pform_verinum_with_size(verinum*s, verinum*val,
|
||||
const char*file, unsigned loneno);
|
||||
const char*file, unsigned lineno);
|
||||
|
||||
/*
|
||||
* This function takes the list of names as new genvars to declare in
|
||||
* the current module scope.
|
||||
*/
|
||||
extern void pform_genvars(list<perm_string>*names);
|
||||
extern void pform_genvars(const struct vlltype&li, list<perm_string>*names);
|
||||
|
||||
extern void pform_start_generate_for(const struct vlltype&li,
|
||||
char*ident1,
|
||||
@@ -263,11 +260,13 @@ extern void pform_set_type_attrib(perm_string name, const string&key,
|
||||
extern void pform_set_parameter(perm_string name,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr);
|
||||
PExpr*expr,
|
||||
const char*file, unsigned lineno);
|
||||
extern void pform_set_localparam(perm_string name,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr);
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr,
|
||||
const char*file, unsigned lineno);
|
||||
extern void pform_set_defparam(const pform_name_t&name, PExpr*expr);
|
||||
|
||||
/*
|
||||
|
||||
+23
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998-2006 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -215,11 +215,30 @@ void PETernary::dump(ostream&out) const
|
||||
|
||||
void PEUnary::dump(ostream&out) const
|
||||
{
|
||||
out << op_ << "(" << *expr_ << ")";
|
||||
switch (op_) {
|
||||
case 'm':
|
||||
out << "abs";
|
||||
break;
|
||||
default:
|
||||
out << op_;
|
||||
break;
|
||||
}
|
||||
out << "(" << *expr_ << ")";
|
||||
}
|
||||
|
||||
void PEBinary::dump(ostream&out) const
|
||||
{
|
||||
/* Handle some special cases, where the operators are written
|
||||
in function notation. */
|
||||
if (op_ == 'm') {
|
||||
out << "min(" << *left_ << "," << *right_ << ")";
|
||||
return;
|
||||
}
|
||||
if (op_ == 'M') {
|
||||
out << "min(" << *left_ << "," << *right_ << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
out << "(" << *left_ << ")";
|
||||
switch (op_) {
|
||||
case 'a':
|
||||
@@ -976,10 +995,10 @@ void Module::dump(ostream&out) const
|
||||
out << "/* ERROR */;" << endl;
|
||||
}
|
||||
|
||||
typedef list<perm_string>::const_iterator genvar_iter_t;
|
||||
typedef map<perm_string,LineInfo*>::const_iterator genvar_iter_t;
|
||||
for (genvar_iter_t cur = genvars.begin()
|
||||
; cur != genvars.end() ; cur++) {
|
||||
out << " genvar " << (*cur) << ";" << endl;
|
||||
out << " genvar " << ((*cur).first) << ";" << endl;
|
||||
}
|
||||
|
||||
typedef list<PGenerate*>::const_iterator genscheme_iter_t;
|
||||
@@ -1104,4 +1123,3 @@ void PUdp::dump(ostream&out) const
|
||||
|
||||
out << "endprimitive" << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,17 +45,17 @@ if [ -e $destdir/$prefix ]; then
|
||||
fi
|
||||
|
||||
echo "Exporting $tag to $destdir/$prefix..."
|
||||
git-archive --prefix="$prefix/" $tag | ( cd "$destdir" ; tar xf - )
|
||||
git-archive --prefix="$prefix/" $tag | ( cd "$destdir" && tar xf - )
|
||||
|
||||
versionh="$destdir/verilog-$id/version.h"
|
||||
versionh="$destdir/$prefix/version.h"
|
||||
echo "Create $versionh ..."
|
||||
echo "#define VERSION_TAG \"$tag\"" > $versionh
|
||||
|
||||
echo "Running autoconf.sh..."
|
||||
( cd $destdir/$prefix ; sh autoconf.sh )
|
||||
( cd $destdir/$prefix && sh autoconf.sh )
|
||||
|
||||
echo "Making bundle $prefix.tar.gz..."
|
||||
tar czf $prefix.tar.gz -C "$destdir" $prefix
|
||||
tar czf $prefix.tar.gz --exclude=autom4te.cache -C "$destdir" $prefix
|
||||
|
||||
echo "Removing temporary $destdir/$prefix..."
|
||||
rm -rf "$destdir/$prefix"
|
||||
|
||||
+4
-2
@@ -413,8 +413,10 @@ bool NetETernary::set_width(unsigned w, bool last_chance)
|
||||
*/
|
||||
bool NetEUFunc::set_width(unsigned wid, bool)
|
||||
{
|
||||
expr_width(wid);
|
||||
return true;
|
||||
if (result_sig_->expr_width() == wid)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetEUnary::set_width(unsigned w, bool)
|
||||
|
||||
@@ -864,6 +864,10 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
|
||||
{
|
||||
assert(net);
|
||||
switch (net->type) {
|
||||
case IVL_LPM_ABS:
|
||||
assert(idx == 0);
|
||||
return net->u_.arith.a;
|
||||
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
@@ -1002,6 +1006,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
|
||||
assert(net);
|
||||
|
||||
switch (net->type) {
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
@@ -1118,6 +1123,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
|
||||
case IVL_LPM_FF:
|
||||
case IVL_LPM_MUX:
|
||||
return 0;
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
@@ -1344,6 +1350,18 @@ extern "C" ivl_expr_t ivl_parameter_expr(ivl_parameter_t net)
|
||||
return net->value;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_parameter_file(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_parameter_lineno(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
extern "C" ivl_scope_t ivl_parameter_scope(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1456,6 +1474,18 @@ extern "C" ivl_statement_t ivl_scope_def(ivl_scope_t net)
|
||||
return net->def;
|
||||
}
|
||||
|
||||
extern "C" const char*ivl_scope_def_file(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->def_file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_def_lineno(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->def_lineno;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_events(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1469,6 +1499,18 @@ extern "C" ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx)
|
||||
return net->event_[idx];
|
||||
}
|
||||
|
||||
extern "C" const char*ivl_scope_file(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_lineno(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_logs(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1715,6 +1757,18 @@ extern "C" int ivl_signal_signed(ivl_signal_t net)
|
||||
return net->signed_;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_signal_file(ivl_signal_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->file.str();
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_signal_lineno(ivl_signal_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
extern "C" int ivl_signal_integer(ivl_signal_t net)
|
||||
{
|
||||
return net->isint_;
|
||||
|
||||
@@ -470,6 +470,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
|
||||
ivl_parameter_t cur_par = scope->param_ + idx;
|
||||
cur_par->basename = (*cur_pit).first;
|
||||
cur_par->scope = scope;
|
||||
cur_par->file = (*cur_pit).second.file;
|
||||
cur_par->lineno = (*cur_pit).second.lineno;
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -482,6 +484,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
|
||||
ivl_parameter_t cur_par = scope->param_ + idx;
|
||||
cur_par->basename = (*cur_pit).first;
|
||||
cur_par->scope = scope;
|
||||
cur_par->file = (*cur_pit).second.file;
|
||||
cur_par->lineno = (*cur_pit).second.lineno;
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -525,6 +529,7 @@ void dll_target::add_root(ivl_design_s &des_, const NetScope *s)
|
||||
ivl_scope_t root_ = new struct ivl_scope_s;
|
||||
perm_string name = s->basename();
|
||||
root_->name_ = name;
|
||||
FILE_NAME(root_, s);
|
||||
root_->child_ = 0;
|
||||
root_->sibling_ = 0;
|
||||
root_->parent = 0;
|
||||
@@ -1302,6 +1307,38 @@ void dll_target::udp(const NetUDP*net)
|
||||
scope_add_logic(scope, obj);
|
||||
}
|
||||
|
||||
void dll_target::lpm_abs(const NetAbs*net)
|
||||
{
|
||||
ivl_lpm_t obj = new struct ivl_lpm_s;
|
||||
obj->type = IVL_LPM_ABS;
|
||||
obj->name = net->name(); // NetAddSub names are permallocated.
|
||||
assert(net->scope());
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
assert(obj->scope);
|
||||
|
||||
obj->u_.arith.signed_flag = 0;
|
||||
obj->width = net->width();
|
||||
|
||||
const Nexus*nex;
|
||||
/* the output is pin(0) */
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.arith.q = nex->t_cookie();
|
||||
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
/* pin(1) is the input data. */
|
||||
obj->u_.arith.a = nex->t_cookie();
|
||||
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
make_lpm_delays_(obj, net);
|
||||
|
||||
scope_add_lpm(obj->scope, obj);
|
||||
}
|
||||
|
||||
void dll_target::lpm_add_sub(const NetAddSub*net)
|
||||
{
|
||||
ivl_lpm_t obj = new struct ivl_lpm_s;
|
||||
@@ -2142,6 +2179,7 @@ void dll_target::scope(const NetScope*net)
|
||||
perm_string sname = make_scope_name(net->fullname());
|
||||
scope = new struct ivl_scope_s;
|
||||
scope->name_ = sname;
|
||||
FILE_NAME(scope, net);
|
||||
scope->child_ = 0;
|
||||
scope->sibling_ = 0;
|
||||
scope->parent = find_scope(des_, net->parent());
|
||||
@@ -2214,6 +2252,8 @@ void dll_target::signal(const NetNet*net)
|
||||
object, or creating the sigs_ array if this is the first
|
||||
signal. */
|
||||
obj->scope_ = find_scope(des_, net->scope());
|
||||
obj->file = perm_string::literal("N/A");
|
||||
obj->lineno = 0;
|
||||
assert(obj->scope_);
|
||||
|
||||
if (obj->scope_->nsigs_ == 0) {
|
||||
|
||||
@@ -70,6 +70,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||
bool ureduce(const NetUReduce*);
|
||||
void net_case_cmp(const NetCaseCmp*);
|
||||
void udp(const NetUDP*);
|
||||
void lpm_abs(const NetAbs*);
|
||||
void lpm_add_sub(const NetAddSub*);
|
||||
bool lpm_array_dq(const NetArrayDq*);
|
||||
void lpm_clshift(const NetCLShift*);
|
||||
@@ -509,6 +510,8 @@ struct ivl_parameter_s {
|
||||
perm_string basename;
|
||||
ivl_scope_t scope;
|
||||
ivl_expr_t value;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
};
|
||||
/*
|
||||
* All we know about a process it its type (initial or always) and the
|
||||
@@ -537,6 +540,10 @@ struct ivl_scope_s {
|
||||
|
||||
perm_string name_;
|
||||
perm_string tname_;
|
||||
perm_string file;
|
||||
perm_string def_file;
|
||||
unsigned lineno;
|
||||
unsigned def_lineno;
|
||||
ivl_scope_type_t type_;
|
||||
|
||||
unsigned nsigs_;
|
||||
@@ -577,6 +584,8 @@ struct ivl_signal_s {
|
||||
ivl_signal_type_t type_;
|
||||
ivl_signal_port_t port_;
|
||||
ivl_variable_type_t data_type;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
|
||||
unsigned width_;
|
||||
unsigned signed_ : 1;
|
||||
@@ -713,4 +722,12 @@ static inline void FILE_NAME(ivl_lpm_t lpm, const LineInfo*info)
|
||||
lpm->lineno = info->get_lineno();
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(ivl_scope_t scope, const NetScope*info)
|
||||
{
|
||||
scope->file = info->get_file();
|
||||
scope->def_file = info->get_def_file();
|
||||
scope->lineno = info->get_lineno();
|
||||
scope->def_lineno = info->get_def_lineno();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -81,6 +81,12 @@ bool target_t::ureduce(const NetUReduce*)
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::lpm_abs(const NetAbs*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetAbs." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_add_sub(const NetAddSub*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
|
||||
@@ -68,6 +68,7 @@ struct target_t {
|
||||
virtual bool func_def(const NetScope*);
|
||||
|
||||
/* LPM style components are handled here. */
|
||||
virtual void lpm_abs(const NetAbs*);
|
||||
virtual void lpm_add_sub(const NetAddSub*);
|
||||
virtual bool lpm_array_dq(const NetArrayDq*);
|
||||
virtual void lpm_clshift(const NetCLShift*);
|
||||
|
||||
+26
-5
@@ -82,8 +82,9 @@ static void show_function_call(ivl_expr_t net, unsigned ind)
|
||||
const char*vt = vt_type_string(net);
|
||||
unsigned idx;
|
||||
|
||||
fprintf(out, "%*s<%s %s function %s with %u arguments>\n", ind, "",
|
||||
vt, sign, ivl_scope_name(def), ivl_expr_parms(net));
|
||||
fprintf(out, "%*s<%s %s function %s with %u arguments (width=%u)>\n",
|
||||
ind, "", vt, sign, ivl_scope_name(def), ivl_expr_parms(net),
|
||||
ivl_expr_width(net));
|
||||
|
||||
for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1)
|
||||
show_expression(ivl_expr_parm(net,idx), ind+4);
|
||||
@@ -160,6 +161,28 @@ static void show_ternary_expression(ivl_expr_t net, unsigned ind)
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
const char*vt = vt_type_string(net);
|
||||
|
||||
char name[8];
|
||||
switch (ivl_expr_opcode(net)) {
|
||||
default:
|
||||
snprintf(name, sizeof name, "%c", ivl_expr_opcode(net));
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
snprintf(name, sizeof name, "abs()");
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(out, "%*s<unary \"%s\" width=%u, %s, type=%s>\n", ind, "",
|
||||
name, width, sign, vt);
|
||||
show_expression(ivl_expr_oper1(net), ind+4);
|
||||
}
|
||||
|
||||
void show_expression(ivl_expr_t net, unsigned ind)
|
||||
{
|
||||
unsigned idx;
|
||||
@@ -252,9 +275,7 @@ void show_expression(ivl_expr_t net, unsigned ind)
|
||||
break;
|
||||
|
||||
case IVL_EX_UNARY:
|
||||
fprintf(out, "%*s<unary \"%c\" width=%u, %s, type=%s>\n", ind, "",
|
||||
ivl_expr_opcode(net), width, sign, vt);
|
||||
show_expression(ivl_expr_oper1(net), ind+4);
|
||||
show_unary_expression(net, ind);
|
||||
break;
|
||||
|
||||
case IVL_EX_UFUNC:
|
||||
|
||||
@@ -175,6 +175,32 @@ static void show_lpm_arithmetic_pins(ivl_lpm_t net)
|
||||
fprintf(out, " DataB: %s\n", nex? ivl_nexus_name(nex) : "");
|
||||
}
|
||||
|
||||
static void show_lpm_abs(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
|
||||
fprintf(out, " LPM_ABS %s: <width=%u>\n",
|
||||
ivl_lpm_basename(net), width);
|
||||
|
||||
ivl_nexus_t nex;
|
||||
nex = ivl_lpm_q(net, 0);
|
||||
fprintf(out, " Q: %s\n", ivl_nexus_name(ivl_lpm_q(net, 0)));
|
||||
|
||||
nex = ivl_lpm_data(net, 0);
|
||||
fprintf(out, " D: %s\n", nex? ivl_nexus_name(nex) : "");
|
||||
if (nex == 0) {
|
||||
fprintf(out, " ERROR: missing input\n");
|
||||
stub_errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (width_of_nexus(nex) != width) {
|
||||
fprintf(out, " ERROR: D width (%d) is wrong\n",
|
||||
width_of_nexus(nex));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_lpm_add(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
@@ -796,6 +822,10 @@ static void show_lpm(ivl_lpm_t net)
|
||||
|
||||
switch (ivl_lpm_type(net)) {
|
||||
|
||||
case IVL_LPM_ABS:
|
||||
show_lpm_abs(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_ADD:
|
||||
show_lpm_add(net);
|
||||
break;
|
||||
|
||||
+7
-3
@@ -57,10 +57,14 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
|
||||
get_number_immediate(d_rise), net);
|
||||
}
|
||||
|
||||
const char* input[3];
|
||||
input[0] = draw_net_input(ivl_lpm_data(net,0));
|
||||
input[1] = draw_net_input(ivl_lpm_data(net,1));
|
||||
input[2] = draw_net_input(ivl_lpm_select(net));
|
||||
fprintf(vvp_out, "L_%p%s .functor %s %u", net, dly, muxz, width);
|
||||
fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_data(net,0)));
|
||||
fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_data(net,1)));
|
||||
fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_select(net)));
|
||||
fprintf(vvp_out, ", %s", input[0]);
|
||||
fprintf(vvp_out, ", %s", input[1]);
|
||||
fprintf(vvp_out, ", %s", input[2]);
|
||||
fprintf(vvp_out, ", C4<>;\n");
|
||||
}
|
||||
|
||||
|
||||
+109
-136
@@ -52,9 +52,12 @@ static int is_fixed_memory_word(ivl_expr_t net)
|
||||
|
||||
sig = ivl_expr_signal(net);
|
||||
|
||||
if (ivl_signal_array_count(sig) == 1)
|
||||
if (ivl_signal_dimensions(sig) == 0)
|
||||
return 1;
|
||||
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG)
|
||||
return 0;
|
||||
|
||||
if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned)))
|
||||
return 1;
|
||||
|
||||
@@ -69,9 +72,14 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
unsigned parm_count = tnet
|
||||
? ivl_stmt_parm_count(tnet)
|
||||
: ivl_expr_parms(fnet);
|
||||
struct vector_info *vec = 0x0;
|
||||
unsigned int vecs= 0;
|
||||
unsigned int veci= 0;
|
||||
|
||||
struct args_info {
|
||||
char*text;
|
||||
int vec_flag; /* True if the vec must be released. */
|
||||
struct vector_info vec;
|
||||
} *args = calloc(parm_count, sizeof(struct args_info));
|
||||
|
||||
char buffer[4096];
|
||||
|
||||
ivl_parameter_t par;
|
||||
|
||||
@@ -89,17 +97,56 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
with VPI handles of their own. Therefore, skip
|
||||
them in the process of evaluating expressions. */
|
||||
case IVL_EX_NONE:
|
||||
args[idx].text = strdup("\" \"");
|
||||
continue;
|
||||
|
||||
case IVL_EX_ARRAY:
|
||||
case IVL_EX_NUMBER:
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"v%p", ivl_expr_signal(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
|
||||
case IVL_EX_NUMBER: {
|
||||
unsigned bit, wid = ivl_expr_width(expr);
|
||||
const char*bits = ivl_expr_bits(expr);
|
||||
char*dp;
|
||||
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"%u'%sb", wid, ivl_expr_signed(expr)? "s" : "");
|
||||
dp = buffer + strlen(buffer);
|
||||
for (bit = wid ; bit > 0 ; bit -= 1)
|
||||
*dp++ = bits[bit-1];
|
||||
*dp++ = 0;
|
||||
assert(dp - buffer <= sizeof buffer);
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
case IVL_EX_STRING:
|
||||
if (( par = ivl_expr_parameter(expr) )) {
|
||||
snprintf(buffer, sizeof buffer, "P_%p", par);
|
||||
|
||||
} else {
|
||||
snprintf(buffer, sizeof buffer, "\"%s\"", ivl_expr_string(expr));
|
||||
}
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
|
||||
case IVL_EX_EVENT:
|
||||
snprintf(buffer, sizeof buffer, "E_%p", ivl_expr_event(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
case IVL_EX_SCOPE:
|
||||
snprintf(buffer, sizeof buffer, "S_%p", ivl_expr_scope(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
|
||||
case IVL_EX_SFUNC:
|
||||
if (is_magic_sfunc(ivl_expr_name(expr)))
|
||||
if (is_magic_sfunc(ivl_expr_name(expr))) {
|
||||
snprintf(buffer, sizeof buffer, "%s", ivl_expr_name(expr));
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
@@ -122,21 +169,47 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
} else if (ivl_expr_signed(expr) !=
|
||||
ivl_signal_signed(ivl_expr_signal(expr))) {
|
||||
break;
|
||||
} else if (! is_fixed_memory_word(expr)){
|
||||
break;
|
||||
} else {
|
||||
/* Some array selects need to be evaluated. */
|
||||
} else if (is_fixed_memory_word(expr)) {
|
||||
/* This is a word of a non-array, or a word
|
||||
of a net array, so we can address the
|
||||
word directly. */
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
unsigned use_word = 0;
|
||||
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||
if (word_ex && !number_is_immediate(word_ex,
|
||||
8*sizeof(unsigned))) {
|
||||
break;
|
||||
if (word_ex) {
|
||||
/* Some array select have been evaluated. */
|
||||
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
|
||||
use_word = get_number_immediate(word_ex);
|
||||
word_ex = 0;
|
||||
}
|
||||
}
|
||||
if (word_ex)
|
||||
break;
|
||||
|
||||
assert(word_ex == 0);
|
||||
snprintf(buffer, sizeof buffer, "v%p_%u", sig, use_word);
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* What's left, this is the work of a var
|
||||
array. Create the right code to handle
|
||||
it. */
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
unsigned use_word = 0;
|
||||
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||
if (word_ex) {
|
||||
/* Some array select have been evaluated. */
|
||||
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
|
||||
use_word = get_number_immediate(word_ex);
|
||||
word_ex = 0;
|
||||
}
|
||||
}
|
||||
if (word_ex)
|
||||
break;
|
||||
|
||||
case IVL_EX_MEMORY:
|
||||
if (!ivl_expr_oper1(expr)) {
|
||||
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -146,143 +219,43 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
break;
|
||||
}
|
||||
|
||||
vec = (struct vector_info *)
|
||||
realloc(vec, (vecs+1)*sizeof(struct vector_info));
|
||||
|
||||
switch (ivl_expr_value(expr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
vec[vecs] = draw_eval_expr(expr, 0);
|
||||
args[idx].vec_flag = 1;
|
||||
args[idx].vec = draw_eval_expr(expr, 0);
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"T<%u,%u,%s>", args[idx].vec.base, args[idx].vec.wid,
|
||||
ivl_expr_signed(expr)? "s" : "u");
|
||||
break;
|
||||
case IVL_VT_REAL:
|
||||
vec[vecs].base = draw_eval_real(expr);
|
||||
vec[vecs].wid = 0;
|
||||
args[idx].vec_flag = 1;
|
||||
args[idx].vec.base = draw_eval_real(expr);
|
||||
args[idx].vec.wid = 0;
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"W<%u,r>", args[idx].vec.base);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
vecs++;
|
||||
args[idx].text = strdup(buffer);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "%s", call_string);
|
||||
|
||||
for (idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
ivl_expr_t expr = tnet
|
||||
? ivl_stmt_parm(tnet, idx)
|
||||
: ivl_expr_parm(fnet, idx);
|
||||
|
||||
switch (ivl_expr_type(expr)) {
|
||||
case IVL_EX_NONE:
|
||||
fprintf(vvp_out, ", \" \"");
|
||||
continue;
|
||||
|
||||
case IVL_EX_ARRAY:
|
||||
fprintf(vvp_out, ", v%p", ivl_expr_signal(expr));
|
||||
continue;
|
||||
|
||||
case IVL_EX_NUMBER: {
|
||||
unsigned bit, wid = ivl_expr_width(expr);
|
||||
const char*bits = ivl_expr_bits(expr);
|
||||
|
||||
fprintf(vvp_out, ", %u'%sb", wid,
|
||||
ivl_expr_signed(expr)? "s" : "");
|
||||
for (bit = wid ; bit > 0 ; bit -= 1)
|
||||
fputc(bits[bit-1], vvp_out);
|
||||
continue;
|
||||
}
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
/* If this is a part select, then the value was
|
||||
calculated above. Otherwise, just pass the
|
||||
signal. */
|
||||
if (ivl_expr_width(expr) !=
|
||||
ivl_signal_width(ivl_expr_signal(expr))) {
|
||||
break;
|
||||
|
||||
} else if (ivl_expr_signed(expr) !=
|
||||
ivl_signal_signed(ivl_expr_signal(expr))) {
|
||||
break;
|
||||
|
||||
} else if (! is_fixed_memory_word(expr)){
|
||||
break;
|
||||
|
||||
} else {
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
unsigned use_word = 0;
|
||||
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
||||
if (word_ex) {
|
||||
/* Some array select have been evaluated. */
|
||||
if (!number_is_immediate(word_ex,
|
||||
8*sizeof(unsigned))) {
|
||||
break;
|
||||
}
|
||||
use_word = get_number_immediate(word_ex);
|
||||
}
|
||||
fprintf(vvp_out, ", v%p_%u", sig, use_word);
|
||||
continue;
|
||||
}
|
||||
assert(0);
|
||||
continue;
|
||||
|
||||
case IVL_EX_STRING:
|
||||
if (( par = ivl_expr_parameter(expr) )) {
|
||||
fprintf(vvp_out, ", P_%p", par);
|
||||
|
||||
} else {
|
||||
fprintf(vvp_out, ", \"%s\"",
|
||||
ivl_expr_string(expr));
|
||||
}
|
||||
continue;
|
||||
|
||||
case IVL_EX_EVENT:
|
||||
fprintf(vvp_out, ", E_%p", ivl_expr_event(expr));
|
||||
continue;
|
||||
|
||||
case IVL_EX_SCOPE:
|
||||
fprintf(vvp_out, ", S_%p", ivl_expr_scope(expr));
|
||||
continue;
|
||||
|
||||
case IVL_EX_SFUNC:
|
||||
if (is_magic_sfunc(ivl_expr_name(expr))) {
|
||||
fprintf(vvp_out, ", %s", ivl_expr_name(expr));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
fprintf(vvp_out, ", %s", args[idx].text);
|
||||
free(args[idx].text);
|
||||
if (args[idx].vec_flag) {
|
||||
if (args[idx].vec.wid > 0)
|
||||
clr_vector(args[idx].vec);
|
||||
else
|
||||
clr_word(args[idx].vec.base);
|
||||
}
|
||||
assert(veci < vecs);
|
||||
|
||||
switch (ivl_expr_value(expr)) {
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
fprintf(vvp_out, ", T<%u,%u,%s>", vec[veci].base,
|
||||
vec[veci].wid, ivl_expr_signed(expr)? "s" : "u");
|
||||
break;
|
||||
|
||||
case IVL_VT_REAL:
|
||||
fprintf(vvp_out, ", W<%u,r>", vec[veci].base);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
veci++;
|
||||
}
|
||||
|
||||
assert(veci == vecs);
|
||||
|
||||
if (vecs) {
|
||||
for (idx = 0; idx < vecs; idx++) {
|
||||
if (vec[idx].wid > 0)
|
||||
clr_vector(vec[idx]);
|
||||
else if (vec[idx].wid == 0)
|
||||
clr_word(vec[idx].base);
|
||||
}
|
||||
free(vec);
|
||||
}
|
||||
free(args);
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
|
||||
+63
-26
@@ -138,8 +138,22 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
|
||||
|
||||
case IVL_EX_SIGNAL: {
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
|
||||
unsigned word = 0;
|
||||
if (ivl_signal_array_count(sig) > 1) {
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* Detect the special case that this is a
|
||||
variable array. In this case, the ix/getv
|
||||
will not work, so do it the hard way. */
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG) {
|
||||
struct vector_info rv;
|
||||
rv = draw_eval_expr(expr, 0);
|
||||
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
||||
ix, rv.base, rv.wid);
|
||||
clr_vector(rv);
|
||||
break;
|
||||
}
|
||||
|
||||
ivl_expr_t ixe = ivl_expr_oper1(expr);
|
||||
if (number_is_immediate(ixe, 8*sizeof(unsigned long)))
|
||||
word = get_number_immediate(ixe);
|
||||
@@ -1246,7 +1260,7 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
|
||||
struct vector_info lv;
|
||||
struct vector_info rv;
|
||||
|
||||
const char*sign_string = ivl_expr_signed(exp)? "/s" : "";
|
||||
const char*sign_string = ivl_expr_signed(le) && ivl_expr_signed(re)? "/s" : "";
|
||||
|
||||
if ((ivl_expr_opcode(exp) == '+')
|
||||
&& (ivl_expr_type(le) == IVL_EX_SIGNAL)
|
||||
@@ -1894,28 +1908,23 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
|
||||
|
||||
/* If this is an access to an array, handle that by emitting a
|
||||
load/av instruction. */
|
||||
if (ivl_signal_array_count(sig) > 1) {
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
ivl_expr_t ix = ivl_expr_oper1(exp);
|
||||
if (!number_is_immediate(ix, 8*sizeof(unsigned long))) {
|
||||
draw_eval_expr_into_integer(ix, 3);
|
||||
if (add_index < 0) {
|
||||
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
||||
res.base, sig, swid);
|
||||
} else {
|
||||
assert(add_index == 0);
|
||||
|
||||
/* Add an immediate value to an array value. */
|
||||
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
|
||||
fprintf(vvp_out, " %%load/avp0 %u, v%p, %u;\n",
|
||||
res.base, sig, swid);
|
||||
}
|
||||
pad_expr_in_place(exp, res, swid);
|
||||
return;
|
||||
draw_eval_expr_into_integer(ix, 3);
|
||||
if (add_index < 0) {
|
||||
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
||||
res.base, sig, swid);
|
||||
} else {
|
||||
assert(add_index == 0);
|
||||
|
||||
/* Add an immediate value to an array value. */
|
||||
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
|
||||
fprintf(vvp_out, " %%load/avp0 %u, v%p, %u;\n",
|
||||
res.base, sig, swid);
|
||||
}
|
||||
|
||||
/* The index is constant, so we can return to direct
|
||||
readout with the specific word selected. */
|
||||
word = get_number_immediate(ix);
|
||||
pad_expr_in_place(exp, res, swid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2030,14 +2039,16 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
|
||||
unsigned use_word = 0;
|
||||
|
||||
/* If this is an access to an array, try to get the index as a
|
||||
constant. If it is, then this reduces to a signal access
|
||||
and we stay here. If it is not constant, then give up and
|
||||
do an array index in front of this part select. */
|
||||
constant. If it is (and the array is not a reg array then
|
||||
this reduces to a signal access and we stay here. If it is
|
||||
not constant, then give up and do an array index in front
|
||||
of this part select. */
|
||||
|
||||
if (ivl_signal_array_count(sig) > 1) {
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
ivl_expr_t ix = ivl_expr_oper1(sube);
|
||||
|
||||
if (!number_is_immediate(ix, 8*sizeof(unsigned long)))
|
||||
if (ivl_signal_type(sig)==IVL_SIT_REG
|
||||
|| !number_is_immediate(ix, 8*sizeof(unsigned long)))
|
||||
return draw_select_array(sube, bit_idx, bit_wid, wid);
|
||||
|
||||
/* The index is constant, so we can return to direct
|
||||
@@ -2456,6 +2467,32 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': /* abs() */
|
||||
res = draw_eval_expr_wid(sub, wid, 0);
|
||||
|
||||
if (!ivl_expr_signed(sub))
|
||||
break;
|
||||
|
||||
if (res.base == 0 || res.base == 2 || res.base == 3)
|
||||
break;
|
||||
|
||||
/* Handle the special case of a -1 constant. Make the
|
||||
result a 1. */
|
||||
if (res.base == 1) {
|
||||
res.base = allocate_vector(wid);
|
||||
fprintf(vvp_out, " %%movi %d, 1, %u;\n",
|
||||
res.base, res.wid);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%cmpi/s %d, 0, %u;\n", res.base, res.wid);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, local_count);
|
||||
fprintf(vvp_out, " %%inv %d, %u;\n", res.base, res.wid);
|
||||
fprintf(vvp_out, " %%addi %d, 1, %u;\n", res.base, res.wid);
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_count);
|
||||
local_count += 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "vvp error: unhandled unary: %c\n",
|
||||
ivl_expr_opcode(exp));
|
||||
|
||||
@@ -112,6 +112,42 @@ static int draw_binary_real(ivl_expr_t exp)
|
||||
case 'p':
|
||||
fprintf(vvp_out, " %%pow/wr %d, %d;\n", l, r);
|
||||
break;
|
||||
|
||||
case 'm': { // min(l,r)
|
||||
int lab_out = local_count++;
|
||||
int lab_r = local_count++;
|
||||
/* If r is NaN, the go out and accept l as result. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out);
|
||||
/* If l is NaN, the go out and accept r as result. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r);
|
||||
/* If l <= r then go out. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out);
|
||||
/* At this point we know we want r as the result. */
|
||||
fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, lab_r, l, r);
|
||||
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'M': { // max(l,r)
|
||||
int lab_out = local_count++;
|
||||
int lab_r = local_count++;
|
||||
/* If r is NaN, the go out and accept l as result. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out);
|
||||
/* If l is NaN, the go out and accept r as result. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r);
|
||||
/* if l >= r then go out. */
|
||||
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out);
|
||||
|
||||
fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, lab_r, l, r);
|
||||
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "XXXX draw_binary_real(%c)\n",
|
||||
ivl_expr_opcode(exp));
|
||||
@@ -420,6 +456,11 @@ static int draw_unary_real(ivl_expr_t exp)
|
||||
return res;
|
||||
}
|
||||
|
||||
if (ivl_expr_opcode(exp) == 'm') { /* abs(sube) */
|
||||
fprintf(vvp_out, " %%abs/wr %d, %d;\n", sub, sub);
|
||||
return sub;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "; XXXX unary (%c)\n", ivl_expr_opcode(exp));
|
||||
fprintf(stderr, "XXXX evaluate unary (%c)\n", ivl_expr_opcode(exp));
|
||||
return 0;
|
||||
|
||||
+89
-32
@@ -99,7 +99,7 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||
if (ivl_lval_mux(lval))
|
||||
part_off_ex = ivl_lval_mux(lval);
|
||||
|
||||
if (part_off_ex) {
|
||||
if (part_off_ex && ivl_signal_dimensions(sig) == 0) {
|
||||
unsigned skip_set = transient_id++;
|
||||
|
||||
/* There is a mux expression, so this must be a write to
|
||||
@@ -118,6 +118,39 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||
lookaside. */
|
||||
save_signal_lookaside(bit, sig, use_word, 0);
|
||||
|
||||
} else if (part_off_ex && ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* Here we have a part select write into an array word. */
|
||||
unsigned skip_set = transient_id++;
|
||||
if (word_ix) {
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word);
|
||||
}
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
||||
} else if ((part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig))
|
||||
&& ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* Here we have a part select write into an array word. */
|
||||
unsigned skip_set = transient_id++;
|
||||
if (word_ix) {
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word);
|
||||
}
|
||||
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
if (word_ix) /* Only need this label if word_ix is set. */
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
||||
} else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
|
||||
/* There is no mux expression, but a constant part
|
||||
offset. Load that into index x0 and generate a
|
||||
@@ -145,14 +178,16 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||
lookaside. */
|
||||
save_signal_lookaside(bit, sig, use_word, 0);
|
||||
|
||||
} else if (ivl_signal_array_count(sig) > 1) {
|
||||
} else if (ivl_signal_dimensions(sig) > 0) {
|
||||
|
||||
/* If the word index is a constant, then we can write
|
||||
directly to the word and save the index calculation. */
|
||||
if (word_ix == 0) {
|
||||
if (use_word < ivl_signal_array_count(sig)) {
|
||||
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
||||
sig, use_word, bit, wid);
|
||||
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
} else {
|
||||
fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u "
|
||||
"OUT OF BOUNDS\n", sig, use_word, bit, wid);
|
||||
@@ -185,44 +220,70 @@ static void set_to_lvariable(ivl_lval_t lval,
|
||||
|
||||
static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
||||
unsigned bit, unsigned delay, ivl_expr_t dexp,
|
||||
unsigned width)
|
||||
ivl_expr_t part_off_ex, unsigned width)
|
||||
{
|
||||
unsigned skip_assign = transient_id++;
|
||||
|
||||
unsigned part_off = 0;
|
||||
if (part_off_ex == 0) {
|
||||
part_off = 0;
|
||||
} else if (number_is_immediate(part_off_ex, 64)) {
|
||||
part_off = get_number_immediate(part_off_ex);
|
||||
part_off_ex = 0;
|
||||
}
|
||||
|
||||
if (dexp == 0) {
|
||||
/* Constant delay... */
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
|
||||
if (number_is_immediate(word_ix, 64)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
|
||||
get_number_immediate(word_ix));
|
||||
} else {
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
}
|
||||
/* Store expression width into index word 0 */
|
||||
fprintf(vvp_out, " %%ix/load 0, %u; // word width\n", width);
|
||||
/* Store constant (0) word part select into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
||||
|
||||
fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width);
|
||||
if (part_off_ex) {
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
/* If the index expression has XZ bits, skip the assign. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
} else {
|
||||
/* Store word part select base into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, %u; part base\n", part_off);
|
||||
}
|
||||
fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig,
|
||||
delay, bit);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
||||
} else {
|
||||
/* Calculated delay... */
|
||||
int delay_index = allocate_word();
|
||||
draw_eval_expr_into_integer(dexp, delay_index);
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
|
||||
if (number_is_immediate(word_ix, 64)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
|
||||
get_number_immediate(word_ix));
|
||||
} else {
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
}
|
||||
/* Store expression width into index word 0 */
|
||||
fprintf(vvp_out, " %%ix/load 0, %u; // word width\n", width);
|
||||
/* Store constant (0) word part select into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, 0;\n");
|
||||
|
||||
fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width);
|
||||
if (part_off_ex) {
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
/* If the index expression has XZ bits, skip the assign. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
} else {
|
||||
/* Store word part select into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, %u; part off\n", part_off);
|
||||
}
|
||||
fprintf(vvp_out, " %%assign/av/d v%p, %d, %u;\n", lsig,
|
||||
delay_index, bit);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_assign);
|
||||
|
||||
clear_expression_lookaside();
|
||||
}
|
||||
|
||||
@@ -235,16 +296,12 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
|
||||
unsigned part_off = 0;
|
||||
|
||||
ivl_expr_t word_ix = ivl_lval_idx(lval);
|
||||
unsigned long use_word = 0;
|
||||
const unsigned long use_word = 0;
|
||||
|
||||
if (ivl_signal_array_count(sig) > 1) {
|
||||
assert(word_ix);
|
||||
if (! number_is_immediate(word_ix, 8*sizeof(use_word))) {
|
||||
assign_to_array_word(sig, word_ix, bit, delay, dexp, width);
|
||||
return;
|
||||
}
|
||||
|
||||
use_word = get_number_immediate(word_ix);
|
||||
assign_to_array_word(sig, word_ix, bit, delay, dexp, part_off_ex, width);
|
||||
return;
|
||||
}
|
||||
|
||||
if (part_off_ex == 0) {
|
||||
|
||||
+39
-6
@@ -615,6 +615,12 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
/* Input is a .var. This device may be a non-zero pin
|
||||
because it may be an array of reg vectors. */
|
||||
snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
|
||||
|
||||
if (ivl_signal_array_count(sptr) > 1) {
|
||||
fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
|
||||
sptr, nptr_pin, sptr, nptr_pin);
|
||||
}
|
||||
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
@@ -679,6 +685,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
if (lpm) switch (ivl_lpm_type(lpm)) {
|
||||
|
||||
case IVL_LPM_FF:
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_ARRAY:
|
||||
case IVL_LPM_CONCAT:
|
||||
@@ -987,6 +994,8 @@ const char*draw_input_from_net(ivl_nexus_t nex)
|
||||
ivl_signal_t sig = signal_of_nexus(nex, &word);
|
||||
if (sig == 0)
|
||||
return draw_net_input(nex);
|
||||
if (ivl_signal_type(sig)==IVL_SIT_REG && ivl_signal_dimensions(sig)>0)
|
||||
return draw_net_input(nex);
|
||||
|
||||
snprintf(result, sizeof result, "v%p_%u", sig, word);
|
||||
return result;
|
||||
@@ -1693,6 +1702,17 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net)
|
||||
return dly;
|
||||
}
|
||||
|
||||
static void draw_lpm_abs(ivl_lpm_t net)
|
||||
{
|
||||
const char*src_table[1];
|
||||
draw_lpm_data_inputs(net, 0, 1, src_table);
|
||||
|
||||
const char*dly = draw_lpm_output_delay(net);
|
||||
|
||||
fprintf(vvp_out, "L_%p%s .abs %s;\n",
|
||||
net, dly, src_table[0]);
|
||||
}
|
||||
|
||||
static void draw_lpm_add(ivl_lpm_t net)
|
||||
{
|
||||
const char*src_table[2];
|
||||
@@ -2338,6 +2358,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
|
||||
{
|
||||
switch (ivl_lpm_type(net)) {
|
||||
|
||||
case IVL_LPM_ABS:
|
||||
draw_lpm_abs(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_SUB:
|
||||
case IVL_LPM_MULT:
|
||||
@@ -2444,12 +2468,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\"",
|
||||
fprintf(vvp_out, "S_%p .scope %s, \"%s\" \"%s\" %d %d",
|
||||
net, type, vvp_mangle_name(ivl_scope_basename(net)),
|
||||
ivl_scope_tname(net));
|
||||
ivl_scope_tname(net), ivl_file_table_index(ivl_scope_file(net)),
|
||||
ivl_scope_lineno(net));
|
||||
|
||||
if (parent) {
|
||||
fprintf(vvp_out, ", S_%p;\n", parent);
|
||||
fprintf(vvp_out, ", %d %d, S_%p;\n",
|
||||
ivl_file_table_index(ivl_scope_def_file(net)),
|
||||
ivl_scope_def_lineno(net), parent);
|
||||
} else {
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
@@ -2463,13 +2490,17 @@ 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\", \"%s\";\n",
|
||||
fprintf(vvp_out, "P_%p .param/str \"%s\" %d %d, \"%s\";\n",
|
||||
par, ivl_parameter_basename(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\", %sC4<",
|
||||
fprintf(vvp_out, "P_%p .param/l \"%s\" %d %d, %sC4<",
|
||||
par, ivl_parameter_basename(par),
|
||||
ivl_file_table_index(ivl_parameter_file(par)),
|
||||
ivl_parameter_lineno(par),
|
||||
ivl_expr_signed(pex)? "+":"");
|
||||
{ const char*bits = ivl_expr_bits(pex);
|
||||
unsigned nbits = ivl_expr_width(pex);
|
||||
@@ -2480,8 +2511,10 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
||||
fprintf(vvp_out, ">;\n");
|
||||
break;
|
||||
case IVL_EX_REALNUM:
|
||||
fprintf(vvp_out, "P_%p .param/real \"%s\", %s; value=%g\n",
|
||||
fprintf(vvp_out, "P_%p .param/real \"%s\" %d %d, %s; value=%g\n",
|
||||
par, ivl_parameter_basename(par),
|
||||
ivl_file_table_index(ivl_parameter_file(par)),
|
||||
ivl_parameter_lineno(par),
|
||||
draw_Cr_to_string(ivl_expr_dvalue(pex)),
|
||||
ivl_expr_dvalue(pex));
|
||||
break;
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
|
||||
The following is from the README.va_math that was included with the
|
||||
initial contribution of the va_math module. I've removed the parts
|
||||
that are obviously not applicable, i.e. how to compile the library, to
|
||||
this bundled version of the library.
|
||||
|
||||
--------
|
||||
License.
|
||||
--------
|
||||
|
||||
Verilog-A math library built for Icarus Verilog
|
||||
http://www.icarus.com/eda/verilog/
|
||||
|
||||
Copyright (C) 2007-2008 Cary R. ([email protected])
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
|
||||
------------------------------------------
|
||||
Standard Verilog-A Mathematical Functions.
|
||||
------------------------------------------
|
||||
|
||||
The va_math VPI module implements all the standard math functions provided
|
||||
by Verilog-A as Verilog-D system functions. The names are the same except
|
||||
like all Verilog-D system functions the name must be prefixed with a '$'.
|
||||
For reference the functions are:
|
||||
|
||||
$ln(x) -- Natural logarithm
|
||||
$log(x) -- Decimal logarithm
|
||||
$exp(x) -- Exponential
|
||||
$sqrt(x) -- Square root
|
||||
$min(x,y) -- Minimum
|
||||
$max(x,y) -- Maximum
|
||||
$abs(x) -- Absolute value
|
||||
$floor(x) -- Floor
|
||||
$ceil(x) -- Ceiling
|
||||
$pow(x,y) -- Power (x**y)
|
||||
$sin(x) -- Sine
|
||||
$cos(x) -- Cosine
|
||||
$tan(x) -- Tangent
|
||||
$asin(x) -- Arc-sine
|
||||
$acos(x) -- Arc-cosine
|
||||
$atan(x) -- Arc-tangent
|
||||
$atan2(y,x) -- Arc-tangent of y/x
|
||||
$hypot(x,y) -- Hypotenuse (sqrt(x**2 + y**2))
|
||||
$sinh(x) -- Hyperbolic sine
|
||||
$cosh(x) -- Hyperbolic cosine
|
||||
$tanh(x) -- Hyperbolic tangent
|
||||
$asinh(x) -- Arc-hyperbolic sine
|
||||
$acosh(x) -- Arc-hyperbolic cosine
|
||||
$atanh(x) -- Arc-hyperbolic tangent
|
||||
|
||||
The only limit placed on the x and y arguments by the library is that they
|
||||
must be numbers (not constant strings). The underlying C library controls
|
||||
any other limits placed on the arguments. Most libraries return +-Inf or
|
||||
NaN for results that cannot be represented with real numbers. All functions
|
||||
return a real result.
|
||||
|
||||
|
||||
------------------------------------------
|
||||
Standard Verilog-A Mathematical Constants.
|
||||
------------------------------------------
|
||||
|
||||
The Verilog-A mathematical constants can be accessed by including the
|
||||
"constants.vams" header file. It is located in the standard include
|
||||
directory. Recent version of Icarus Verilog (0.9.devel) automatically
|
||||
add this directory to the end of the list used to find include files.
|
||||
For reference the mathematical constants are:
|
||||
|
||||
`M_PI -- Pi
|
||||
`M_TWO_PI -- 2*Pi
|
||||
`M_PI_2 -- Pi/2
|
||||
`M_PI_4 -- Pi/4
|
||||
`M_1_PI -- 1/Pi
|
||||
`M_2_PI -- 2/Pi
|
||||
`M_2_SQRTPI -- 2/sqrt(Pi)
|
||||
`M_E -- e
|
||||
`M_LOG2E -- log base 2 of e
|
||||
`M_LOG10E -- log base 10 of e
|
||||
`M_LN2 -- log base e of 2
|
||||
`M_LN10 -- log base e of 10
|
||||
`M_SQRT2 -- sqrt(2)
|
||||
`M_SQRT1_2 -- 1/sqrt(2)
|
||||
|
||||
|
||||
------------------
|
||||
Using the Library.
|
||||
------------------
|
||||
|
||||
Just add "-m va_math" to your iverilog command line/command file and
|
||||
`include the "constants.vams" file as needed.
|
||||
|
||||
------
|
||||
Thanks
|
||||
------
|
||||
|
||||
I would like to thank Larry Doolittle for his suggestions and
|
||||
Stephen Williams for developing Icarus Verilog.
|
||||
|
||||
|
||||
--------
|
||||
The End.
|
||||
--------
|
||||
+40
-35
@@ -1,10 +1,15 @@
|
||||
#norootforbuild
|
||||
#
|
||||
%define rev_date 20080429
|
||||
#
|
||||
#
|
||||
Summary: Icarus Verilog
|
||||
Name: verilog
|
||||
Version: 0.9.0.20080429
|
||||
Version: 0.9.0.%{rev_date}
|
||||
Release: 0
|
||||
License: GPL
|
||||
Group: Productivity/Scientific/Electronics
|
||||
Source: verilog-20080429.tar.gz
|
||||
Source: verilog-%{rev_date}.tar.gz
|
||||
URL: http://www.icarus.com/eda/verilog/index.html
|
||||
Packager: Stephen Williams <[email protected]>
|
||||
|
||||
@@ -22,14 +27,14 @@ engineering formats, including simulation. It strives to be true
|
||||
to the IEEE-1364 standard.
|
||||
|
||||
%prep
|
||||
%setup -n verilog-20080429
|
||||
%setup -n verilog-%{rev_date}
|
||||
|
||||
%build
|
||||
./configure --prefix=/usr --mandir='$(prefix)/share/man'
|
||||
%{configure}
|
||||
make CXXFLAGS=-O
|
||||
|
||||
%install
|
||||
make prefix=$RPM_BUILD_ROOT/usr install
|
||||
%{makeinstall}
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
@@ -39,35 +44,35 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%attr(-,root,root) %doc COPYING README.txt BUGS.txt QUICK_START.txt ieee1364-notes.txt mingw.txt swift.txt netlist.txt t-dll.txt vpi.txt xnf.txt tgt-fpga/fpga.txt cadpli/cadpli.txt xilinx-hint.txt
|
||||
%attr(-,root,root) %doc examples/*
|
||||
|
||||
%attr(-,root,root) /usr/share/man/man1/iverilog.1.gz
|
||||
%attr(-,root,root) %{_mandir}/man1/iverilog.1.gz
|
||||
#%attr(-,root,root) /usr/man/man1/iverilog-fpga.1.gz
|
||||
%attr(-,root,root) /usr/share/man/man1/iverilog-vpi.1.gz
|
||||
%attr(-,root,root) /usr/share/man/man1/vvp.1.gz
|
||||
%attr(-,root,root) %{_mandir}/man1/iverilog-vpi.1.gz
|
||||
%attr(-,root,root) %{_mandir}/man1/vvp.1.gz
|
||||
|
||||
%attr(-,root,root) /usr/bin/iverilog
|
||||
%attr(-,root,root) /usr/bin/iverilog-vpi
|
||||
%attr(-,root,root) /usr/bin/vvp
|
||||
%attr(-,root,root) /usr/lib/ivl/ivl
|
||||
%attr(-,root,root) /usr/lib/ivl/ivlpp
|
||||
%attr(-,root,root) /usr/lib/ivl/null.tgt
|
||||
%attr(-,root,root) /usr/lib/ivl/null.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/null-s.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/stub.tgt
|
||||
%attr(-,root,root) /usr/lib/ivl/stub.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/stub-s.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/vvp.tgt
|
||||
%attr(-,root,root) /usr/lib/ivl/vvp.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/vvp-s.conf
|
||||
#%attr(-,root,root) /usr/lib/ivl/fpga.tgt
|
||||
#%attr(-,root,root) /usr/lib/ivl/fpga.conf
|
||||
#%attr(-,root,root) /usr/lib/ivl/fpga-s.conf
|
||||
#%attr(-,root,root) /usr/lib/ivl/xnf.conf
|
||||
#%attr(-,root,root) /usr/lib/ivl/xnf-s.conf
|
||||
%attr(-,root,root) /usr/lib/ivl/system.sft
|
||||
%attr(-,root,root) /usr/lib/ivl/system.vpi
|
||||
%attr(-,root,root) /usr/lib/ivl/cadpli.vpl
|
||||
%attr(-,root,root) /usr/lib/libvpi.a
|
||||
%attr(-,root,root) /usr/lib/libveriuser.a
|
||||
%attr(-,root,root) %{_bindir}/iverilog
|
||||
%attr(-,root,root) %{_bindir}/iverilog-vpi
|
||||
%attr(-,root,root) %{_bindir}/vvp
|
||||
%attr(-,root,root) %{_libdir}/ivl/ivl
|
||||
%attr(-,root,root) %{_libdir}/ivl/ivlpp
|
||||
%attr(-,root,root) %{_libdir}/ivl/null.tgt
|
||||
%attr(-,root,root) %{_libdir}/ivl/null.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/null-s.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/stub.tgt
|
||||
%attr(-,root,root) %{_libdir}/ivl/stub.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/stub-s.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/vvp.tgt
|
||||
%attr(-,root,root) %{_libdir}/ivl/vvp.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/vvp-s.conf
|
||||
#%attr(-,root,root) %{_libdir}/ivl/fpga.tgt
|
||||
#%attr(-,root,root) %{_libdir}/ivl/fpga.conf
|
||||
#%attr(-,root,root) %{_libdir}/ivl/fpga-s.conf
|
||||
#%attr(-,root,root) %{_libdir}/ivl/xnf.conf
|
||||
#%attr(-,root,root) %{_libdir}/ivl/xnf-s.conf
|
||||
%attr(-,root,root) %{_libdir}/ivl/system.sft
|
||||
%attr(-,root,root) %{_libdir}/ivl/system.vpi
|
||||
%attr(-,root,root) %{_libdir}/ivl/cadpli.vpl
|
||||
%attr(-,root,root) %{_libdir}/libvpi.a
|
||||
%attr(-,root,root) %{_libdir}/libveriuser.a
|
||||
%attr(-,root,root) /usr/include/ivl_target.h
|
||||
%attr(-,root,root) /usr/include/vpi_user.h
|
||||
%attr(-,root,root) /usr/include/acc_user.h
|
||||
@@ -75,8 +80,8 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%attr(-,root,root) /usr/include/_pli_types.h
|
||||
|
||||
%changelog -n verilog
|
||||
* Sun Feb 28 2007 - [email protected]
|
||||
- Added formatting suitable for openSUSE packaging.
|
||||
|
||||
* Fri Jan 25 2008 - [email protected]
|
||||
- Removed vvp32 support for x86_64 build.
|
||||
|
||||
* Sun Feb 28 2007 - [email protected]
|
||||
- Added formatting suitable for openSUSE packaging.
|
||||
|
||||
+3
-3
@@ -448,7 +448,7 @@ verinum pad_to_width(const verinum&that, unsigned width)
|
||||
verinum::V pad = that[that.len()-1];
|
||||
if (pad==verinum::V1 && !that.has_sign())
|
||||
pad = verinum::V0;
|
||||
if (that.has_len()) {
|
||||
if (that.has_len() && !that.has_sign()) {
|
||||
if (pad==verinum::Vx)
|
||||
pad = verinum::V0;
|
||||
if (pad==verinum::Vz)
|
||||
@@ -1238,9 +1238,9 @@ verinum::V operator & (verinum::V l, verinum::V r)
|
||||
verinum::V operator ^ (verinum::V l, verinum::V r)
|
||||
{
|
||||
if (l == verinum::V0)
|
||||
return r;
|
||||
return bit4_z2x(r);
|
||||
if (r == verinum::V0)
|
||||
return l;
|
||||
return bit4_z2x(l);
|
||||
if ((l == verinum::V1) && (r == verinum::V1))
|
||||
return verinum::V0;
|
||||
|
||||
|
||||
@@ -130,6 +130,9 @@ extern verinum trim_vnum(const verinum&);
|
||||
extern ostream& operator<< (ostream&, const verinum&);
|
||||
extern ostream& operator<< (ostream&, verinum::V);
|
||||
|
||||
inline verinum::V bit4_z2x(verinum::V bit)
|
||||
{ return bit<2? bit : verinum::Vx; /* Relies on V0 and V1 being <2 */}
|
||||
|
||||
extern verinum::V operator ~ (verinum::V l);
|
||||
extern verinum::V operator | (verinum::V l, verinum::V r);
|
||||
extern verinum::V operator & (verinum::V l, verinum::V r);
|
||||
|
||||
+24
-4
@@ -46,7 +46,7 @@ CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. -I$(srcdir) -I.. @file64_support@
|
||||
CFLAGS = -Wall @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep system.vpi $(ALL32)
|
||||
all: dep system.vpi va_math.vpi $(ALL32)
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
@@ -55,8 +55,9 @@ dep:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
# Object files for system.vpi
|
||||
O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \
|
||||
sys_finish.o sys_plusargs.o sys_random.o sys_random_mti.o \
|
||||
sys_finish.o sys_icarus.o sys_plusargs.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 priv.o sdf_lexor.o sdf_parse.o stringheap.o
|
||||
@@ -68,10 +69,15 @@ endif
|
||||
O += sys_lxt2.o lxt2_write.o
|
||||
endif
|
||||
|
||||
# Object files for va_math.vpi
|
||||
V = va_math.o
|
||||
|
||||
LIBS = @LIBS@
|
||||
SYSTEM_VPI_LDFLAGS = $(LIBS)
|
||||
VA_MATH_LDFLAGS =
|
||||
ifeq (@MING32@,yes)
|
||||
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
||||
VA_MATH_LDFLAGS += @EXTRALIBS@
|
||||
endif
|
||||
|
||||
system.vpi: $O ../vvp/libvpi.a
|
||||
@@ -88,8 +94,11 @@ sdf_lexor.c: sdf_lexor.lex
|
||||
sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y
|
||||
$(YACC) --verbose -d -p sdf -o sdf_parse.c $(srcdir)/sdf_parse.y
|
||||
|
||||
va_math.vpi: $V ../vvp/libvpi.a
|
||||
$(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf *.o sys_readmem_lex.c dep system.vpi bin32
|
||||
rm -rf *.o sys_readmem_lex.c dep system.vpi va_math.vpi bin32
|
||||
rm -f sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h
|
||||
|
||||
distclean: clean
|
||||
@@ -97,7 +106,10 @@ distclean: clean
|
||||
|
||||
check: all
|
||||
|
||||
install: all installdirs $(vpidir)/system.vpi $(libdir)/ivl/system.sft
|
||||
install: all installdirs \
|
||||
$(vpidir)/system.vpi $(libdir)/ivl/system.sft \
|
||||
$(vpidir)/va_math.vpi $(libdir)/ivl/va_math.sft \
|
||||
$(vpidir)/include/
|
||||
|
||||
$(vpidir)/system.vpi: ./system.vpi
|
||||
$(INSTALL_PROGRAM) ./system.vpi $(vpidir)/system.vpi
|
||||
@@ -105,12 +117,20 @@ $(vpidir)/system.vpi: ./system.vpi
|
||||
$(libdir)/ivl/system.sft: system.sft
|
||||
$(INSTALL_DATA) $< $@
|
||||
|
||||
$(vpidir)/va_math.vpi: ./va_math.vpi
|
||||
$(INSTALL_PROGRAM) ./va_math.vpi $(vpidir)/va_math.vpi
|
||||
|
||||
$(libdir)/ivl/va_math.sft: va_math.sft
|
||||
$(INSTALL_DATA) $< $@
|
||||
|
||||
installdirs: ../mkinstalldirs
|
||||
$(srcdir)/../mkinstalldirs $(vpidir)
|
||||
|
||||
uninstall:
|
||||
rm -f $(vpidir)/system.vpi
|
||||
rm -f $(libdir)/ivl/system.sft
|
||||
rm -f $(vpidir)/va_math.vpi
|
||||
rm -f $(libdir)/ivl/va_math.sft
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
||||
+2
-12
@@ -45,18 +45,8 @@ AC_CHECK_LIB(bz2, BZ2_bzdopen, HAVE_LIBBZ2=yes, HAVE_LIBBZ2=no)
|
||||
fi
|
||||
AC_SUBST(HAVE_LIBBZ2)
|
||||
|
||||
# --
|
||||
# Look for a dl library to use. First look for the standard dlopen
|
||||
# functions, and failing that look for the HP specific shl_load function.
|
||||
|
||||
AC_CHECK_HEADERS(dlfcn.h dl.h, break)
|
||||
|
||||
DLLIB=''
|
||||
AC_CHECK_LIB(dl,dlopen,[DLLIB=-ldl])
|
||||
if test -z "$DLLIB" ; then
|
||||
AC_CHECK_LIB(dld,shl_load,[DLLIB=-ldld])
|
||||
fi
|
||||
AC_SUBST(DLLIB)
|
||||
# fmin and fmax are needed by va_math.vpi
|
||||
AC_CHECK_FUNCS(fmin fmax)
|
||||
|
||||
AC_PROG_INSTALL
|
||||
|
||||
|
||||
@@ -1122,6 +1122,7 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
|
||||
case vpiReg:
|
||||
case vpiIntegerVar:
|
||||
case vpiRealVar:
|
||||
case vpiMemoryWord:
|
||||
/* Monitoring reg and net values involves setting
|
||||
a callback for value changes. Pass the storage
|
||||
pointer for the callback itself as user_data so
|
||||
|
||||
+31
-16
@@ -480,23 +480,40 @@ static PLI_INT32 sys_ungetc_compiletf(PLI_BYTE8*name)
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
|
||||
if (item == 0) {
|
||||
vpi_printf("%s: mcd parameter missing.\n", name);
|
||||
vpi_printf("%s: character parameter missing.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
type = vpi_get(vpiType, item);
|
||||
switch (type) {
|
||||
case vpiReg:
|
||||
case vpiRealVal:
|
||||
case vpiRealVal: // Is this correct?
|
||||
case vpiIntegerVar:
|
||||
break;
|
||||
default:
|
||||
vpi_printf("ERROR: %s mcd parameter must be of integral", name);
|
||||
vpi_printf(", got vpiType=%d\n", type);
|
||||
vpi_printf("ERROR: %s character parameter must be ", name);
|
||||
vpi_printf("integral, got vpiType=%d\n", type);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = vpi_scan(argv);
|
||||
type = vpi_get(vpiType, item);
|
||||
switch (type) {
|
||||
case vpiReg:
|
||||
case vpiRealVal: // Is this correct?
|
||||
case vpiIntegerVar:
|
||||
break;
|
||||
default:
|
||||
vpi_printf("ERROR: %s mcd parameter must be integral, ", name);
|
||||
vpi_printf("got vpiType=%d\n", type);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* That should be all the arguments. */
|
||||
item = vpi_scan(argv);
|
||||
assert(item == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -504,7 +521,7 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
unsigned int mcd;
|
||||
unsigned char x;
|
||||
s_vpi_value value, xvalue, rval;
|
||||
s_vpi_value val, rval;
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
@@ -512,11 +529,15 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
||||
|
||||
rval.format = vpiIntVal;
|
||||
|
||||
assert(item);
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(item, &val);
|
||||
x = val.value.integer;
|
||||
|
||||
value.format = vpiIntVal;
|
||||
vpi_get_value(item, &value);
|
||||
mcd = value.value.integer;
|
||||
item = vpi_scan(argv);
|
||||
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(item, &val);
|
||||
mcd = val.value.integer;
|
||||
|
||||
if (IS_MCD(mcd)) {
|
||||
rval.value.integer = EOF;
|
||||
@@ -524,12 +545,6 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = vpi_scan(argv);
|
||||
|
||||
xvalue.format = vpiIntVal;
|
||||
vpi_get_value(item, &xvalue);
|
||||
x = xvalue.value.integer;
|
||||
|
||||
fp = vpi_get_file(mcd);
|
||||
if ( !fp ) {
|
||||
rval.value.integer = EOF;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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
|
||||
* 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 "vpi_config.h"
|
||||
#include <assert.h>
|
||||
#include <vpi_user.h>
|
||||
|
||||
|
||||
/*
|
||||
* Routine to return the width in bits of a CPU word (long).
|
||||
*/
|
||||
static PLI_INT32 vvp_cpu_wordsize_calltf(PLI_BYTE8* ud)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
s_vpi_value val;
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
/* Calculate the result */
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = 8*sizeof(long);
|
||||
|
||||
/* Return the result */
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 size_32(PLI_BYTE8* ud)
|
||||
{
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the function with Verilog.
|
||||
*/
|
||||
void sys_special_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
/* Register the single argument functions. */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.calltf = vvp_cpu_wordsize_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = size_32;
|
||||
tf_data.tfname = "$vvp_cpu_wordsize";
|
||||
tf_data.user_data = 0;
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
+1
-9
@@ -109,7 +109,6 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
|
||||
FILE*file;
|
||||
unsigned addr;
|
||||
s_vpi_value value;
|
||||
vpiHandle words;
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item = vpi_scan(argv);
|
||||
@@ -283,11 +282,7 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
words = vpi_iterate(vpiMemoryWord, mitem);
|
||||
assert(words);
|
||||
|
||||
item = vpi_scan(words);
|
||||
item = vpi_handle_by_index(mitem,min_addr);
|
||||
wwid = vpi_get(vpiSize, item);
|
||||
|
||||
/* variable that will be uses by the lexer to pass values
|
||||
@@ -347,9 +342,6 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
|
||||
|
||||
bailout:
|
||||
free(value.value.vector);
|
||||
|
||||
if (item)
|
||||
vpi_free_object(words);
|
||||
free(path);
|
||||
fclose(file);
|
||||
return 0;
|
||||
|
||||
+3
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -16,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_table.c,v 1.26 2006/08/03 05:06:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
# include "vpi_user.h"
|
||||
@@ -40,6 +37,7 @@ 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();
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
#ifdef HAVE_LIBBZ2
|
||||
@@ -181,6 +179,6 @@ void (*vlog_startup_routines[])() = {
|
||||
sys_time_register,
|
||||
sys_lxt_or_vcd_register,
|
||||
sys_sdf_register,
|
||||
sys_special_register,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
@@ -14,3 +14,4 @@ $dist_poisson vpiSysFuncInt
|
||||
$dist_chi_square vpiSysFuncInt
|
||||
$dist_t vpiSysFuncInt
|
||||
$dist_erlang vpiSysFuncInt
|
||||
$vvp_cpu_wordsize vpiSysFuncInt
|
||||
|
||||
+372
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Verilog-A math library for Icarus Verilog
|
||||
* http://www.icarus.com/eda/verilog/
|
||||
*
|
||||
* Copyright (C) 2007-2008 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
|
||||
* 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 "vpi_config.h"
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <vpi_user.h>
|
||||
|
||||
/*
|
||||
* Compile time options: (set in the Makefile.)
|
||||
*
|
||||
* The functions fmax() and fmin() may not be available in pre-c99
|
||||
* libraries, so if they are not available you need to uncomment the
|
||||
* -DUSE_MY_FMAX_AND_FMIN in the Makefile.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* These are functionally equivalent fmax() and fmin() implementations
|
||||
* that can be used when needed.
|
||||
*/
|
||||
#ifndef HAVE_FMIN
|
||||
static double va_fmin(const double x, const double y)
|
||||
{
|
||||
if (x != x) {return y;} /* x is NaN so return y. */
|
||||
if (y != y) {return x;} /* y is NaN so return x. */
|
||||
|
||||
return (x < y) ? x : y;
|
||||
}
|
||||
#endif
|
||||
#ifndef HAVE_FMAX
|
||||
static double va_fmax(const double x, const double y)
|
||||
{
|
||||
if (x != x) {return y;} /* x is NaN so return y. */
|
||||
if (y != y) {return x;} /* y is NaN so return x. */
|
||||
|
||||
return (x > y) ? x : y;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Single argument functions. */
|
||||
typedef struct s_single_data {
|
||||
const char *name;
|
||||
double (*func)(double);
|
||||
} t_single_data;
|
||||
|
||||
static t_single_data va_single_data[]= {
|
||||
{"$sqrt", sqrt},
|
||||
{"$ln", log},
|
||||
{"$log", log10}, /* FIXME: The $log function is replaced by the
|
||||
$log10 function to eliminate confusion with
|
||||
the natural log. In C, "log" is ln and log10
|
||||
is log-base-10. The $log is being left in for
|
||||
compatibility. */
|
||||
{"$log10", log10},
|
||||
{"$exp", exp},
|
||||
{"$abs", fabs},
|
||||
{"$ceil", ceil},
|
||||
{"$floor", floor},
|
||||
{"$sin", sin},
|
||||
{"$cos", cos},
|
||||
{"$tan", tan},
|
||||
{"$asin", asin},
|
||||
{"$acos", acos},
|
||||
{"$atan", atan},
|
||||
{"$sinh", sinh},
|
||||
{"$cosh", cosh},
|
||||
{"$tanh", tanh},
|
||||
{"$asinh", asinh},
|
||||
{"$acosh", acosh},
|
||||
{"$atanh", atanh},
|
||||
{0, 0} /* Must be NULL terminated! */
|
||||
};
|
||||
|
||||
|
||||
/* Double argument functions. */
|
||||
typedef struct s_double_data {
|
||||
const char *name;
|
||||
double (*func)(double, double);
|
||||
} t_double_data;
|
||||
|
||||
static t_double_data va_double_data[]= {
|
||||
#ifdef HAVE_FMAX
|
||||
{"$max", fmax},
|
||||
#else
|
||||
{"$max", va_fmax},
|
||||
#endif
|
||||
#ifdef HAVE_FMIN
|
||||
{"$min", fmin},
|
||||
#else
|
||||
{"$min", va_fmin},
|
||||
#endif
|
||||
{"$pow", pow},
|
||||
{"$atan2", atan2},
|
||||
{"$hypot", hypot},
|
||||
{0, 0} /* Must be NULL terminated! */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This structure holds the single argument information.
|
||||
*/
|
||||
typedef struct {
|
||||
vpiHandle arg;
|
||||
double (*func)(double);
|
||||
} va_single_t;
|
||||
|
||||
|
||||
/*
|
||||
* This structure holds the double argument information.
|
||||
*/
|
||||
typedef struct {
|
||||
vpiHandle arg1;
|
||||
vpiHandle arg2;
|
||||
double (*func)(double, double);
|
||||
} va_double_t;
|
||||
|
||||
|
||||
/*
|
||||
* Standard error message routine. The format string must take one
|
||||
* string argument (the name of the function).
|
||||
*/
|
||||
static void va_error_message(vpiHandle callh, const char* format,
|
||||
const char* name) {
|
||||
vpi_printf("%s:%d: error: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf(format, name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process an argument.
|
||||
*/
|
||||
vpiHandle va_process_argument(vpiHandle callh, const char* name,
|
||||
vpiHandle arg, const char* post) {
|
||||
PLI_INT32 type;
|
||||
|
||||
if (arg == NULL) return 0;
|
||||
type = vpi_get(vpiType, arg);
|
||||
/* Math function cannot do anything with a string. */
|
||||
if ((type == vpiConstant || type == vpiParameter) &&
|
||||
(vpi_get(vpiConstType, arg) == vpiStringConst)) {
|
||||
const char* basemsg = "%s cannot process strings";
|
||||
char* msg = malloc(strlen(basemsg)+strlen(post)+3);
|
||||
strcpy(msg, basemsg);
|
||||
strcat(msg, post);
|
||||
strcat(msg, ".\n");
|
||||
va_error_message(callh, msg, name);
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to check all the single argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_single_argument_compiletf(PLI_BYTE8* ud)
|
||||
{
|
||||
assert(ud != 0);
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
t_single_data *data = (t_single_data *) ud;
|
||||
const char *name = data->name;
|
||||
|
||||
va_single_t* fun_data = malloc(sizeof(va_single_t));
|
||||
|
||||
/* Check that malloc gave use some memory. */
|
||||
if (fun_data == 0) {
|
||||
va_error_message(callh, "%s failed to allocate memory.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that there are arguments. */
|
||||
if (argv == 0) {
|
||||
va_error_message(callh, "%s requires one argument.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In Icarus if we have an argv we have at least one argument. */
|
||||
arg = vpi_scan(argv);
|
||||
fun_data->arg = va_process_argument(callh, name, arg, "");
|
||||
|
||||
/* These functions only take one argument. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
va_error_message(callh, "%s takes only one argument.\n", name);
|
||||
}
|
||||
|
||||
/* Get the function that is to be used by the calltf routine. */
|
||||
fun_data->func = data->func;
|
||||
|
||||
vpi_put_userdata(callh, fun_data);
|
||||
|
||||
/* vpi_scan() returning 0 (NULL) has already freed argv. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to implement the single argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_single_argument_calltf(PLI_BYTE8* ud)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
s_vpi_value val;
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
/* Retrieve the function and argument data. */
|
||||
va_single_t* fun_data = vpi_get_userdata(callh);
|
||||
|
||||
/* Calculate the result */
|
||||
val.format = vpiRealVal;
|
||||
vpi_get_value(fun_data->arg, &val);
|
||||
val.value.real = (fun_data->func)(val.value.real);
|
||||
|
||||
/* Return the result */
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to check all the double argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_double_argument_compiletf(PLI_BYTE8* ud)
|
||||
{
|
||||
assert(ud != 0);
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
t_double_data *data = (t_double_data *) ud;
|
||||
const char *name = data->name;
|
||||
|
||||
va_double_t* fun_data = malloc(sizeof(va_double_t));
|
||||
|
||||
/* Check that malloc gave use some memory. */
|
||||
if (fun_data == 0) {
|
||||
va_error_message(callh, "%s failed to allocate memory.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that there are arguments. */
|
||||
if (argv == 0) {
|
||||
va_error_message(callh, "%s requires two arguments.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In Icarus if we have an argv we have at least one argument. */
|
||||
arg = vpi_scan(argv);
|
||||
fun_data->arg1 = va_process_argument(callh, name, arg, " (arg1)");
|
||||
|
||||
/* Check that there are at least two arguments. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg == 0) {
|
||||
va_error_message(callh, "%s requires two arguments.\n", name);
|
||||
}
|
||||
fun_data->arg2 = va_process_argument(callh, name, arg, " (arg2)");
|
||||
|
||||
/* These functions only take two arguments. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
va_error_message(callh, "%s takes only two arguments.\n", name);
|
||||
}
|
||||
|
||||
/* Get the function that is to be used by the calltf routine. */
|
||||
fun_data->func = data->func;
|
||||
|
||||
vpi_put_userdata(callh, fun_data);
|
||||
|
||||
/* vpi_scan() returning 0 (NULL) has already freed argv. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to implement the double argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_double_argument_calltf(PLI_BYTE8 *ud)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
s_vpi_value val;
|
||||
double first_arg;
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
/* Retrieve the function and argument data. */
|
||||
va_double_t* fun_data = vpi_get_userdata(callh);
|
||||
|
||||
/* Calculate the result */
|
||||
val.format = vpiRealVal;
|
||||
vpi_get_value(fun_data->arg1, &val);
|
||||
first_arg = val.value.real;
|
||||
vpi_get_value(fun_data->arg2, &val);
|
||||
val.value.real = (fun_data->func)(first_arg, val.value.real);
|
||||
|
||||
/* Return the result */
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Register all the functions with Verilog.
|
||||
*/
|
||||
static void va_math_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
unsigned idx;
|
||||
|
||||
/* Register the single argument functions. */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.calltf = va_single_argument_calltf;
|
||||
tf_data.compiletf = va_single_argument_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
|
||||
for (idx=0; va_single_data[idx].name != 0; idx++) {
|
||||
tf_data.tfname = va_single_data[idx].name;
|
||||
tf_data.user_data = (PLI_BYTE8 *) &va_single_data[idx];
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/* Register the double argument functions. */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.calltf = va_double_argument_calltf;
|
||||
tf_data.compiletf = va_double_argument_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
|
||||
for (idx=0; va_double_data[idx].name != 0; idx++) {
|
||||
tf_data.tfname = va_double_data[idx].name;
|
||||
tf_data.user_data = (PLI_BYTE8 *) &va_double_data[idx];
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Hook to get Icarus Verilog to find the registration function.
|
||||
*/
|
||||
void (*vlog_startup_routines[])(void) = {
|
||||
va_math_register,
|
||||
0
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# This is the system function descriptor table for the
|
||||
# Verilog-A math functions.
|
||||
#
|
||||
|
||||
# Single argument functions.
|
||||
$sqrt vpiSysFuncReal
|
||||
$ln vpiSysFuncReal
|
||||
$log vpiSysFuncReal
|
||||
$log10 vpiSysFuncReal
|
||||
$exp vpiSysFuncReal
|
||||
$abs vpiSysFuncReal
|
||||
$ceil vpiSysFuncReal
|
||||
$floor vpiSysFuncReal
|
||||
$sin vpiSysFuncReal
|
||||
$cos vpiSysFuncReal
|
||||
$tan vpiSysFuncReal
|
||||
$asin vpiSysFuncReal
|
||||
$acos vpiSysFuncReal
|
||||
$atan vpiSysFuncReal
|
||||
$sinh vpiSysFuncReal
|
||||
$cosh vpiSysFuncReal
|
||||
$tanh vpiSysFuncReal
|
||||
$asinh vpiSysFuncReal
|
||||
$acosh vpiSysFuncReal
|
||||
$atanh vpiSysFuncReal
|
||||
# Double argument functions.
|
||||
$min vpiSysFuncReal
|
||||
$max vpiSysFuncReal
|
||||
$pow vpiSysFuncReal
|
||||
$atan2 vpiSysFuncReal
|
||||
$hypot vpiSysFuncReal
|
||||
+4
-16
@@ -1,7 +1,7 @@
|
||||
#ifndef __vpi_config_H
|
||||
#define __config_H
|
||||
#define __vpi_config_H
|
||||
/*
|
||||
* Copyright (c) 2004 Stephen Williams ([email protected])
|
||||
* Copyright (c) 2004-2008 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -18,16 +18,13 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: vpi_config.h.in,v 1.2 2004/01/26 21:52:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
# undef HAVE_LIBIBERTY_H
|
||||
# undef HAVE_MALLOC_H
|
||||
# undef HAVE_DLFCN_H
|
||||
# undef HAVE_DL_H
|
||||
# undef HAVE_LIBZ
|
||||
# undef HAVE_LIBBZ2
|
||||
# undef HAVE_FMIN
|
||||
# undef HAVE_FMAX
|
||||
# undef WORDS_BIGENDIAN
|
||||
|
||||
# undef _LARGEFILE_SOURCE
|
||||
@@ -35,13 +32,4 @@
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $Log: vpi_config.h.in,v $
|
||||
* Revision 1.2 2004/01/26 21:52:46 steve
|
||||
* Make sure file64 support is on cc -D flags.
|
||||
*
|
||||
* Revision 1.1 2004/01/21 01:22:53 steve
|
||||
* Give the vip directory its own configure and vpi_config.h
|
||||
*
|
||||
*/
|
||||
#endif // __config_H
|
||||
|
||||
@@ -312,6 +312,8 @@ typedef struct t_vpi_delay {
|
||||
#define vpiDefName 9
|
||||
#define vpiTimeUnit 11
|
||||
#define vpiTimePrecision 12
|
||||
#define vpiDefFile 15
|
||||
#define vpiDefLineNo 16
|
||||
#define vpiNetType 22
|
||||
# define vpiWire 1
|
||||
#define vpiArray 28
|
||||
|
||||
+2
-2
@@ -70,14 +70,14 @@ check: all
|
||||
|
||||
V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \
|
||||
vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \
|
||||
vpi_memory.o vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
|
||||
vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
|
||||
vpip_to_dec.o vpip_format.o vvp_vpi.o
|
||||
|
||||
O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
|
||||
concat.o \
|
||||
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
|
||||
ufunc.o codes.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o memory.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \
|
||||
event.o logic.o delay.o words.o $V
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
|
||||
@@ -55,6 +55,41 @@ void vvp_arith_::dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit)
|
||||
}
|
||||
|
||||
|
||||
vvp_arith_abs::vvp_arith_abs()
|
||||
{
|
||||
}
|
||||
|
||||
vvp_arith_abs::~vvp_arith_abs()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_arith_abs::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
{
|
||||
vvp_vector4_t out (bit.size(), BIT4_0);;
|
||||
|
||||
vvp_bit4_t cmp = compare_gtge_signed(bit, out, BIT4_1);
|
||||
switch (cmp) {
|
||||
case BIT4_1: // bit >= 0
|
||||
out = bit;
|
||||
break;
|
||||
case BIT4_0: // bit < 0
|
||||
out = ~bit;
|
||||
out += 1;
|
||||
break;
|
||||
default: // There's an X.
|
||||
out = vvp_vector4_t(bit.size(), BIT4_X);
|
||||
break;
|
||||
}
|
||||
|
||||
vvp_send_vec4(ptr.ptr()->out, out);
|
||||
}
|
||||
|
||||
void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit)
|
||||
{
|
||||
double out = fabs(bit);
|
||||
vvp_send_real(ptr.ptr()->out, out);
|
||||
}
|
||||
|
||||
// Division
|
||||
|
||||
vvp_arith_div::vvp_arith_div(unsigned wid, bool signed_flag)
|
||||
|
||||
+11
@@ -49,6 +49,17 @@ class vvp_arith_ : public vvp_net_fun_t {
|
||||
vvp_vector4_t x_val_;
|
||||
};
|
||||
|
||||
class vvp_arith_abs : public vvp_net_fun_t {
|
||||
public:
|
||||
explicit vvp_arith_abs();
|
||||
~vvp_arith_abs();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit);
|
||||
void recv_real(vvp_net_ptr_t ptr, double bit);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class vvp_arith_div : public vvp_arith_ {
|
||||
|
||||
public:
|
||||
|
||||
+435
-48
@@ -35,7 +35,7 @@ static symbol_table_t array_table =0;
|
||||
class vvp_fun_arrayport;
|
||||
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
|
||||
|
||||
vvp_array_t array_find(char*label)
|
||||
vvp_array_t array_find(const char*label)
|
||||
{
|
||||
if (array_table == 0)
|
||||
return 0;
|
||||
@@ -55,9 +55,15 @@ struct __vpiArray {
|
||||
unsigned array_count;
|
||||
struct __vpiDecConst first_addr;
|
||||
struct __vpiDecConst last_addr;
|
||||
vpiHandle*words;
|
||||
// If this is a net array, nets lists the handles.
|
||||
vpiHandle*nets;
|
||||
// If this is a var array, then these are used instead of nets.
|
||||
vvp_vector4_t *vals;
|
||||
unsigned vals_width;
|
||||
struct __vpiArrayWord*vals_words;
|
||||
|
||||
class vvp_fun_arrayport*ports_;
|
||||
struct __vpiCallback *vpi_callbacks;
|
||||
};
|
||||
|
||||
struct __vpiArrayIterator {
|
||||
@@ -72,6 +78,36 @@ struct __vpiArrayIndex {
|
||||
unsigned done;
|
||||
};
|
||||
|
||||
struct __vpiArrayVthrA {
|
||||
struct __vpiHandle base;
|
||||
struct __vpiArray*array;
|
||||
unsigned address;
|
||||
};
|
||||
|
||||
/*
|
||||
* The vpiArrayWord is magic. It is used as the handle to return when
|
||||
* vpi code tries to index or scan an array of variable words. The
|
||||
* array word handle contains no actual data. It is just a hook for
|
||||
* the vpi methods and to point to the parent.
|
||||
*
|
||||
* How the point to the parent works is tricky. The vpiArrayWord
|
||||
* objects for an array are themselves allocated as an array. All the
|
||||
* ArrayWord objects in the array have a word0 that points to the base
|
||||
* of the array. Thus, the position into the array (and the index into
|
||||
* the memory) is calculated by subtracting word0 from the ArrayWord
|
||||
* pointer.
|
||||
*
|
||||
* To then get to the parent, use word0[-1].parent.
|
||||
*/
|
||||
struct __vpiArrayWord {
|
||||
struct __vpiHandle base;
|
||||
union {
|
||||
struct __vpiArray*parent;
|
||||
struct __vpiArrayWord*word0;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
static int vpi_array_get(int code, vpiHandle ref);
|
||||
static char*vpi_array_get_str(int code, vpiHandle ref);
|
||||
static vpiHandle vpi_array_get_handle(int code, vpiHandle ref);
|
||||
@@ -84,6 +120,14 @@ static int array_iterator_free_object(vpiHandle ref);
|
||||
static vpiHandle array_index_scan(vpiHandle ref, int);
|
||||
static int array_index_free_object(vpiHandle ref);
|
||||
|
||||
static int vpi_array_var_word_get(int code, vpiHandle);
|
||||
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
|
||||
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
|
||||
|
||||
static int vpi_array_vthr_A_get(int code, vpiHandle);
|
||||
static void vpi_array_vthr_A_get_value(vpiHandle, p_vpi_value);
|
||||
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle, p_vpi_value, int);
|
||||
|
||||
static const struct __vpirt vpip_arraymem_rt = {
|
||||
vpiMemory,
|
||||
vpi_array_get,
|
||||
@@ -122,14 +166,86 @@ static const struct __vpirt vpip_array_index_rt = {
|
||||
array_index_free_object
|
||||
};
|
||||
|
||||
static const struct __vpirt vpip_array_var_word_rt = {
|
||||
vpiMemoryWord,
|
||||
&vpi_array_var_word_get,
|
||||
0,
|
||||
&vpi_array_var_word_get_value,
|
||||
&vpi_array_var_word_put_value,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct __vpirt vpip_array_vthr_A_rt = {
|
||||
vpiMemoryWord,
|
||||
&vpi_array_vthr_A_get,
|
||||
0,
|
||||
&vpi_array_vthr_A_get_value,
|
||||
&vpi_array_vthr_A_put_value,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
# define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \
|
||||
(struct __vpiArray*)ref)
|
||||
|
||||
static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref)
|
||||
{
|
||||
if (ref == 0)
|
||||
return 0;
|
||||
if (ref->vpi_type != &vpip_array_var_word_rt)
|
||||
return 0;
|
||||
|
||||
return (struct __vpiArrayWord*) ref;
|
||||
}
|
||||
|
||||
static struct __vpiArrayVthrA* array_vthr_a_from_handle(vpiHandle ref)
|
||||
{
|
||||
if (ref == 0)
|
||||
return 0;
|
||||
if (ref->vpi_type != &vpip_array_vthr_A_rt)
|
||||
return 0;
|
||||
|
||||
return (struct __vpiArrayVthrA*) ref;
|
||||
}
|
||||
|
||||
static void array_make_vals_words(struct __vpiArray*parent)
|
||||
{
|
||||
assert(parent->vals_words == 0);
|
||||
parent->vals_words = new struct __vpiArrayWord[parent->array_count + 1];
|
||||
|
||||
// Make word[-1] point to the parent.
|
||||
parent->vals_words->parent = parent;
|
||||
// Now point to word-0
|
||||
parent->vals_words += 1;
|
||||
|
||||
struct __vpiArrayWord*words = parent->vals_words;
|
||||
for (unsigned idx = 0 ; idx < parent->array_count ; idx += 1) {
|
||||
words[idx].base.vpi_type = &vpip_array_var_word_rt;
|
||||
words[idx].word0 = words;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned decode_array_word_pointer(struct __vpiArrayWord*word,
|
||||
struct __vpiArray*&parent)
|
||||
{
|
||||
struct __vpiArrayWord*word0 = word->word0;
|
||||
parent = (word0 - 1) -> parent;
|
||||
return word - word0;
|
||||
}
|
||||
|
||||
static int vpi_array_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArray*obj = ARRAY_HANDLE(ref);
|
||||
|
||||
switch (code) {
|
||||
case vpiLineNo:
|
||||
return 0; // Not implemented for now!
|
||||
|
||||
case vpiSize:
|
||||
return (int) obj->array_count;
|
||||
|
||||
@@ -142,6 +258,10 @@ static char*vpi_array_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArray*obj = ARRAY_HANDLE(ref);
|
||||
|
||||
if (code == vpiFile) { // Not implemented for now!
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
}
|
||||
|
||||
return generic_get_str(code, &obj->scope->base, obj->name, NULL);
|
||||
}
|
||||
|
||||
@@ -198,7 +318,56 @@ static vpiHandle vpi_array_index(vpiHandle ref, int index)
|
||||
if (index < 0)
|
||||
return 0;
|
||||
|
||||
return obj->words[index];
|
||||
if (obj->nets != 0) {
|
||||
return obj->nets[index];
|
||||
}
|
||||
|
||||
if (obj->vals_words == 0)
|
||||
array_make_vals_words(obj);
|
||||
|
||||
return &(obj->vals_words[index].base);
|
||||
}
|
||||
|
||||
static int vpi_array_var_word_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||
struct __vpiArray*parent;
|
||||
|
||||
assert(obj);
|
||||
decode_array_word_pointer(obj, parent);
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return (int) parent->vals_width;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
|
||||
{
|
||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||
struct __vpiArray*parent;
|
||||
|
||||
assert(obj);
|
||||
unsigned index = decode_array_word_pointer(obj, parent);
|
||||
|
||||
vpip_vec4_get_value(parent->vals[index], parent->vals_width,
|
||||
false, value);
|
||||
}
|
||||
|
||||
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags)
|
||||
{
|
||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||
struct __vpiArray*parent;
|
||||
|
||||
assert(obj);
|
||||
unsigned index = decode_array_word_pointer(obj, parent);
|
||||
|
||||
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
|
||||
array_set_word(parent, index, 0, val);
|
||||
return ref;
|
||||
}
|
||||
|
||||
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
|
||||
@@ -213,9 +382,18 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int)
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpiHandle res = obj->array->words[obj->next];
|
||||
unsigned use_index = obj->next;
|
||||
obj->next += 1;
|
||||
return res;
|
||||
|
||||
if (obj->array->nets)
|
||||
return obj->array->nets[obj->next];
|
||||
|
||||
assert(obj->array->vals);
|
||||
|
||||
if (obj->array->vals_words == 0)
|
||||
array_make_vals_words(obj->array);
|
||||
|
||||
return &(obj->array->vals_words[use_index].base);
|
||||
}
|
||||
|
||||
static int array_iterator_free_object(vpiHandle ref)
|
||||
@@ -264,6 +442,56 @@ static int array_index_free_object(vpiHandle ref)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vpi_array_vthr_A_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||
assert(obj);
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
switch (code) {
|
||||
case vpiLineNo:
|
||||
return 0; // Not implemented for now!
|
||||
|
||||
case vpiSize:
|
||||
assert(parent->vals);
|
||||
return parent->vals_width;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||
assert(obj);
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
assert(parent);
|
||||
assert(parent->vals);
|
||||
assert(obj->address < parent->array_count);
|
||||
|
||||
vpip_vec4_get_value(parent->vals[obj->address],
|
||||
parent->vals_width, false, value);
|
||||
}
|
||||
|
||||
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||
assert(obj);
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
unsigned index = obj->address;
|
||||
|
||||
assert(parent);
|
||||
assert(obj->address < parent->array_count);
|
||||
|
||||
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
|
||||
array_set_word(parent, index, 0, val);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
void array_set_word(vvp_array_t arr,
|
||||
unsigned address,
|
||||
unsigned part_off,
|
||||
@@ -272,22 +500,61 @@ void array_set_word(vvp_array_t arr,
|
||||
if (address >= arr->array_count)
|
||||
return;
|
||||
|
||||
if (arr->vals) {
|
||||
assert(arr->nets == 0);
|
||||
if (part_off != 0 || val.size() != arr->vals_width) {
|
||||
if (arr->vals[address].size() == 0)
|
||||
arr->vals[address] = vvp_vector4_t(arr->vals_width, BIT4_X);
|
||||
if ((part_off + val.size()) > arr->vals[address].size()) {
|
||||
cerr << "part_off=" << part_off
|
||||
<< " val.size()=" << val.size()
|
||||
<< " arr->vals[address].size()=" << arr->vals[address].size()
|
||||
<< " arr->vals_width=" << arr->vals_width << endl;
|
||||
assert(0);
|
||||
}
|
||||
arr->vals[address].set_vec(part_off, val);
|
||||
} else {
|
||||
arr->vals[address] = val;
|
||||
}
|
||||
array_word_change(arr, address);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(arr->nets != 0);
|
||||
|
||||
// Select the word of the array that we affect.
|
||||
vpiHandle word = arr->words[address];
|
||||
vpiHandle word = arr->nets[address];
|
||||
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
||||
assert(vsig);
|
||||
|
||||
vvp_net_ptr_t ptr (vsig->node, 0);
|
||||
vvp_send_vec4_pv(ptr, val, part_off, val.size(), vpip_size(vsig));
|
||||
array_word_change(arr, address);
|
||||
}
|
||||
|
||||
vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
|
||||
{
|
||||
if (arr->vals) {
|
||||
assert(arr->nets == 0);
|
||||
|
||||
vvp_vector4_t tmp;
|
||||
if (address < arr->array_count)
|
||||
tmp = arr->vals[address];
|
||||
|
||||
if (tmp.size() == 0)
|
||||
tmp = vvp_vector4_t(arr->vals_width, BIT4_X);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
assert(arr->vals == 0);
|
||||
assert(arr->nets != 0);
|
||||
|
||||
if (address >= arr->array_count) {
|
||||
// Reading outside the array. Return X's but get the
|
||||
// width by looking at a word that we know is present.
|
||||
assert(arr->array_count > 0);
|
||||
vpiHandle word = arr->words[0];
|
||||
vpiHandle word = arr->nets[0];
|
||||
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
||||
assert(vsig);
|
||||
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
|
||||
@@ -295,7 +562,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
|
||||
return vvp_vector4_t(sig->size(), BIT4_X);
|
||||
}
|
||||
|
||||
vpiHandle word = arr->words[address];
|
||||
vpiHandle word = arr->nets[address];
|
||||
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
|
||||
assert(vsig);
|
||||
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
|
||||
@@ -325,10 +592,15 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
||||
vpip_make_dec_const(&obj->first_addr, first_addr);
|
||||
vpip_make_dec_const(&obj->last_addr, last_addr);
|
||||
|
||||
obj->words = (vpiHandle*)calloc(array_count, sizeof(vpiHandle));
|
||||
// Start off now knowing if we are nets or variables.
|
||||
obj->nets = 0;
|
||||
obj->vals = 0;
|
||||
obj->vals_width = 0;
|
||||
obj->vals_words = 0;
|
||||
|
||||
// Initialize (clear) the read-ports list.
|
||||
obj->ports_ = 0;
|
||||
obj->vpi_callbacks = 0;
|
||||
|
||||
/* Add this symbol to the array_symbols table for later lookup. */
|
||||
if (!array_table)
|
||||
@@ -339,19 +611,29 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
||||
v.ptr = obj;
|
||||
sym_set_value(array_table, label, v);
|
||||
|
||||
/* Add this into the table of VPI objects. This is used for
|
||||
contexts that try to look up VPI objects in
|
||||
general. (i.e. arguments to vpi_task calls.) */
|
||||
compile_vpi_symbol(label, &(obj->base));
|
||||
|
||||
/* Blindly attach to the scope as an object. */
|
||||
vpip_attach_to_current_scope(&(obj->base));
|
||||
|
||||
return &(obj->base);
|
||||
}
|
||||
|
||||
void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
||||
{
|
||||
assert(addr < array->array_count);
|
||||
array->words[addr] = word;
|
||||
assert(array->nets);
|
||||
array->nets[addr] = word;
|
||||
}
|
||||
|
||||
void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
||||
{
|
||||
assert(addr < array->array_count);
|
||||
array->words[addr] = word;
|
||||
assert(array->nets);
|
||||
array->nets[addr] = word;
|
||||
|
||||
if (struct __vpiSignal*sig = vpip_signal_from_handle(word)) {
|
||||
vvp_net_t*net = sig->node;
|
||||
@@ -364,33 +646,16 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
|
||||
}
|
||||
}
|
||||
|
||||
static vpiHandle common_array_build(char*label, char*name, int last, int first)
|
||||
{
|
||||
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||
/* Add this into the table of VPI objects. This is used for
|
||||
contexts that try to look up VPI objects in
|
||||
general. (i.e. arguments to vpi_task calls.) */
|
||||
compile_vpi_symbol(label, obj);
|
||||
/* Blindly attach to the scope as an object. */
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void compile_var_array(char*label, char*name, int last, int first,
|
||||
int msb, int lsb, char signed_flag)
|
||||
{
|
||||
vpiHandle obj = common_array_build(label, name, last, first);
|
||||
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||
|
||||
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
||||
vvp_array_t array = array_find(label);
|
||||
|
||||
/* Make the words. */
|
||||
for (unsigned idx = 0 ; idx < arr->array_count ; idx += 1) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof buf, "%s_%u", label, idx);
|
||||
compile_variablew(strdup(buf), array, idx, msb, lsb, signed_flag);
|
||||
}
|
||||
arr->vals = new vvp_vector4_t[arr->array_count];
|
||||
arr->vals_width = labs(msb-lsb) + 1;
|
||||
|
||||
free(label);
|
||||
free(name);
|
||||
@@ -399,7 +664,7 @@ void compile_var_array(char*label, char*name, int last, int first,
|
||||
void compile_real_array(char*label, char*name, int last, int first,
|
||||
int msb, int lsb)
|
||||
{
|
||||
vpiHandle obj = common_array_build(label, name, last, first);
|
||||
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||
|
||||
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
||||
vvp_array_t array = array_find(label);
|
||||
@@ -417,7 +682,10 @@ void compile_real_array(char*label, char*name, int last, int first,
|
||||
|
||||
void compile_net_array(char*label, char*name, int last, int first)
|
||||
{
|
||||
/* vpiHandle obj = */ common_array_build(label, name, last, first);
|
||||
vpiHandle obj = vpip_make_array(label, name, first, last);
|
||||
|
||||
struct __vpiArray*arr = ARRAY_HANDLE(obj);
|
||||
arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle));
|
||||
|
||||
free(label);
|
||||
free(name);
|
||||
@@ -427,6 +695,7 @@ class vvp_fun_arrayport : public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net);
|
||||
explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr);
|
||||
~vvp_fun_arrayport();
|
||||
|
||||
void check_word_change(unsigned long addr);
|
||||
@@ -449,6 +718,12 @@ vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net)
|
||||
next_ = 0;
|
||||
}
|
||||
|
||||
vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr)
|
||||
: arr_(mem), net_(net), addr_(addr)
|
||||
{
|
||||
next_ = 0;
|
||||
}
|
||||
|
||||
vvp_fun_arrayport::~vvp_fun_arrayport()
|
||||
{
|
||||
}
|
||||
@@ -492,26 +767,121 @@ void array_word_change(vvp_array_t array, unsigned long addr)
|
||||
{
|
||||
for (vvp_fun_arrayport*cur = array->ports_; cur; cur = cur->next_)
|
||||
cur->check_word_change(addr);
|
||||
|
||||
// Run callbacks attatched to the array itself.
|
||||
struct __vpiCallback *next = array->vpi_callbacks;
|
||||
struct __vpiCallback *prev = 0;
|
||||
|
||||
while (next) {
|
||||
struct __vpiCallback*cur = next;
|
||||
next = cur->next;
|
||||
|
||||
// Skip callbacks for callbacks not for me.
|
||||
if (cur->extra_data != (long)addr) {
|
||||
prev = cur;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur->cb_data.cb_rtn != 0) {
|
||||
if (cur->cb_data.value)
|
||||
vpip_vec4_get_value(array->vals[addr], array->vals_width,
|
||||
false, cur->cb_data.value);
|
||||
|
||||
callback_execute(cur);
|
||||
prev = cur;
|
||||
|
||||
} else if (prev == 0) {
|
||||
|
||||
array->vpi_callbacks = next;
|
||||
cur->next = 0;
|
||||
delete_vpi_callback(cur);
|
||||
|
||||
} else {
|
||||
assert(prev->next == cur);
|
||||
prev->next = next;
|
||||
cur->next = 0;
|
||||
delete_vpi_callback(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class array_port_resolv_list_t : public resolv_list_s {
|
||||
|
||||
public:
|
||||
explicit array_port_resolv_list_t(char*label) : resolv_list_s(label) { }
|
||||
|
||||
vvp_net_t*ptr;
|
||||
bool use_addr;
|
||||
long addr;
|
||||
bool resolve(bool mes);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
bool array_port_resolv_list_t::resolve(bool mes)
|
||||
{
|
||||
vvp_array_t mem = array_find(label());
|
||||
if (mem == 0) {
|
||||
assert(mem || !mes);
|
||||
return false;
|
||||
}
|
||||
|
||||
vvp_fun_arrayport*fun;
|
||||
if (use_addr)
|
||||
fun = new vvp_fun_arrayport(mem, ptr, addr);
|
||||
else
|
||||
fun = new vvp_fun_arrayport(mem, ptr);
|
||||
ptr->fun = fun;
|
||||
|
||||
array_attach_port(mem, fun);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj)
|
||||
{
|
||||
struct __vpiArray*parent = 0;
|
||||
if (struct __vpiArrayWord*word = array_var_word_from_handle(obj)) {
|
||||
unsigned addr = decode_array_word_pointer(word, parent);
|
||||
cb->extra_data = addr;
|
||||
|
||||
} else if (struct __vpiArrayVthrA*word = array_vthr_a_from_handle(obj)) {
|
||||
parent = word->array;
|
||||
cb->extra_data = word->address;
|
||||
}
|
||||
|
||||
assert(parent);
|
||||
cb->next = parent->vpi_callbacks;
|
||||
parent->vpi_callbacks = cb;
|
||||
}
|
||||
|
||||
void compile_array_port(char*label, char*array, char*addr)
|
||||
{
|
||||
vvp_array_t mem = array_find(array);
|
||||
assert(mem);
|
||||
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_fun_arrayport*fun = new vvp_fun_arrayport(mem, ptr);
|
||||
ptr->fun = fun;
|
||||
|
||||
define_functor_symbol(label, ptr);
|
||||
// Connect the port-0 input as the address.
|
||||
input_connect(ptr, 0, addr);
|
||||
|
||||
array_attach_port(mem, fun);
|
||||
array_port_resolv_list_t*resolv_mem
|
||||
= new array_port_resolv_list_t(array);
|
||||
|
||||
resolv_mem->ptr = new vvp_net_t;
|
||||
resolv_mem->use_addr = false;
|
||||
define_functor_symbol(label, resolv_mem->ptr);
|
||||
free(label);
|
||||
free(array);
|
||||
// The input_connect arranges for the array string to be free'ed.
|
||||
// Connect the port-0 input as the address.
|
||||
input_connect(resolv_mem->ptr, 0, addr);
|
||||
|
||||
resolv_submit(resolv_mem);
|
||||
}
|
||||
|
||||
void compile_array_port(char*label, char*array, long addr)
|
||||
{
|
||||
array_port_resolv_list_t*resolv_mem
|
||||
= new array_port_resolv_list_t(array);
|
||||
|
||||
resolv_mem->ptr = new vvp_net_t;
|
||||
resolv_mem->use_addr = true;
|
||||
resolv_mem->addr = addr;
|
||||
define_functor_symbol(label, resolv_mem->ptr);
|
||||
free(label);
|
||||
|
||||
resolv_submit(resolv_mem);
|
||||
}
|
||||
|
||||
void compile_array_alias(char*label, char*name, char*src)
|
||||
@@ -532,7 +902,8 @@ void compile_array_alias(char*label, char*name, char*src)
|
||||
vpip_make_dec_const(&obj->last_addr, mem->last_addr.value);
|
||||
|
||||
// Share the words with the source array.
|
||||
obj->words = mem->words;
|
||||
obj->nets = mem->nets;
|
||||
obj->vals = mem->vals;
|
||||
|
||||
obj->ports_ = 0;
|
||||
|
||||
@@ -549,3 +920,19 @@ void compile_array_alias(char*label, char*name, char*src)
|
||||
free(name);
|
||||
free(src);
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*)
|
||||
malloc(sizeof (struct __vpiArrayVthrA));
|
||||
|
||||
obj->base.vpi_type = &vpip_array_vthr_A_rt;
|
||||
|
||||
obj->array = array_find(label);
|
||||
assert(obj->array);
|
||||
|
||||
obj->address = addr;
|
||||
assert(addr < obj->array->array_count);
|
||||
|
||||
return &(obj->base);
|
||||
}
|
||||
|
||||
+6
-1
@@ -28,7 +28,7 @@ typedef struct __vpiArray* vvp_array_t;
|
||||
* This function tries to find the array (by label) in the global
|
||||
* table of all the arrays in the design.
|
||||
*/
|
||||
extern vvp_array_t array_find(char*label);
|
||||
extern vvp_array_t array_find(const char*label);
|
||||
extern vpiHandle array_index_iterate(int code, vpiHandle ref);
|
||||
|
||||
extern void array_word_change(vvp_array_t array, unsigned long addr);
|
||||
@@ -45,6 +45,11 @@ extern void array_set_word(vvp_array_t arr,
|
||||
|
||||
extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned adddress);
|
||||
|
||||
/* VPI hooks */
|
||||
|
||||
extern void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle word);
|
||||
|
||||
/* Compile hooks */
|
||||
extern void compile_variablew(char*label, vvp_array_t array,
|
||||
unsigned long array_addr,
|
||||
int msb, int lsb, char signed_flag);
|
||||
|
||||
+1
-3
@@ -32,6 +32,7 @@ typedef bool (*vvp_code_fun)(vthread_t thr, vvp_code_t code);
|
||||
* implementation lives in the vthread.cc file so that they have
|
||||
* access to the thread context.
|
||||
*/
|
||||
extern bool of_ABS_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ADD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ADD_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ADDI(vthread_t thr, vvp_code_t code);
|
||||
@@ -96,7 +97,6 @@ extern bool of_JOIN(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_MV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_NX(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code);
|
||||
@@ -126,7 +126,6 @@ extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_MV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
|
||||
@@ -161,7 +160,6 @@ struct vvp_code_s {
|
||||
unsigned long number;
|
||||
vvp_net_t *net;
|
||||
vvp_code_t cptr;
|
||||
vvp_memory_t mem;
|
||||
vvp_array_t array;
|
||||
struct __vpiHandle*handle;
|
||||
struct __vpiScope*scope;
|
||||
|
||||
+69
-198
@@ -22,7 +22,6 @@
|
||||
# include "logic.h"
|
||||
# include "resolv.h"
|
||||
# include "udp.h"
|
||||
# include "memory.h"
|
||||
# include "symbols.h"
|
||||
# include "codes.h"
|
||||
# include "schedule.h"
|
||||
@@ -67,8 +66,6 @@ enum operand_e {
|
||||
OA_FUNC_PTR,
|
||||
/* The operand is a second functor pointer */
|
||||
OA_FUNC_PTR2,
|
||||
/* The operand is a pointer to a memory */
|
||||
OA_MEM_PTR,
|
||||
/* The operand is a VPI handle */
|
||||
OA_VPI_PTR,
|
||||
};
|
||||
@@ -82,6 +79,7 @@ struct opcode_table_s {
|
||||
};
|
||||
|
||||
const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%abs/wr", of_ABS_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%add", of_ADD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%add/wr", of_ADD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%addi", of_ADDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
@@ -89,7 +87,6 @@ const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/mv",of_ASSIGN_MV,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
@@ -143,7 +140,6 @@ const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/mv",of_LOAD_MV,3, {OA_BIT1, OA_MEM_PTR, OA_BIT2} },
|
||||
{ "%load/nx",of_LOAD_NX,3, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
|
||||
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
@@ -173,7 +169,6 @@ const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/mv", of_SET_MV, 3, {OA_MEM_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/wr", of_SET_WORDR,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
@@ -320,13 +315,12 @@ vvp_net_t* vvp_net_lookup(const char*label)
|
||||
*/
|
||||
static struct resolv_list_s*resolv_list = 0;
|
||||
|
||||
struct resolv_list_s {
|
||||
virtual ~resolv_list_s() { }
|
||||
struct resolv_list_s*next;
|
||||
virtual bool resolve(bool mes = false) = 0;
|
||||
};
|
||||
resolv_list_s::~resolv_list_s()
|
||||
{
|
||||
free(label_);
|
||||
}
|
||||
|
||||
static void resolv_submit(struct resolv_list_s*cur)
|
||||
void resolv_submit(struct resolv_list_s*cur)
|
||||
{
|
||||
if (cur->resolve()) {
|
||||
delete cur;
|
||||
@@ -345,8 +339,8 @@ static void resolv_submit(struct resolv_list_s*cur)
|
||||
* put net->port[port] into the fan-out list for that node.
|
||||
*/
|
||||
struct vvp_net_resolv_list_s: public resolv_list_s {
|
||||
// node to locate
|
||||
char*source;
|
||||
|
||||
vvp_net_resolv_list_s(char*l) : resolv_list_s(l) { }
|
||||
// port to be driven by the located node.
|
||||
vvp_net_ptr_t port;
|
||||
virtual bool resolve(bool mes);
|
||||
@@ -354,20 +348,18 @@ struct vvp_net_resolv_list_s: public resolv_list_s {
|
||||
|
||||
bool vvp_net_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
vvp_net_t*tmp = vvp_net_lookup(source);
|
||||
vvp_net_t*tmp = vvp_net_lookup(label());
|
||||
|
||||
if (tmp) {
|
||||
// Link the input port to the located output.
|
||||
vvp_net_t*net = port.ptr();
|
||||
net->port[port.port()] = tmp->out;
|
||||
tmp->out = port;
|
||||
|
||||
free(source);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "unresolved vvp_net reference: %s\n", source);
|
||||
fprintf(stderr, "unresolved vvp_net reference: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -375,10 +367,8 @@ bool vvp_net_resolv_list_s::resolve(bool mes)
|
||||
inline static
|
||||
void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
||||
{
|
||||
struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s;
|
||||
|
||||
struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s(lab);
|
||||
res->port = port;
|
||||
res->source = lab;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
@@ -389,24 +379,22 @@ void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
||||
*/
|
||||
|
||||
struct functor_gen_resolv_list_s: public resolv_list_s {
|
||||
char*source;
|
||||
explicit functor_gen_resolv_list_s(char*txt) : resolv_list_s(txt) { }
|
||||
vvp_net_t**ref;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool functor_gen_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
vvp_net_t*tmp = vvp_net_lookup(source);
|
||||
vvp_net_t*tmp = vvp_net_lookup(label());
|
||||
|
||||
if (tmp) {
|
||||
*ref = tmp;
|
||||
|
||||
free(source);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "unresolved functor reference: %s\n", source);
|
||||
fprintf(stderr, "unresolved functor reference: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -414,10 +402,9 @@ bool functor_gen_resolv_list_s::resolve(bool mes)
|
||||
void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
||||
{
|
||||
struct functor_gen_resolv_list_s*res =
|
||||
new struct functor_gen_resolv_list_s;
|
||||
new struct functor_gen_resolv_list_s(lab);
|
||||
|
||||
res->ref = ref;
|
||||
res->source = lab;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
@@ -427,27 +414,27 @@ void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
||||
*/
|
||||
|
||||
struct vpi_handle_resolv_list_s: public resolv_list_s {
|
||||
vpiHandle *handle;
|
||||
char *label;
|
||||
explicit vpi_handle_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
virtual bool resolve(bool mes);
|
||||
vpiHandle *handle;
|
||||
};
|
||||
|
||||
bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
symbol_value_t val = sym_get_value(sym_vpi, label);
|
||||
symbol_value_t val = sym_get_value(sym_vpi, label());
|
||||
if (!val.ptr) {
|
||||
// check for thread vector T<base,wid>
|
||||
unsigned base, wid;
|
||||
unsigned n = 0;
|
||||
char ss[32];
|
||||
if (2 <= sscanf(label, "T<%u,%u>%n", &base, &wid, &n)
|
||||
&& n == strlen(label)) {
|
||||
if (2 <= sscanf(label(), "T<%u,%u>%n", &base, &wid, &n)
|
||||
&& n == strlen(label())) {
|
||||
val.ptr = vpip_make_vthr_vector(base, wid, false);
|
||||
sym_set_value(sym_vpi, label, val);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (3 <= sscanf(label, "T<%u,%u,%[su]>%n", &base,
|
||||
} else if (3 <= sscanf(label(), "T<%u,%u,%[su]>%n", &base,
|
||||
&wid, ss, &n)
|
||||
&& n == strlen(label)) {
|
||||
&& n == strlen(label())) {
|
||||
|
||||
bool signed_flag = false;
|
||||
for (char*fp = ss ; *fp ; fp += 1) switch (*fp) {
|
||||
@@ -462,13 +449,13 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||
}
|
||||
|
||||
val.ptr = vpip_make_vthr_vector(base, wid, signed_flag);
|
||||
sym_set_value(sym_vpi, label, val);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (2 == sscanf(label, "W<%u,%[r]>%n", &base, ss, &n)
|
||||
&& n == strlen(label)) {
|
||||
} else if (2 == sscanf(label(), "W<%u,%[r]>%n", &base, ss, &n)
|
||||
&& n == strlen(label())) {
|
||||
|
||||
val.ptr = vpip_make_vthr_word(base, ss);
|
||||
sym_set_value(sym_vpi, label, val);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -479,12 +466,11 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||
|
||||
if (val.ptr) {
|
||||
*handle = (vpiHandle) val.ptr;
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "unresolved vpi name lookup: %s\n", label);
|
||||
fprintf(stderr, "unresolved vpi name lookup: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -516,10 +502,9 @@ void compile_vpi_lookup(vpiHandle *handle, char*label)
|
||||
}
|
||||
|
||||
struct vpi_handle_resolv_list_s*res
|
||||
= new struct vpi_handle_resolv_list_s;
|
||||
= new struct vpi_handle_resolv_list_s(label);
|
||||
|
||||
res->handle = handle;
|
||||
res->label = label;
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
||||
@@ -528,27 +513,24 @@ void compile_vpi_lookup(vpiHandle *handle, char*label)
|
||||
*/
|
||||
|
||||
struct code_label_resolv_list_s: public resolv_list_s {
|
||||
code_label_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
struct vvp_code_s *code;
|
||||
char *label;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool code_label_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
symbol_value_t val = sym_get_value(sym_codespace, label);
|
||||
symbol_value_t val = sym_get_value(sym_codespace, label());
|
||||
if (val.num) {
|
||||
if (code->opcode == of_FORK)
|
||||
code->cptr2 = reinterpret_cast<vvp_code_t>(val.ptr);
|
||||
else
|
||||
code->cptr = reinterpret_cast<vvp_code_t>(val.ptr);
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr,
|
||||
"unresolved code label: %s\n",
|
||||
label);
|
||||
fprintf(stderr, "unresolved code label: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -556,75 +538,38 @@ bool code_label_resolv_list_s::resolve(bool mes)
|
||||
void code_label_lookup(struct vvp_code_s *code, char *label)
|
||||
{
|
||||
struct code_label_resolv_list_s *res
|
||||
= new struct code_label_resolv_list_s;
|
||||
= new struct code_label_resolv_list_s(label);
|
||||
|
||||
res->code = code;
|
||||
res->label = label;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup memories.
|
||||
*/
|
||||
struct memory_resolv_list_s: public resolv_list_s {
|
||||
struct code_array_resolv_list_s: public resolv_list_s {
|
||||
code_array_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
struct vvp_code_s *code;
|
||||
char *label;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool memory_resolv_list_s::resolve(bool mes)
|
||||
bool code_array_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
code->mem = memory_find(label);
|
||||
if (code->mem != 0) {
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "Memory unresolved: %s\n", label);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void compile_mem_lookup(struct vvp_code_s *code, char *label)
|
||||
{
|
||||
struct memory_resolv_list_s *res
|
||||
= new struct memory_resolv_list_s;
|
||||
|
||||
res->code = code;
|
||||
res->label = label;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
||||
struct array_resolv_list_s: public resolv_list_s {
|
||||
struct vvp_code_s *code;
|
||||
char *label;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool array_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
code->array = array_find(label);
|
||||
code->array = array_find(label());
|
||||
if (code->array != 0) {
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "Array unresolved: %s\n", label);
|
||||
fprintf(stderr, "Array unresolved: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void compile_array_lookup(struct vvp_code_s*code, char*label)
|
||||
{
|
||||
struct array_resolv_list_s *res
|
||||
= new struct array_resolv_list_s;
|
||||
struct code_array_resolv_list_s *res
|
||||
= new struct code_array_resolv_list_s(label);
|
||||
|
||||
res->code = code;
|
||||
res->label = label;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
@@ -941,6 +886,21 @@ template <class T_> void make_arith(T_ *arith, char*label,
|
||||
free(argv);
|
||||
}
|
||||
|
||||
void compile_arith_abs(char*label, unsigned argc, struct symb_s*argv)
|
||||
{
|
||||
vvp_arith_abs*arith = new vvp_arith_abs;
|
||||
|
||||
vvp_net_t* ptr = new vvp_net_t;
|
||||
ptr->fun = arith;
|
||||
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
|
||||
assert(argc == 1);
|
||||
inputs_connect(ptr, argc, argv);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
void compile_arith_div(char*label, long wid, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv)
|
||||
{
|
||||
@@ -1506,90 +1466,6 @@ char **compile_udp_table(char **table, char *row)
|
||||
return table;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take the detailed parse items from a .mem statement and generate
|
||||
* the necessary internal structures.
|
||||
*
|
||||
* <label> .mem <name>, <msb>, <lsb>, <idxs...> ;
|
||||
*
|
||||
*/
|
||||
void compile_memory(char *label, char *name, int msb, int lsb,
|
||||
unsigned narg, long *args)
|
||||
{
|
||||
/* Create an empty memory in the symbol table. */
|
||||
vvp_memory_t mem = memory_create(label);
|
||||
|
||||
assert( narg > 0 && narg%2 == 0 );
|
||||
|
||||
struct memory_address_range*ranges
|
||||
= new struct memory_address_range[narg/2];
|
||||
|
||||
for (unsigned idx = 0 ; idx < narg ; idx += 2) {
|
||||
ranges[idx/2].msb = args[idx+0];
|
||||
ranges[idx/2].lsb = args[idx+1];
|
||||
}
|
||||
|
||||
memory_configure(mem, msb, lsb, narg/2, ranges);
|
||||
|
||||
delete[]ranges;
|
||||
|
||||
vpiHandle obj = vpip_make_memory(mem, name);
|
||||
compile_vpi_symbol(label, obj);
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
free(label);
|
||||
free(name);
|
||||
}
|
||||
|
||||
void compile_memory_port(char *label, char *memid,
|
||||
unsigned argc, struct symb_s *argv)
|
||||
{
|
||||
vvp_memory_t mem = memory_find(memid);
|
||||
free(memid);
|
||||
assert(mem);
|
||||
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_fun_memport*fun = new vvp_fun_memport(mem, ptr);
|
||||
ptr->fun = fun;
|
||||
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
|
||||
inputs_connect(ptr, argc, argv);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* The parser calls this multiple times to parse a .mem/init
|
||||
* statement. The first call includes a memid label and is used to
|
||||
* select the memory and the start address. Subsequent calls contain
|
||||
* only the word value to assign.
|
||||
*/
|
||||
void compile_memory_init(char *memid, unsigned i, long val)
|
||||
{
|
||||
static vvp_memory_t current_mem = 0;
|
||||
static unsigned current_word;
|
||||
|
||||
if (memid) {
|
||||
current_mem = memory_find(memid);
|
||||
free(memid);
|
||||
current_word = i;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(current_mem);
|
||||
|
||||
unsigned word_wid = memory_word_width(current_mem);
|
||||
|
||||
vvp_vector4_t val4 (word_wid);
|
||||
for (unsigned idx = 0 ; idx < word_wid ; idx += 1) {
|
||||
vvp_bit4_t bit = val & 1 ? BIT4_1 : BIT4_0;
|
||||
val4.set_bit(idx, bit);
|
||||
}
|
||||
|
||||
memory_init_word(current_mem, current_word, val4);
|
||||
current_word += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The parser uses this function to compile and link an executable
|
||||
@@ -1705,15 +1581,6 @@ void compile_code(char*label, char*mnem, comp_operands_t opa)
|
||||
code->number = opa->argv[idx].numb;
|
||||
break;
|
||||
|
||||
case OA_MEM_PTR:
|
||||
if (opa->argv[idx].ltype != L_SYMB) {
|
||||
yyerror("operand format");
|
||||
break;
|
||||
}
|
||||
|
||||
compile_mem_lookup(code, opa->argv[idx].symb.text);
|
||||
break;
|
||||
|
||||
case OA_VPI_PTR:
|
||||
/* The operand is a functor. Resolve the label to
|
||||
a functor pointer, or postpone the resolution
|
||||
@@ -1781,7 +1648,7 @@ void compile_fork(char*label, struct symb_s dest, struct symb_s scope)
|
||||
}
|
||||
|
||||
void compile_vpi_call(char*label, char*name,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv)
|
||||
{
|
||||
if (label)
|
||||
@@ -1794,7 +1661,7 @@ void compile_vpi_call(char*label, char*name,
|
||||
/* Create a vpiHandle that bundles the call information, and
|
||||
store that handle in the instruction. */
|
||||
code->handle = vpip_build_vpi_call(name, 0, 0, 0, argc, argv,
|
||||
file_idx, line_no);
|
||||
file_idx, lineno);
|
||||
if (code->handle == 0)
|
||||
compile_errors += 1;
|
||||
|
||||
@@ -1804,7 +1671,7 @@ void compile_vpi_call(char*label, char*name,
|
||||
|
||||
void compile_vpi_func_call(char*label, char*name,
|
||||
unsigned vbit, int vwid,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv)
|
||||
{
|
||||
if (label)
|
||||
@@ -1817,7 +1684,7 @@ void compile_vpi_func_call(char*label, char*name,
|
||||
/* Create a vpiHandle that bundles the call information, and
|
||||
store that handle in the instruction. */
|
||||
code->handle = vpip_build_vpi_call(name, vbit, vwid, 0, argc, argv,
|
||||
file_idx, line_no);
|
||||
file_idx, lineno);
|
||||
if (code->handle == 0)
|
||||
compile_errors += 1;
|
||||
|
||||
@@ -1852,10 +1719,12 @@ void compile_thread(char*start_sym, char*flag)
|
||||
free(flag);
|
||||
}
|
||||
|
||||
void compile_param_logic(char*label, char*name, char*value, bool signed_flag)
|
||||
void compile_param_logic(char*label, char*name, char*value, bool signed_flag,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
vvp_vector4_t value4 = c4string_to_vector4(value);
|
||||
vpiHandle obj = vpip_make_binary_param(name, value4, signed_flag);
|
||||
vpiHandle obj = vpip_make_binary_param(name, value4, signed_flag,
|
||||
file_idx, lineno);
|
||||
compile_vpi_symbol(label, obj);
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
@@ -1863,19 +1732,21 @@ void compile_param_logic(char*label, char*name, char*value, bool signed_flag)
|
||||
free(value);
|
||||
}
|
||||
|
||||
void compile_param_string(char*label, char*name, char*value)
|
||||
void compile_param_string(char*label, char*name, char*value,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
vpiHandle obj = vpip_make_string_param(name, value);
|
||||
vpiHandle obj = vpip_make_string_param(name, value, file_idx, lineno);
|
||||
compile_vpi_symbol(label, obj);
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
free(label);
|
||||
}
|
||||
|
||||
void compile_param_real(char*label, char*name, char*value)
|
||||
void compile_param_real(char*label, char*name, char*value,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
double dvalue = crstring_to_double(value);
|
||||
vpiHandle obj = vpip_make_real_param(name, dvalue);
|
||||
vpiHandle obj = vpip_make_real_param(name, dvalue, file_idx, lineno);
|
||||
compile_vpi_symbol(label, obj);
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
|
||||
+52
-15
@@ -149,6 +149,8 @@ extern void compile_part_select_var(char*label, char*src,
|
||||
*/
|
||||
extern void compile_arith_pow(char*label, long width, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_arith_abs(char*label,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_arith_div(char*label, long width, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_arith_mod(char*label, long width,
|
||||
@@ -218,7 +220,7 @@ extern void compile_reduce_xnor(char*label, struct symb_s arg);
|
||||
extern void compile_extend_signed(char*label, long width, struct symb_s arg);
|
||||
|
||||
extern void compile_sfunc(char*label, char*name, char*format_string,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_repeat(char*label, long width, long repeat,
|
||||
struct symb_s arg);
|
||||
@@ -233,10 +235,48 @@ extern void compile_timescale(long units, long precision);
|
||||
extern void compile_vpi_symbol(const char*label, vpiHandle obj);
|
||||
extern void compile_vpi_lookup(vpiHandle *objref, char*label);
|
||||
|
||||
extern void compile_param_string(char*label, char*name, char*value);
|
||||
extern void compile_param_string(char*label, char*name, char*value,
|
||||
long file_idx, long lineno);
|
||||
extern void compile_param_logic(char*label, char*name, char*value,
|
||||
bool signed_flag);
|
||||
extern void compile_param_real(char*label, char*name, char*value);
|
||||
bool signed_flag,
|
||||
long file_idx, long lineno);
|
||||
extern void compile_param_real(char*label, char*name, char*value,
|
||||
long file_idx, long lineno);
|
||||
|
||||
/*
|
||||
* The resolv_list_s is the base class for a symbol resolve
|
||||
* action. Some function creates an instance of a resolv_list_s object
|
||||
* that contains the data pertinent to that resolution request, and
|
||||
* executes it with the resolv_submit function. If the operation can
|
||||
* complete, then the resolv_submit deletes the object. Otherwise, it
|
||||
* pushes it onto the resolv_list for later processing.
|
||||
*
|
||||
* Derived classes implement the resolve function to perform the
|
||||
* actual binding or resolution that the instance requires. If the
|
||||
* function succeeds, the resolve method returns true and the object
|
||||
* can be deleted any time.
|
||||
*
|
||||
* The mes parameter of the resolve method tells the resolver that
|
||||
* this call is its last chance. If it cannot complete the operation,
|
||||
* it must print an error message and return false.
|
||||
*/
|
||||
class resolv_list_s {
|
||||
|
||||
public:
|
||||
explicit resolv_list_s(char*lab) : label_(lab) { }
|
||||
virtual ~resolv_list_s();
|
||||
virtual bool resolve(bool mes = false) = 0;
|
||||
|
||||
protected:
|
||||
const char*label() const { return label_; }
|
||||
|
||||
private:
|
||||
friend void ::resolv_submit(struct resolv_list_s*cur);
|
||||
friend void ::compile_cleanup(void);
|
||||
|
||||
char*label_;
|
||||
struct resolv_list_s*next;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function schedules a lookup of an indexed label. The ref
|
||||
@@ -290,15 +330,10 @@ extern void compile_net_array(char*label, char*name,
|
||||
int last, int first);
|
||||
extern void compile_array_alias(char*label, char*name, char*src);
|
||||
|
||||
/* Index is a net. */
|
||||
extern void compile_array_port(char*label, char*name, char*addr);
|
||||
|
||||
extern void compile_memory(char *label, char *name, int lsb, int msb,
|
||||
unsigned idxs, long *idx);
|
||||
|
||||
extern void compile_memory_port(char *label, char *memid,
|
||||
unsigned argc, struct symb_s *argv);
|
||||
|
||||
extern void compile_memory_init(char *memid, unsigned idx, long val);
|
||||
/* Index is a constant address */
|
||||
extern void compile_array_port(char*label, char*name, long addr);
|
||||
|
||||
/*
|
||||
* Compile the .ufunc statement.
|
||||
@@ -349,7 +384,7 @@ extern void compile_code(char*label, char*mnem, comp_operands_t opa);
|
||||
extern void compile_disable(char*label, struct symb_s symb);
|
||||
|
||||
extern void compile_vpi_call(char*label, char*name,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv);
|
||||
|
||||
/* Compile a function call. The vbit and vwid encode the return
|
||||
@@ -358,7 +393,7 @@ extern void compile_vpi_call(char*label, char*name,
|
||||
code that represents the function type. */
|
||||
extern void compile_vpi_func_call(char*label, char*name,
|
||||
unsigned vbit, int vwid,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv);
|
||||
|
||||
extern void compile_fork(char*label, struct symb_s targ_s,
|
||||
@@ -369,7 +404,9 @@ extern void compile_codelabel(char*label);
|
||||
* The parser uses these functions to compile .scope statements.
|
||||
* The implementations of these live in the vpi_scope.cc file.
|
||||
*/
|
||||
extern void compile_scope_decl(char*typ, char*lab, char*nam,const char*tnam,char*par);
|
||||
extern void compile_scope_decl(char*typ, char*lab, char*nam,const char*tnam,
|
||||
char*par, long file_idx, long lineno,
|
||||
long def_file_idx, long def_lineno);
|
||||
extern void compile_scope_recall(char*sym);
|
||||
|
||||
/*
|
||||
|
||||
+2
-3
@@ -87,6 +87,7 @@
|
||||
".alias" { return K_ALIAS; }
|
||||
".alias/real" { return K_ALIAS_R; }
|
||||
".alias/s" { return K_ALIAS_S; }
|
||||
".abs" { return K_ARITH_ABS; }
|
||||
".arith/div" { return K_ARITH_DIV; }
|
||||
".arith/div.r" { return K_ARITH_DIV_R; }
|
||||
".arith/div.s" { return K_ARITH_DIV_S; }
|
||||
@@ -160,9 +161,6 @@
|
||||
".udp" { return K_UDP; }
|
||||
".udp/c"(omb)? { return K_UDP_C; }
|
||||
".udp/s"(equ)? { return K_UDP_S; }
|
||||
".mem" { return K_MEM; }
|
||||
".mem/p"(ort)? { return K_MEM_P; }
|
||||
".mem/i"(nit)? { return K_MEM_I; }
|
||||
"-debug" { return K_DEBUG; }
|
||||
|
||||
/* instructions start with a % character. The compiler decides what
|
||||
@@ -189,6 +187,7 @@
|
||||
return T_NUMBER; }
|
||||
|
||||
|
||||
"&A" { return K_A; }
|
||||
|
||||
/* Handle some specialized constant/literals as symbols. */
|
||||
|
||||
|
||||
-299
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: memory.cc,v 1.29 2006/03/05 05:45:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "symbols.h"
|
||||
#include "schedule.h"
|
||||
#include "vpi_priv.h"
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
typedef struct vvp_memory_port_s *vvp_memory_port_t;
|
||||
|
||||
struct vvp_memory_s
|
||||
{
|
||||
// Address ranges (1 or more)
|
||||
unsigned nrange;
|
||||
struct memory_address_range*ranges;
|
||||
|
||||
// Data port properties:
|
||||
unsigned width; // number of data bits
|
||||
|
||||
int msb, lsb; // Most/Least Significant data bit (VPI)
|
||||
|
||||
// Array of words.
|
||||
unsigned word_count;
|
||||
vvp_vector4_t*words;
|
||||
|
||||
// List of ports into this memory.
|
||||
class vvp_fun_memport* port_list;
|
||||
vpiHandle vpi_self;
|
||||
};
|
||||
|
||||
#define VVP_MEMORY_NO_ADDR ((int)0x80000000)
|
||||
|
||||
// Compilation
|
||||
|
||||
static symbol_table_t memory_table = 0;
|
||||
|
||||
vvp_memory_t memory_find(char *label)
|
||||
{
|
||||
if (memory_table == 0)
|
||||
return 0;
|
||||
|
||||
symbol_value_t v = sym_get_value(memory_table, label);
|
||||
return (vvp_memory_t)v.ptr;
|
||||
}
|
||||
|
||||
vvp_memory_t memory_create(char *label)
|
||||
{
|
||||
if (!memory_table)
|
||||
memory_table = new_symbol_table();
|
||||
|
||||
assert(!memory_find(label));
|
||||
|
||||
vvp_memory_t mem = new struct vvp_memory_s;
|
||||
|
||||
symbol_value_t v;
|
||||
v.ptr = mem;
|
||||
sym_set_value(memory_table, label, v);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void memory_configure(vvp_memory_t mem,
|
||||
int msb, int lsb,
|
||||
unsigned nrange,
|
||||
const struct memory_address_range*ranges)
|
||||
{
|
||||
/* Get the word width details. */
|
||||
mem->width = msb > lsb ? msb-lsb+1 : lsb-msb+1;
|
||||
mem->msb = msb;
|
||||
mem->lsb = lsb;
|
||||
|
||||
/* Make a private copy of the memory address ranges. */
|
||||
assert(nrange > 0);
|
||||
mem->nrange = nrange;
|
||||
mem->ranges = new struct memory_address_range[nrange];
|
||||
for (unsigned idx = 0 ; idx < nrange ; idx += 1)
|
||||
mem->ranges[idx] = ranges[idx];
|
||||
|
||||
/* Scan the indices (multiplying each range) to add up the
|
||||
total number of words in this memory. */
|
||||
mem->word_count = 1;
|
||||
for (unsigned idx = 0 ; idx < mem->nrange ; idx += 1) {
|
||||
struct memory_address_range*rp = mem->ranges+idx;
|
||||
|
||||
unsigned count = rp->msb > rp->lsb
|
||||
? rp->msb - rp->lsb + 1
|
||||
: rp->lsb - rp->msb + 1;
|
||||
|
||||
mem->word_count *= count;
|
||||
}
|
||||
|
||||
mem->words = new vvp_vector4_t [mem->word_count];
|
||||
assert(mem->words);
|
||||
|
||||
mem->port_list = 0;
|
||||
mem->vpi_self = 0;
|
||||
}
|
||||
|
||||
void memory_attach_self(vvp_memory_t mem, vpiHandle self)
|
||||
{
|
||||
assert(mem->vpi_self == 0);
|
||||
mem->vpi_self = self;
|
||||
}
|
||||
|
||||
unsigned memory_word_width(vvp_memory_t mem)
|
||||
{
|
||||
return mem->width;
|
||||
}
|
||||
|
||||
unsigned memory_word_count(vvp_memory_t mem)
|
||||
{
|
||||
return mem->word_count;
|
||||
}
|
||||
|
||||
long memory_word_left_range(vvp_memory_t mem)
|
||||
{
|
||||
return mem->msb;
|
||||
}
|
||||
|
||||
long memory_word_right_range(vvp_memory_t mem)
|
||||
{
|
||||
return mem->lsb;
|
||||
}
|
||||
|
||||
long memory_left_range(vvp_memory_t mem, unsigned ix)
|
||||
{
|
||||
assert(ix < mem->nrange);
|
||||
return mem->ranges[ix].msb;
|
||||
}
|
||||
|
||||
long memory_right_range(vvp_memory_t mem, unsigned ix)
|
||||
{
|
||||
assert(ix < mem->nrange);
|
||||
return mem->ranges[ix].lsb;
|
||||
}
|
||||
|
||||
vvp_vector4_t memory_get_word(vvp_memory_t mem, unsigned addr)
|
||||
{
|
||||
/* If the address is out of range, then return a vector of all
|
||||
X bits. */
|
||||
if (addr >= mem->word_count) {
|
||||
vvp_vector4_t val (mem->width);
|
||||
for (unsigned idx = 0 ; idx < mem->width ; idx += 1)
|
||||
val.set_bit(idx, BIT4_X);
|
||||
return val;
|
||||
}
|
||||
|
||||
assert(addr <= mem->word_count);
|
||||
|
||||
if (mem->words[addr].size() == 0) {
|
||||
vvp_vector4_t tmp (mem->width);
|
||||
for (unsigned idx = 0 ; idx < mem->width ; idx += 1)
|
||||
tmp.set_bit(idx, BIT4_X);
|
||||
mem->words[addr] = tmp;
|
||||
}
|
||||
|
||||
return mem->words[addr];
|
||||
}
|
||||
|
||||
void memory_init_word(vvp_memory_t mem, unsigned addr, vvp_vector4_t val)
|
||||
{
|
||||
if (addr >= mem->word_count)
|
||||
return;
|
||||
|
||||
assert(val.size() == mem->width);
|
||||
mem->words[addr] = val;
|
||||
}
|
||||
|
||||
void memory_set_word(vvp_memory_t mem, unsigned addr,
|
||||
unsigned off, vvp_vector4_t val)
|
||||
{
|
||||
if (addr >= mem->word_count)
|
||||
return;
|
||||
|
||||
if (off >= mem->width)
|
||||
return;
|
||||
|
||||
if (off == 0 && val.size() == mem->width) {
|
||||
mem->words[addr] = val;
|
||||
|
||||
} else {
|
||||
if ((off + val.size()) > mem->width)
|
||||
val = val.subvalue(0, mem->width - off);
|
||||
|
||||
mem->words[addr].set_vec(off, val);
|
||||
}
|
||||
|
||||
for (vvp_fun_memport*cur = mem->port_list
|
||||
; cur ; cur = cur->next_) {
|
||||
cur->check_word_change(addr);
|
||||
}
|
||||
|
||||
vpip_run_memory_value_change(mem->vpi_self, addr);
|
||||
}
|
||||
|
||||
void schedule_memory(vvp_memory_t mem, unsigned addr,
|
||||
vvp_vector4_t val, unsigned long delay)
|
||||
{
|
||||
fprintf(stderr, "XXXX Forgot how to schedule memory write.\n");
|
||||
}
|
||||
|
||||
vvp_fun_memport::vvp_fun_memport(vvp_memory_t mem, vvp_net_t*net)
|
||||
: mem_(mem), net_(net)
|
||||
{
|
||||
addr_ = 0;
|
||||
next_ = mem_->port_list;
|
||||
mem_->port_list = this;
|
||||
}
|
||||
|
||||
vvp_fun_memport::~vvp_fun_memport()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_fun_memport::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
||||
{
|
||||
bool addr_valid_flag;
|
||||
|
||||
switch (port.port()) {
|
||||
|
||||
case 0: // Address input
|
||||
addr_valid_flag = vector4_to_value(bit, addr_);
|
||||
if (! addr_valid_flag)
|
||||
addr_ = memory_word_count(mem_);
|
||||
vvp_send_vec4(port.ptr()->out, memory_get_word(mem_,addr_));
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stdout, "XXXX write ports not implemented.\n");
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by the memory itself to tell this port that
|
||||
* the given address had a content change. The device itself figures
|
||||
* out what to do with that information.
|
||||
*/
|
||||
void vvp_fun_memport::check_word_change(unsigned long addr)
|
||||
{
|
||||
if (addr != addr_)
|
||||
return;
|
||||
|
||||
vvp_vector4_t bit = memory_get_word(mem_, addr_);
|
||||
vvp_send_vec4(net_->out, bit);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: memory.cc,v $
|
||||
* Revision 1.29 2006/03/05 05:45:58 steve
|
||||
* Add support for memory value change callbacks.
|
||||
*
|
||||
* Revision 1.28 2006/02/02 02:44:00 steve
|
||||
* Allow part selects of memory words in l-values.
|
||||
*
|
||||
* Revision 1.27 2005/06/22 00:04:49 steve
|
||||
* Reduce vvp_vector4 copies by using const references.
|
||||
*
|
||||
* Revision 1.26 2005/03/09 04:52:40 steve
|
||||
* reimplement memory ports.
|
||||
*
|
||||
* Revision 1.25 2005/03/06 17:07:48 steve
|
||||
* Non blocking assign to memory words.
|
||||
*
|
||||
* Revision 1.24 2005/03/05 05:44:32 steve
|
||||
* Get read width of unitialized memory words right.
|
||||
*
|
||||
* Revision 1.23 2005/03/03 04:33:10 steve
|
||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
||||
*
|
||||
*/
|
||||
-180
@@ -1,180 +0,0 @@
|
||||
#ifndef __memory_H // -*- c++ -*-
|
||||
#define __memory_H
|
||||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: memory.h,v 1.13 2007/03/22 16:08:19 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "vvp_net.h"
|
||||
#include "vpi_user.h"
|
||||
|
||||
/*
|
||||
** vvp_memory_t is a memory
|
||||
** vvp_memory_index_t is a memory index range definition
|
||||
*/
|
||||
typedef struct vvp_memory_s *vvp_memory_t;
|
||||
|
||||
struct memory_address_range {
|
||||
int msb;
|
||||
int lsb;
|
||||
};
|
||||
|
||||
/*
|
||||
* Given a memory device, the memory_configure function configures it
|
||||
* by defining the dimensions of the device. It is an error to
|
||||
* redefine the dimensions of a device already configured.
|
||||
*
|
||||
* The lsb and msb define the dimensions of a word. They are in
|
||||
* Verilog form. The actual word contents are vvp_vector4_t values.
|
||||
*
|
||||
* The idx array is an array of address ranges that describe the
|
||||
* complete multi-dimensional array. In a normal Verilog array, idxs
|
||||
* is 1, and idx is a pointer to a single memory_address_range. The
|
||||
* table does not need to be persistent.
|
||||
*/
|
||||
extern void memory_configure(vvp_memory_t mem, int msb, int lsb,
|
||||
unsigned idxs,
|
||||
const struct memory_address_range *idx);
|
||||
extern void memory_attach_self(vvp_memory_t mem, vpiHandle self);
|
||||
|
||||
/*
|
||||
* init_word and set_word functions take the memory to be manipulated
|
||||
* and write a word value at the given word address. The idx is the
|
||||
* canonical (0-based, 1-dimensional) address of the word to be
|
||||
* written. The caller needs to have converted any multi-dimensional
|
||||
* address into a canonical address first.
|
||||
*
|
||||
* The difference between init_word and set_word are that the set_word
|
||||
* function causes values to be propagated through structural ports,
|
||||
* but the init_word does not.
|
||||
*/
|
||||
extern void memory_init_word(vvp_memory_t mem,
|
||||
unsigned idx,
|
||||
vvp_vector4_t val);
|
||||
extern void memory_set_word(vvp_memory_t mem,
|
||||
unsigned idx,
|
||||
unsigned off,
|
||||
vvp_vector4_t val);
|
||||
|
||||
/*
|
||||
* This doesn't actually write the value to the memory word, but
|
||||
* schedules for the write to happen some time in the future. The delay
|
||||
* is in simulation clock units.
|
||||
*/
|
||||
void schedule_memory(vvp_memory_t mem, unsigned addr,
|
||||
vvp_vector4_t val, unsigned long delay);
|
||||
|
||||
/*
|
||||
* Get the word value at the given index into the memory.
|
||||
*/
|
||||
extern vvp_vector4_t memory_get_word(vvp_memory_t mem, unsigned idx);
|
||||
|
||||
|
||||
/* Number of words in the memory. */
|
||||
unsigned memory_word_count(vvp_memory_t mem);
|
||||
/* Width of a word */
|
||||
unsigned memory_word_width(vvp_memory_t mem);
|
||||
/* Get the user declared geometry of the memory address. This is the
|
||||
msb and lsb values for each pair in the multi-dimensional array. */
|
||||
long memory_left_range(vvp_memory_t mem, unsigned ix);
|
||||
long memory_right_range(vvp_memory_t mem, unsigned ix);
|
||||
/* Get the user defined geometry for the memory *word*. */
|
||||
long memory_word_left_range(vvp_memory_t mem);
|
||||
long memory_word_right_range(vvp_memory_t mem);
|
||||
|
||||
|
||||
/* vvp_fun_memport
|
||||
* The vvp_fum_memport is a structural port into a vvp_memory_t
|
||||
* object. The output is the word that is read from the addressed
|
||||
* memory, and the inputs are the address and optional write controls.
|
||||
*
|
||||
* 0 -- Address
|
||||
* This addresses the word in the memory. The output follows this
|
||||
* address as it changes, and also follows the value of the addressed
|
||||
* word.
|
||||
*
|
||||
* 1 -- Write event
|
||||
*
|
||||
* 2 -- Write enable
|
||||
*
|
||||
* 3 -- Write data
|
||||
*
|
||||
* NOTE: This functor is unique in that it needs to store the
|
||||
* vvp_net_t pointer associated with it. It needs this because it can
|
||||
* received input from other than its ports. Notably, the memory
|
||||
* itself reports word changes.
|
||||
*/
|
||||
class vvp_fun_memport : public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_memport(vvp_memory_t mem, vvp_net_t*net);
|
||||
~vvp_fun_memport();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
|
||||
|
||||
private:
|
||||
vvp_memory_t mem_;
|
||||
|
||||
friend void memory_set_word(vvp_memory_t, unsigned,
|
||||
unsigned, vvp_vector4_t);
|
||||
void check_word_change(unsigned long address);
|
||||
class vvp_fun_memport*next_;
|
||||
|
||||
unsigned long addr_;
|
||||
|
||||
vvp_net_t*net_;
|
||||
};
|
||||
|
||||
/*
|
||||
** Access to the memory symbol table.
|
||||
**
|
||||
** The memory_find function locates the memory device by name. If the
|
||||
** device does not exist, a nil is returned.
|
||||
**
|
||||
** The memory_create function creates a new memory device with the given
|
||||
** name. It is a fatal error to try to create a device that already exists.
|
||||
*/
|
||||
vvp_memory_t memory_find(char *label);
|
||||
vvp_memory_t memory_create(char *label);
|
||||
|
||||
/*
|
||||
* $Log: memory.h,v $
|
||||
* Revision 1.13 2007/03/22 16:08:19 steve
|
||||
* Spelling fixes from Larry
|
||||
*
|
||||
* Revision 1.12 2006/03/05 05:45:58 steve
|
||||
* Add support for memory value change callbacks.
|
||||
*
|
||||
* Revision 1.11 2006/02/02 02:44:00 steve
|
||||
* Allow part selects of memory words in l-values.
|
||||
*
|
||||
* Revision 1.10 2005/06/22 00:04:49 steve
|
||||
* Reduce vvp_vector4 copies by using const references.
|
||||
*
|
||||
* Revision 1.9 2005/03/09 04:52:40 steve
|
||||
* reimplement memory ports.
|
||||
*
|
||||
* Revision 1.8 2005/03/03 04:33:10 steve
|
||||
* Rearrange how memories are supported as vvp_vector4 arrays.
|
||||
*
|
||||
*/
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,10 @@ the left operand, the right operand, and the base. The left operand is
|
||||
replaced with the result, which is the same width as the left and
|
||||
right operands.
|
||||
|
||||
* %abs/wr <bit-o>, <bit-i>
|
||||
|
||||
This instructure calculate the absolute value of a real value. It uses
|
||||
the fabs() function in the run-time to do the work.
|
||||
|
||||
* %add <bit-l>, <bit-r>, <wid>
|
||||
|
||||
|
||||
+61
-68
@@ -65,8 +65,9 @@ static struct __vpiModPath*modpath_dst = 0;
|
||||
vvp_delay_t*cdelay;
|
||||
};
|
||||
|
||||
%token K_ALIAS K_ALIAS_S K_ALIAS_R
|
||||
%token K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD K_ARITH_MOD_R
|
||||
%token K_A K_ALIAS K_ALIAS_S K_ALIAS_R
|
||||
%token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD
|
||||
%token K_ARITH_MOD_R
|
||||
%token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R
|
||||
%token K_ARITH_SUM K_ARITH_SUM_R K_ARITH_POW K_ARITH_POW_R K_ARITH_POW_S
|
||||
%token K_ARRAY K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_PORT
|
||||
@@ -81,7 +82,6 @@ static struct __vpiModPath*modpath_dst = 0;
|
||||
%token K_RESOLV K_SCOPE K_SFUNC K_SHIFTL K_SHIFTR K_SHIFTRS
|
||||
%token K_THREAD K_TIMESCALE K_UFUNC
|
||||
%token K_UDP K_UDP_C K_UDP_S
|
||||
%token K_MEM K_MEM_P K_MEM_I
|
||||
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_func K_vpi_func_r
|
||||
%token K_disable K_fork
|
||||
%token K_vpi_module K_vpi_time_precision K_file_names
|
||||
@@ -184,14 +184,6 @@ statement
|
||||
|
||||
/* Memory. Definition, port, initialization */
|
||||
|
||||
| T_LABEL K_MEM T_STRING ',' T_NUMBER ',' T_NUMBER ',' numbers ';'
|
||||
{ compile_memory($1, $3, $5, $7, $9.cnt, $9.nvec); }
|
||||
|
||||
| T_LABEL K_MEM_P T_SYMBOL ',' symbols ';'
|
||||
{ compile_memory_port($1, $3, $5.cnt, $5.vect); }
|
||||
|
||||
| mem_init_stmt
|
||||
|
||||
| T_LABEL K_ARRAY T_STRING ',' signed_t_number signed_t_number ',' signed_t_number signed_t_number ';'
|
||||
{ compile_var_array($1, $3, $5, $6, $8, $9, 0); }
|
||||
|
||||
@@ -210,6 +202,9 @@ statement
|
||||
| T_LABEL K_ARRAY_PORT T_SYMBOL ',' T_SYMBOL ';'
|
||||
{ compile_array_port($1, $3, $5); }
|
||||
|
||||
| T_LABEL K_ARRAY_PORT T_SYMBOL ',' T_NUMBER ';'
|
||||
{ compile_array_port($1, $3, $5); }
|
||||
|
||||
| T_LABEL K_ARRAY T_STRING ',' T_SYMBOL ';'
|
||||
{ compile_array_alias($1, $3, $5); }
|
||||
|
||||
@@ -248,6 +243,14 @@ statement
|
||||
symbols ';'
|
||||
{ compile_concat($1, $4, $5, $6, $7, $10.cnt, $10.vect); }
|
||||
|
||||
/* The ABS statement is a special arithmetic node that takes 1
|
||||
input. Re-use the symbols rule. */
|
||||
|
||||
| T_LABEL K_ARITH_ABS symbols ';'
|
||||
{ struct symbv_s obj = $3;
|
||||
compile_arith_abs($1, obj.cnt, obj.vect);
|
||||
}
|
||||
|
||||
/* Arithmetic statements generate functor arrays of a given width
|
||||
that take like size input vectors. */
|
||||
|
||||
@@ -529,19 +532,20 @@ statement
|
||||
The final symbol is the label of the parent scope. If there is no
|
||||
parent scope, then this is a root scope. */
|
||||
|
||||
| T_LABEL K_SCOPE T_SYMBOL ',' T_STRING T_STRING ';'
|
||||
{ compile_scope_decl($1, $3, $5, $6, 0); }
|
||||
| T_LABEL K_SCOPE T_SYMBOL ',' T_STRING T_STRING T_NUMBER T_NUMBER ';'
|
||||
{ compile_scope_decl($1, $3, $5, $6, 0, $7, $8, $7, $8); }
|
||||
|
||||
| T_LABEL K_SCOPE T_SYMBOL ',' T_STRING T_STRING ',' T_SYMBOL ';'
|
||||
{ compile_scope_decl($1, $3, $5, $6, $8); }
|
||||
| T_LABEL K_SCOPE T_SYMBOL ',' T_STRING T_STRING T_NUMBER T_NUMBER ','
|
||||
T_NUMBER T_NUMBER ',' T_SYMBOL ';'
|
||||
{ compile_scope_decl($1, $3, $5, $6, $13, $7, $8, $10, $11); }
|
||||
|
||||
/* XXXX Legacy declaration has no type name. */
|
||||
|
||||
| T_LABEL K_SCOPE T_SYMBOL ',' T_STRING ';'
|
||||
{ compile_scope_decl($1, $3, $5, "", 0); }
|
||||
{ compile_scope_decl($1, $3, $5, "", 0, 0, 0, 0, 0); }
|
||||
|
||||
| T_LABEL K_SCOPE T_SYMBOL ',' T_STRING ',' T_SYMBOL ';'
|
||||
{ compile_scope_decl($1, $3, $5, "", $7); }
|
||||
{ compile_scope_decl($1, $3, $5, "", $7, 0, 0, 0, 0); }
|
||||
|
||||
/* Scope recall has no label of its own, but refers by label to a
|
||||
declared scope. */
|
||||
@@ -657,17 +661,17 @@ statement
|
||||
/* Parameter statements come in a few simple forms. The most basic
|
||||
is the string parameter. */
|
||||
|
||||
| T_LABEL K_PARAM_STR T_STRING ',' T_STRING ';'
|
||||
{ compile_param_string($1, $3, $5); }
|
||||
| T_LABEL K_PARAM_STR T_STRING T_NUMBER T_NUMBER',' T_STRING ';'
|
||||
{ compile_param_string($1, $3, $7, $4, $5); }
|
||||
|
||||
| T_LABEL K_PARAM_L T_STRING ',' T_SYMBOL ';'
|
||||
{ compile_param_logic($1, $3, $5, false); }
|
||||
| T_LABEL K_PARAM_L T_STRING T_NUMBER T_NUMBER',' T_SYMBOL ';'
|
||||
{ compile_param_logic($1, $3, $7, false, $4, $5); }
|
||||
|
||||
| T_LABEL K_PARAM_L T_STRING ',' '+' T_SYMBOL ';'
|
||||
{ compile_param_logic($1, $3, $6, true); }
|
||||
| T_LABEL K_PARAM_L T_STRING T_NUMBER T_NUMBER',' '+' T_SYMBOL ';'
|
||||
{ compile_param_logic($1, $3, $8, true, $4, $5); }
|
||||
|
||||
| T_LABEL K_PARAM_REAL T_STRING ',' T_SYMBOL ';'
|
||||
{ compile_param_real($1, $3, $5); }
|
||||
| T_LABEL K_PARAM_REAL T_STRING T_NUMBER T_NUMBER',' T_SYMBOL ';'
|
||||
{ compile_param_real($1, $3, $7, $4, $5); }
|
||||
|
||||
/* Oh and by the way, empty statements are OK as well. */
|
||||
|
||||
@@ -753,38 +757,40 @@ argument_opt
|
||||
;
|
||||
|
||||
argument_list
|
||||
: argument
|
||||
{ struct argv_s tmp;
|
||||
argv_init(&tmp);
|
||||
argv_add(&tmp, $1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| argument_list ',' argument
|
||||
{ struct argv_s tmp = $1;
|
||||
argv_add(&tmp, $3);
|
||||
$$ = tmp;
|
||||
}
|
||||
| T_SYMBOL
|
||||
{ struct argv_s tmp;
|
||||
argv_init(&tmp);
|
||||
argv_sym_add(&tmp, $1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| argument_list ',' T_SYMBOL
|
||||
{ struct argv_s tmp = $1;
|
||||
argv_sym_add(&tmp, $3);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
: argument
|
||||
{ struct argv_s tmp;
|
||||
argv_init(&tmp);
|
||||
argv_add(&tmp, $1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| argument_list ',' argument
|
||||
{ struct argv_s tmp = $1;
|
||||
argv_add(&tmp, $3);
|
||||
$$ = tmp;
|
||||
}
|
||||
| T_SYMBOL
|
||||
{ struct argv_s tmp;
|
||||
argv_init(&tmp);
|
||||
argv_sym_add(&tmp, $1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| argument_list ',' T_SYMBOL
|
||||
{ struct argv_s tmp = $1;
|
||||
argv_sym_add(&tmp, $3);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
argument
|
||||
: T_STRING
|
||||
{ $$ = vpip_make_string_const($1); }
|
||||
| T_VECTOR
|
||||
{ $$ = vpip_make_binary_const($1.idx, $1.text);
|
||||
free($1.text);
|
||||
}
|
||||
;
|
||||
: T_STRING
|
||||
{ $$ = vpip_make_string_const($1); }
|
||||
| T_VECTOR
|
||||
{ $$ = vpip_make_binary_const($1.idx, $1.text);
|
||||
free($1.text);
|
||||
}
|
||||
| K_A '<' T_SYMBOL ',' T_NUMBER '>'
|
||||
{ $$ = vpip_make_vthr_A($3, $5); }
|
||||
;
|
||||
|
||||
|
||||
/* functor operands can only be a list of symbols. */
|
||||
@@ -889,19 +895,6 @@ udp_table
|
||||
{ $$ = compile_udp_table($1, $3); }
|
||||
;
|
||||
|
||||
mem_init_stmt
|
||||
: K_MEM_I symbol T_NUMBER ','
|
||||
{ compile_memory_init($2.text, $3, 0); }
|
||||
mem_init_list ';'
|
||||
;
|
||||
|
||||
mem_init_list
|
||||
: mem_init_list ',' T_NUMBER
|
||||
{ compile_memory_init(0, 0, $3); }
|
||||
| T_NUMBER
|
||||
{ compile_memory_init(0, 0, $1); }
|
||||
;
|
||||
|
||||
signed_t_number
|
||||
: T_NUMBER { $$ = $1; }
|
||||
| '-' T_NUMBER { $$ = -$2; }
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
# include "schedule.h"
|
||||
# include "memory.h"
|
||||
# include "vthread.h"
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
@@ -141,20 +140,6 @@ void assign_real_event_s::run_run(void)
|
||||
vvp_send_real(ptr, val);
|
||||
}
|
||||
|
||||
struct assign_memory_word_s : public event_s {
|
||||
vvp_memory_t mem;
|
||||
unsigned adr;
|
||||
vvp_vector4_t val;
|
||||
unsigned off;
|
||||
void run_run(void);
|
||||
};
|
||||
|
||||
void assign_memory_word_s::run_run(void)
|
||||
{
|
||||
count_assign_events += 1;
|
||||
memory_set_word(mem, adr, off, val);
|
||||
}
|
||||
|
||||
struct assign_array_word_s : public event_s {
|
||||
vvp_array_t mem;
|
||||
unsigned adr;
|
||||
@@ -500,20 +485,6 @@ void schedule_assign_vector(vvp_net_ptr_t ptr,
|
||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
void schedule_assign_memory_word(vvp_memory_t mem,
|
||||
unsigned word_addr,
|
||||
unsigned off,
|
||||
vvp_vector4_t val,
|
||||
vvp_time64_t delay)
|
||||
{
|
||||
struct assign_memory_word_s*cur = new struct assign_memory_word_s;
|
||||
cur->mem = mem;
|
||||
cur->adr = word_addr;
|
||||
cur->off = off;
|
||||
cur->val = val;
|
||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
void schedule_assign_array_word(vvp_array_t mem,
|
||||
unsigned word_addr,
|
||||
unsigned off,
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
# include "vthread.h"
|
||||
# include "pointers.h"
|
||||
# include "vvp_net.h"
|
||||
# include "memory.h"
|
||||
# include "array.h"
|
||||
|
||||
/*
|
||||
@@ -57,11 +56,6 @@ extern void schedule_assign_array_word(vvp_array_t mem,
|
||||
unsigned off,
|
||||
vvp_vector4_t val,
|
||||
vvp_time64_t delay);
|
||||
extern void schedule_assign_memory_word(vvp_memory_t mem,
|
||||
unsigned word_address,
|
||||
unsigned off,
|
||||
vvp_vector4_t val,
|
||||
vvp_time64_t delay);
|
||||
/*
|
||||
* This is very similar to schedule_assign_vector, but generates an
|
||||
* event in the active queue. It is used at link time to assign a
|
||||
|
||||
+2
-3
@@ -129,7 +129,7 @@ static int make_vpi_argv(unsigned argc, vpiHandle*vpi_argv,
|
||||
|
||||
|
||||
void compile_sfunc(char*label, char*name, char*format_string,
|
||||
long file_idx, long line_no,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, struct symb_s*argv)
|
||||
{
|
||||
vpiHandle*vpi_argv = new vpiHandle[argc];
|
||||
@@ -139,7 +139,7 @@ void compile_sfunc(char*label, char*name, char*format_string,
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
|
||||
vpiHandle sys = vpip_build_vpi_call(name, 0, width_code, ptr,
|
||||
argc, vpi_argv, file_idx, line_no);
|
||||
argc, vpi_argv, file_idx, lineno);
|
||||
assert(sys);
|
||||
|
||||
/* Create and connect the functor to the label. */
|
||||
@@ -152,4 +152,3 @@ void compile_sfunc(char*label, char*name, char*format_string,
|
||||
wide_inputs_connect(score, argc, argv);
|
||||
free(argv);
|
||||
}
|
||||
|
||||
|
||||
+28
-15
@@ -103,7 +103,7 @@ struct __vpiCallback* new_vpi_callback()
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void delete_vpi_callback(struct __vpiCallback* ref)
|
||||
void delete_vpi_callback(struct __vpiCallback* ref)
|
||||
{
|
||||
assert(ref);
|
||||
assert(ref->base.vpi_type);
|
||||
@@ -162,8 +162,8 @@ static struct __vpiCallback* make_value_change(p_cb_data data)
|
||||
nev->callbacks = obj;
|
||||
break;
|
||||
|
||||
case vpiMemory:
|
||||
vpip_memory_value_change(obj, data->obj);
|
||||
case vpiMemoryWord:
|
||||
vpip_array_word_change(obj, data->obj);
|
||||
break;
|
||||
|
||||
case vpiModule:
|
||||
@@ -465,14 +465,11 @@ void callback_execute(struct __vpiCallback*cur)
|
||||
vvp_vpi_callback::vvp_vpi_callback()
|
||||
{
|
||||
vpi_callbacks_ = 0;
|
||||
array_ = 0;
|
||||
array_word_ = 0;
|
||||
}
|
||||
|
||||
vvp_vpi_callback::~vvp_vpi_callback()
|
||||
{
|
||||
assert(vpi_callbacks_ == 0);
|
||||
assert(array_ == 0);
|
||||
}
|
||||
|
||||
void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb)
|
||||
@@ -481,13 +478,6 @@ void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb)
|
||||
vpi_callbacks_ = cb;
|
||||
}
|
||||
|
||||
void vvp_vpi_callback::attach_as_word(vvp_array_t arr, unsigned long addr)
|
||||
{
|
||||
assert(array_ == 0);
|
||||
array_ = arr;
|
||||
array_word_ = addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* A vvp_fun_signal uses this method to run its callbacks whenever it
|
||||
* has a value change. If the cb_rtn is non-nil, then call the
|
||||
@@ -499,8 +489,6 @@ void vvp_vpi_callback::run_vpi_callbacks()
|
||||
struct __vpiCallback *next = vpi_callbacks_;
|
||||
struct __vpiCallback *prev = 0;
|
||||
|
||||
if (array_) array_word_change(array_, array_word_);
|
||||
|
||||
while (next) {
|
||||
struct __vpiCallback*cur = next;
|
||||
next = cur->next;
|
||||
@@ -527,6 +515,31 @@ void vvp_vpi_callback::run_vpi_callbacks()
|
||||
}
|
||||
}
|
||||
|
||||
vvp_vpi_callback_wordable::vvp_vpi_callback_wordable()
|
||||
{
|
||||
array_ = 0;
|
||||
array_word_ = 0;
|
||||
}
|
||||
|
||||
vvp_vpi_callback_wordable::~vvp_vpi_callback_wordable()
|
||||
{
|
||||
assert(array_ == 0);
|
||||
}
|
||||
|
||||
void vvp_vpi_callback_wordable::run_vpi_callbacks()
|
||||
{
|
||||
if (array_) array_word_change(array_, array_word_);
|
||||
|
||||
vvp_vpi_callback::run_vpi_callbacks();
|
||||
}
|
||||
|
||||
void vvp_vpi_callback_wordable::attach_as_word(vvp_array_t arr, unsigned long addr)
|
||||
{
|
||||
assert(array_ == 0);
|
||||
array_ = arr;
|
||||
array_word_ = addr;
|
||||
}
|
||||
|
||||
void vvp_fun_signal::get_value(struct t_vpi_value*vp)
|
||||
{
|
||||
switch (vp->format) {
|
||||
|
||||
+69
-15
@@ -32,9 +32,6 @@ static int string_get(int code, vpiHandle ref)
|
||||
struct __vpiStringConst*rfp;
|
||||
|
||||
switch (code) {
|
||||
case vpiLineNo:
|
||||
return 0; // Not implemented for now!
|
||||
|
||||
case vpiSize:
|
||||
rfp = (struct __vpiStringConst*)ref;
|
||||
|
||||
@@ -247,17 +244,33 @@ vpiHandle vpip_make_string_const(char*text, bool persistent_flag)
|
||||
struct __vpiStringParam : public __vpiStringConst {
|
||||
const char*basename;
|
||||
struct __vpiScope* scope;
|
||||
unsigned file_idx;
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
static int string_param_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiStringParam*rfp = (struct __vpiStringParam*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code == vpiParameter);
|
||||
|
||||
if (code == vpiLineNo) {
|
||||
return rfp->lineno;
|
||||
}
|
||||
|
||||
return string_get(code, ref);
|
||||
}
|
||||
|
||||
static char* string_param_get_str(int code, vpiHandle obj)
|
||||
{
|
||||
struct __vpiStringParam*rfp = (struct __vpiStringParam*)obj;
|
||||
|
||||
assert(obj->vpi_type->type_code == vpiParameter);
|
||||
|
||||
if (code == vpiFile) { // Not implemented for now!
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
if (code == vpiFile) {
|
||||
return simple_set_rbuf_str(file_names[rfp->file_idx]);
|
||||
}
|
||||
|
||||
return generic_get_str(code, &rfp->scope->base, rfp->basename, NULL);
|
||||
}
|
||||
|
||||
@@ -278,7 +291,7 @@ static vpiHandle string_param_handle(int code, vpiHandle obj)
|
||||
|
||||
static const struct __vpirt vpip_string_param_rt = {
|
||||
vpiParameter,
|
||||
string_get,
|
||||
string_param_get,
|
||||
string_param_get_str,
|
||||
string_value,
|
||||
0,
|
||||
@@ -291,7 +304,8 @@ static const struct __vpirt vpip_string_param_rt = {
|
||||
};
|
||||
|
||||
|
||||
vpiHandle vpip_make_string_param(char*name, char*text)
|
||||
vpiHandle vpip_make_string_param(char*name, char*text,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
struct __vpiStringParam*obj;
|
||||
|
||||
@@ -302,6 +316,8 @@ vpiHandle vpip_make_string_param(char*name, char*text)
|
||||
obj->value_len = 0;
|
||||
obj->basename = name;
|
||||
obj->scope = vpip_peek_current_scope();
|
||||
obj->file_idx = (unsigned) file_idx;
|
||||
obj->lineno = (unsigned) lineno;
|
||||
|
||||
vpip_process_string(obj);
|
||||
|
||||
@@ -426,17 +442,33 @@ vpiHandle vpip_make_binary_const(unsigned wid, const char*bits)
|
||||
struct __vpiBinaryParam : public __vpiBinaryConst {
|
||||
const char*basename;
|
||||
struct __vpiScope*scope;
|
||||
unsigned file_idx;
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
static int binary_param_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code == vpiParameter);
|
||||
|
||||
if (code == vpiLineNo) {
|
||||
return rfp->lineno;
|
||||
}
|
||||
|
||||
return binary_get(code, ref);
|
||||
}
|
||||
|
||||
static char* binary_param_get_str(int code, vpiHandle obj)
|
||||
{
|
||||
struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)obj;
|
||||
|
||||
assert(obj->vpi_type->type_code == vpiParameter);
|
||||
|
||||
if (code == vpiFile) { // Not implemented for now!
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
if (code == vpiFile) {
|
||||
return simple_set_rbuf_str(file_names[rfp->file_idx]);
|
||||
}
|
||||
|
||||
return generic_get_str(code, &rfp->scope->base, rfp->basename, NULL);
|
||||
}
|
||||
|
||||
@@ -457,7 +489,7 @@ static vpiHandle binary_param_handle(int code, vpiHandle obj)
|
||||
|
||||
static const struct __vpirt vpip_binary_param_rt = {
|
||||
vpiParameter,
|
||||
binary_get,
|
||||
binary_param_get,
|
||||
binary_param_get_str,
|
||||
binary_value,
|
||||
0,
|
||||
@@ -470,7 +502,8 @@ static const struct __vpirt vpip_binary_param_rt = {
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits,
|
||||
bool signed_flag)
|
||||
bool signed_flag,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
struct __vpiBinaryParam*obj = new __vpiBinaryParam;
|
||||
|
||||
@@ -480,6 +513,8 @@ vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits,
|
||||
obj->sized_flag = 0;
|
||||
obj->basename = name;
|
||||
obj->scope = vpip_peek_current_scope();
|
||||
obj->file_idx = (unsigned) file_idx;
|
||||
obj->lineno = (unsigned) lineno;
|
||||
|
||||
return &obj->base;
|
||||
}
|
||||
@@ -654,17 +689,33 @@ vpiHandle vpip_make_real_const(double value)
|
||||
struct __vpiRealParam : public __vpiRealConst {
|
||||
const char*basename;
|
||||
struct __vpiScope* scope;
|
||||
unsigned file_idx;
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
static int real_param_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiRealParam*rfp = (struct __vpiRealParam*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code == vpiParameter);
|
||||
|
||||
if (code == vpiLineNo) {
|
||||
return rfp->lineno;
|
||||
}
|
||||
|
||||
return real_get(code, ref);
|
||||
}
|
||||
|
||||
static char* real_param_get_str(int code, vpiHandle obj)
|
||||
{
|
||||
struct __vpiRealParam*rfp = (struct __vpiRealParam*)obj;
|
||||
|
||||
assert(obj->vpi_type->type_code == vpiParameter);
|
||||
|
||||
if (code == vpiFile) { // Not implemented for now!
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
if (code == vpiFile) {
|
||||
return simple_set_rbuf_str(file_names[rfp->file_idx]);
|
||||
}
|
||||
|
||||
return generic_get_str(code, &rfp->scope->base, rfp->basename, NULL);
|
||||
}
|
||||
|
||||
@@ -685,7 +736,7 @@ static vpiHandle real_param_handle(int code, vpiHandle obj)
|
||||
|
||||
static const struct __vpirt vpip_real_param_rt = {
|
||||
vpiParameter,
|
||||
real_get,
|
||||
real_param_get,
|
||||
real_param_get_str,
|
||||
real_value,
|
||||
0,
|
||||
@@ -697,7 +748,8 @@ static const struct __vpirt vpip_real_param_rt = {
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_real_param(char*name, double value)
|
||||
vpiHandle vpip_make_real_param(char*name, double value,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
struct __vpiRealParam*obj;
|
||||
|
||||
@@ -707,6 +759,8 @@ vpiHandle vpip_make_real_param(char*name, double value)
|
||||
obj->value = value;
|
||||
obj->basename = name;
|
||||
obj->scope = vpip_peek_current_scope();
|
||||
obj->file_idx = (unsigned) file_idx;
|
||||
obj->lineno = (unsigned) lineno;
|
||||
|
||||
return &obj->base;
|
||||
}
|
||||
|
||||
@@ -1,449 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com>
|
||||
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "compile.h"
|
||||
# include "vpi_priv.h"
|
||||
# include "memory.h"
|
||||
# include "statistics.h"
|
||||
# include <iostream>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <assert.h>
|
||||
|
||||
# include <stdio.h>
|
||||
|
||||
extern const char hex_digits[256];
|
||||
|
||||
static void memory_make_word_handles(struct __vpiMemory*rfp);
|
||||
|
||||
struct __vpiMemoryWord {
|
||||
struct __vpiHandle base;
|
||||
struct __vpiMemory*mem;
|
||||
struct __vpiDecConst index;
|
||||
};
|
||||
|
||||
struct __vpiMemory {
|
||||
struct __vpiHandle base;
|
||||
struct __vpiScope* scope;
|
||||
struct __vpiMemoryWord*words;
|
||||
vvp_memory_t mem;
|
||||
const char*name; /* Permanently allocated string. */
|
||||
struct __vpiDecConst left_range;
|
||||
struct __vpiDecConst right_range;
|
||||
struct __vpiDecConst word_left_range;
|
||||
struct __vpiDecConst word_right_range;
|
||||
|
||||
struct __vpiCallback*value_change_cb;
|
||||
};
|
||||
|
||||
struct __vpiMemWordIterator {
|
||||
struct __vpiHandle base;
|
||||
struct __vpiMemory*mem;
|
||||
unsigned next;
|
||||
};
|
||||
|
||||
static vpiHandle memory_get_handle(int code, vpiHandle obj)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)obj;
|
||||
|
||||
assert(obj->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch(code){
|
||||
case vpiLeftRange:
|
||||
return &(rfp->left_range.base);
|
||||
|
||||
case vpiRightRange:
|
||||
return &(rfp->right_range.base);
|
||||
|
||||
case vpiScope:
|
||||
return &rfp->scope->base;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpi_memory_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return (int)memory_word_count(rfp->mem);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char* memory_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
|
||||
if (code == vpiFile) { // Not implemented for now!
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
}
|
||||
return generic_get_str(code, &rfp->scope->base, rfp->name, NULL);
|
||||
}
|
||||
|
||||
static vpiHandle memory_scan(vpiHandle ref, int)
|
||||
{
|
||||
struct __vpiMemWordIterator*obj = (struct __vpiMemWordIterator*)ref;
|
||||
assert(ref->vpi_type->type_code == vpiIterator);
|
||||
|
||||
if (obj->next >= memory_word_count(obj->mem->mem)) {
|
||||
vpi_free_object(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return &obj->mem->words[obj->next++].base;
|
||||
}
|
||||
|
||||
static int mem_iter_free_object(vpiHandle ref)
|
||||
{
|
||||
free(ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_mem_iter_rt = {
|
||||
vpiIterator,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
memory_scan,
|
||||
&mem_iter_free_object
|
||||
};
|
||||
|
||||
|
||||
static vpiHandle memory_iterate(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
switch (code) {
|
||||
case vpiMemoryWord: {
|
||||
memory_make_word_handles(rfp);
|
||||
|
||||
struct __vpiMemWordIterator*res =
|
||||
(struct __vpiMemWordIterator*)
|
||||
calloc(1, sizeof(struct __vpiMemWordIterator));
|
||||
assert(res);
|
||||
res->base.vpi_type = &vpip_mem_iter_rt;
|
||||
res->mem = rfp;
|
||||
res->next = 0;
|
||||
return &(res->base);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vpiHandle memory_index(vpiHandle ref, int index)
|
||||
{
|
||||
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
|
||||
assert(ref->vpi_type->type_code==vpiMemory);
|
||||
|
||||
if (index >= (int)memory_word_count(rfp->mem))
|
||||
return 0;
|
||||
if (index < 0)
|
||||
return 0;
|
||||
|
||||
memory_make_word_handles(rfp);
|
||||
return &(rfp->words[index].base);
|
||||
}
|
||||
|
||||
//==============================
|
||||
|
||||
static vpiHandle memory_word_get_handle(int code, vpiHandle obj)
|
||||
{
|
||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)obj;
|
||||
assert(obj->vpi_type->type_code==vpiMemoryWord);
|
||||
|
||||
switch(code){
|
||||
case vpiLeftRange:
|
||||
return &(rfp->mem->word_left_range.base);
|
||||
|
||||
case vpiRightRange:
|
||||
return &(rfp->mem->word_right_range.base);
|
||||
|
||||
case vpiIndex:
|
||||
return &(rfp->index.base);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memory_word_get(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
||||
assert(ref->vpi_type->type_code==vpiMemoryWord);
|
||||
|
||||
switch (code) {
|
||||
case vpiSize:
|
||||
return memory_word_width(rfp->mem->mem);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static vpiHandle memory_word_put(vpiHandle ref, p_vpi_value val, int)
|
||||
{
|
||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
||||
assert(ref->vpi_type->type_code==vpiMemoryWord);
|
||||
|
||||
|
||||
/* Get the width of the memory, and the byte index of the
|
||||
first byte of the word. */
|
||||
unsigned width = memory_word_width(rfp->mem->mem);
|
||||
unsigned word_addr = rfp->index.value;
|
||||
|
||||
/* Addresses are converted to canonical form by offsetting the
|
||||
address by the lowest index. */
|
||||
long addr_off = memory_left_range(rfp->mem->mem, 0);
|
||||
if (memory_right_range(rfp->mem->mem, 0) < addr_off)
|
||||
addr_off = memory_right_range(rfp->mem->mem, 0);
|
||||
|
||||
assert(addr_off >= 0 && (unsigned) addr_off <= word_addr);
|
||||
word_addr -= addr_off;
|
||||
|
||||
/* Build up the word value from whatever format the user
|
||||
supplies. */
|
||||
vvp_vector4_t put_val (width);
|
||||
|
||||
switch (val->format) {
|
||||
case vpiVectorVal:
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
p_vpi_vecval cur = val->value.vector + (idx/32);
|
||||
int aval = (cur->aval >> (idx%32)) & 1;
|
||||
int bval = (cur->bval >> (idx%32)) & 1;
|
||||
|
||||
/* Check this bit value conversion. This is
|
||||
specifically defined by the IEEE1364 standard. */
|
||||
vvp_bit4_t bit;
|
||||
if (bval) {
|
||||
bit = aval? BIT4_Z : BIT4_X;
|
||||
} else {
|
||||
bit = aval? BIT4_1 : BIT4_0;
|
||||
}
|
||||
put_val.set_bit(idx, bit);
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiIntVal: {
|
||||
int cur = val->value.integer;
|
||||
for (unsigned idx = 0; idx < width; idx += 1) {
|
||||
vvp_bit4_t bit = (cur&1)? BIT4_1 : BIT4_0;
|
||||
put_val.set_bit(idx, bit);
|
||||
cur >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiBinStrVal: {
|
||||
char*str = val->value.str;
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
switch (str[width-idx-1]) {
|
||||
case '0':
|
||||
put_val.set_bit(idx, BIT4_0);
|
||||
break;
|
||||
case '1':
|
||||
put_val.set_bit(idx, BIT4_1);
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
put_val.set_bit(idx, BIT4_X);
|
||||
break;
|
||||
case 'z':
|
||||
case 'Z':
|
||||
put_val.set_bit(idx, BIT4_Z);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported value %c(%d).\n",
|
||||
str[width-idx-1], str[width-idx-1]);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiOctStrVal: {
|
||||
char*str = val->value.str;
|
||||
vpip_oct_str_to_vec4(put_val, str);
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiDecStrVal: {
|
||||
char*str = val->value.str;
|
||||
vpip_dec_str_to_vec4(put_val, str, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case vpiHexStrVal: {
|
||||
char*str = val->value.str;
|
||||
vpip_hex_str_to_vec4(put_val, str);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
cerr << "internal error: memory_word put_value format="
|
||||
<< val->format << endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
memory_set_word(rfp->mem->mem, word_addr, 0, put_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char* memory_word_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
assert(ref->vpi_type->type_code==vpiMemoryWord);
|
||||
|
||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
||||
|
||||
char number[32];
|
||||
sprintf(number, "%d", rfp->index.value);
|
||||
|
||||
return generic_get_str(code, &rfp->mem->scope->base, rfp->mem->name, number);
|
||||
}
|
||||
|
||||
static void memory_word_get_value(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
struct __vpiMemoryWord*rfp = (struct __vpiMemoryWord*)ref;
|
||||
assert(rfp->base.vpi_type->type_code==vpiMemoryWord);
|
||||
|
||||
unsigned width = memory_word_width(rfp->mem->mem);
|
||||
unsigned word_address = rfp->index.value;
|
||||
|
||||
vvp_vector4_t word_val = memory_get_word(rfp->mem->mem, word_address);
|
||||
|
||||
vpip_vec4_get_value(word_val, width, false /* never signed */, vp);
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_memory_rt = {
|
||||
vpiMemory,
|
||||
vpi_memory_get,
|
||||
memory_get_str,
|
||||
0,
|
||||
0,
|
||||
memory_get_handle,
|
||||
memory_iterate,
|
||||
memory_index,
|
||||
};
|
||||
|
||||
static const struct __vpirt vpip_memory_word_rt = {
|
||||
vpiMemoryWord,
|
||||
memory_word_get,
|
||||
memory_word_get_str,
|
||||
memory_word_get_value,
|
||||
memory_word_put,
|
||||
memory_word_get_handle,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
static void memory_make_word_handles(struct __vpiMemory*rfp)
|
||||
{
|
||||
if (rfp->words != 0)
|
||||
return;
|
||||
|
||||
unsigned word_count = memory_word_count(rfp->mem);
|
||||
|
||||
rfp->words = (struct __vpiMemoryWord*)
|
||||
calloc(word_count, sizeof (struct __vpiMemoryWord));
|
||||
|
||||
for (unsigned idx = 0 ; idx < word_count ; idx += 1) {
|
||||
struct __vpiMemoryWord*cur = rfp->words + idx;
|
||||
cur->base.vpi_type = &vpip_memory_word_rt;
|
||||
cur->mem = rfp;
|
||||
vpip_make_dec_const(&cur->index, idx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the callbacks for a memory value change. The memory.cc methods
|
||||
* call this method with the canonical address of the word that
|
||||
* changed, and we here run through all the callbacks for the memory,
|
||||
* passing the translated index through.
|
||||
*/
|
||||
void vpip_run_memory_value_change(vpiHandle ref, unsigned addr)
|
||||
{
|
||||
struct __vpiMemory*obj = reinterpret_cast<struct __vpiMemory*>(ref);
|
||||
|
||||
vvp_vector4_t word_val = memory_get_word(obj->mem, addr);
|
||||
unsigned width = memory_word_width(obj->mem);
|
||||
|
||||
for (struct __vpiCallback*cur=obj->value_change_cb;
|
||||
cur != 0 ; cur = cur->next) {
|
||||
|
||||
if (cur->cb_data.cb_rtn == 0)
|
||||
continue;
|
||||
|
||||
if (cur->cb_data.value)
|
||||
vpip_vec4_get_value(word_val, width, false, cur->cb_data.value);
|
||||
|
||||
cur->cb_data.index = addr;
|
||||
vpi_mode_flag = VPI_MODE_RWSYNC;
|
||||
(cur->cb_data.cb_rtn) (&cur->cb_data);
|
||||
vpi_mode_flag = VPI_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach the callback to the memory.
|
||||
*/
|
||||
void vpip_memory_value_change(struct __vpiCallback*cbh, vpiHandle ref)
|
||||
{
|
||||
struct __vpiMemory*obj = reinterpret_cast<struct __vpiMemory*>(ref);
|
||||
cbh->next = obj->value_change_cb;
|
||||
obj->value_change_cb = cbh;
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_memory(vvp_memory_t mem, const char*name)
|
||||
{
|
||||
struct __vpiMemory*obj = (struct __vpiMemory*)
|
||||
malloc(sizeof(struct __vpiMemory));
|
||||
count_vpi_memories += 1;
|
||||
|
||||
obj->base.vpi_type = &vpip_memory_rt;
|
||||
obj->scope = vpip_peek_current_scope();
|
||||
obj->mem = mem;
|
||||
obj->name = vpip_name_string(name);
|
||||
obj->value_change_cb = 0;
|
||||
|
||||
memory_attach_self(mem, &(obj->base));
|
||||
vpip_make_dec_const(&obj->left_range, memory_left_range(mem, 0));
|
||||
vpip_make_dec_const(&obj->right_range, memory_right_range(mem, 0));
|
||||
vpip_make_dec_const(&obj->word_left_range, memory_word_left_range(mem));
|
||||
vpip_make_dec_const(&obj->word_right_range,memory_word_right_range(mem));
|
||||
|
||||
obj->words = 0;
|
||||
|
||||
return &(obj->base);
|
||||
}
|
||||
|
||||
+10
-4
@@ -37,7 +37,7 @@ static s_vpi_error_info vpip_last_error = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
/*
|
||||
* The vpip_string function creates a constant string from the pass
|
||||
* input. This constant string is permanently allocate from an
|
||||
* input. This constant string is permanently allocated from an
|
||||
* efficient string buffer store.
|
||||
*/
|
||||
struct vpip_string_chunk {
|
||||
@@ -115,7 +115,7 @@ PLI_INT32 vpi_chk_error(p_vpi_error_info info)
|
||||
info->level = vpip_last_error.level;
|
||||
info->message = vpip_last_error.message;
|
||||
info->product = vpi_vlog_info.product;
|
||||
info->code = "";
|
||||
info->code = (char *) "";
|
||||
info->file = 0;
|
||||
info->line = 0;
|
||||
|
||||
@@ -863,10 +863,16 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope)
|
||||
*/
|
||||
if (scope) {
|
||||
/* Some implementations support either a module or a scope. */
|
||||
if (vpi_get(vpiType, scope ) == vpiScope) {
|
||||
switch (vpi_get(vpiType, scope)) {
|
||||
case vpiScope:
|
||||
hand = vpi_handle(vpiModule, scope);
|
||||
} else {
|
||||
break;
|
||||
case vpiModule:
|
||||
hand = scope;
|
||||
break;
|
||||
default:
|
||||
// Use vpi_chk_error() here when it is implemented.
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
hand = find_scope(name, NULL, 0);
|
||||
|
||||
+20
-12
@@ -22,7 +22,6 @@
|
||||
# include "vpi_user.h"
|
||||
# include "pointers.h"
|
||||
# include "vvp_net.h"
|
||||
# include "memory.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -142,11 +141,15 @@ struct __vpiCallback {
|
||||
// scheduled event
|
||||
struct sync_cb* cb_sync;
|
||||
|
||||
// The calback holder may use this for various purposes.
|
||||
long extra_data;
|
||||
|
||||
// Used for listing callbacks.
|
||||
struct __vpiCallback*next;
|
||||
};
|
||||
|
||||
extern struct __vpiCallback* new_vpi_callback();
|
||||
extern void delete_vpi_callback(struct __vpiCallback* ref);
|
||||
extern void callback_execute(struct __vpiCallback*cur);
|
||||
|
||||
struct __vpiSystemTime {
|
||||
@@ -165,6 +168,10 @@ struct __vpiScope {
|
||||
/* The scope has a name. */
|
||||
const char*name;
|
||||
const char*tname;
|
||||
unsigned file_idx;
|
||||
unsigned lineno;
|
||||
unsigned def_file_idx;
|
||||
unsigned def_lineno;
|
||||
/* The scope has a system time of its own. */
|
||||
struct __vpiSystemTime scoped_time;
|
||||
struct __vpiSystemTime scoped_realtime;
|
||||
@@ -304,12 +311,6 @@ extern void vpip_real_value_change(struct __vpiCallback*cbh,
|
||||
* the memory.
|
||||
*/
|
||||
|
||||
extern vpiHandle vpip_make_memory(vvp_memory_t mem, const char*name);
|
||||
extern void vpip_memory_value_change(struct __vpiCallback*cbh,
|
||||
vpiHandle ref);
|
||||
|
||||
extern void vpip_run_memory_value_change(vpiHandle ref, unsigned adr);
|
||||
|
||||
/*
|
||||
* These are the various variable types.
|
||||
*/
|
||||
@@ -366,7 +367,7 @@ struct __vpiSysTaskCall {
|
||||
signed vwid;
|
||||
class vvp_net_t*fnet;
|
||||
unsigned file_idx;
|
||||
unsigned line_no;
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
extern struct __vpiSysTaskCall*vpip_cur_task;
|
||||
@@ -386,7 +387,8 @@ struct __vpiStringConst {
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_string_const(char*text, bool persistent =true);
|
||||
vpiHandle vpip_make_string_param(char*name, char*value);
|
||||
vpiHandle vpip_make_string_param(char*name, char*value,
|
||||
long file_idx, long lineno);
|
||||
|
||||
struct __vpiBinaryConst {
|
||||
struct __vpiHandle base;
|
||||
@@ -399,7 +401,8 @@ struct __vpiBinaryConst {
|
||||
|
||||
vpiHandle vpip_make_binary_const(unsigned wid, const char*bits);
|
||||
vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits,
|
||||
bool signed_flag);
|
||||
bool signed_flag,
|
||||
long file_idx, long lineno);
|
||||
|
||||
struct __vpiDecConst {
|
||||
struct __vpiHandle base;
|
||||
@@ -415,7 +418,8 @@ struct __vpiRealConst {
|
||||
};
|
||||
|
||||
vpiHandle vpip_make_real_const(double value);
|
||||
vpiHandle vpip_make_real_param(char*name, double value);
|
||||
vpiHandle vpip_make_real_param(char*name, double value,
|
||||
long file_idx, long lineno);
|
||||
|
||||
/*
|
||||
* This one looks like a constant, but really is a vector in the current
|
||||
@@ -426,6 +430,8 @@ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag);
|
||||
|
||||
vpiHandle vpip_make_vthr_word(unsigned base, const char*type);
|
||||
|
||||
vpiHandle vpip_make_vthr_A(char*symbol, unsigned index);
|
||||
|
||||
/*
|
||||
* This function is called before any compilation to load VPI
|
||||
* modules. This gives the modules a chance to announce their
|
||||
@@ -462,7 +468,7 @@ extern vpiHandle vpip_build_vpi_call(const char*name,
|
||||
unsigned argc,
|
||||
vpiHandle*argv,
|
||||
long file_idx,
|
||||
long line_no);
|
||||
long lineno);
|
||||
|
||||
extern vthread_t vpip_current_vthread;
|
||||
|
||||
@@ -523,6 +529,8 @@ extern void vpip_oct_str_to_vec4(vvp_vector4_t&val, const char*str);
|
||||
extern void vpip_dec_str_to_vec4(vvp_vector4_t&val, const char*str, bool sign);
|
||||
extern void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str);
|
||||
|
||||
extern vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid);
|
||||
|
||||
extern void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
|
||||
bool signed_flag, s_vpi_value*vp);
|
||||
|
||||
|
||||
+9
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -34,8 +34,15 @@ static int real_var_get(int code, vpiHandle ref)
|
||||
|
||||
struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref;
|
||||
|
||||
if (code == vpiArray) {
|
||||
switch (code) {
|
||||
case vpiArray:
|
||||
return rfp->parent != 0;
|
||||
|
||||
case vpiSize:
|
||||
return 1;
|
||||
|
||||
case vpiLineNo:
|
||||
return 0; // Not implemented for now!
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -186,4 +193,3 @@ vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net)
|
||||
|
||||
return &obj->base;
|
||||
}
|
||||
|
||||
|
||||
+17
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -61,8 +61,11 @@ static int scope_get(int code, vpiHandle obj)
|
||||
assert(handle_is_scope(obj));
|
||||
|
||||
switch (code) {
|
||||
case vpiDefLineNo:
|
||||
return ref->def_lineno;
|
||||
|
||||
case vpiLineNo:
|
||||
return 0; // Not implemented for now!
|
||||
return ref->lineno;
|
||||
|
||||
case vpiTimeUnit:
|
||||
return ref->time_units;
|
||||
@@ -115,8 +118,12 @@ static char* scope_get_str(int code, vpiHandle obj)
|
||||
char buf[4096]; // XXX is a fixed buffer size really reliable?
|
||||
const char *p=0;
|
||||
switch (code) {
|
||||
case vpiDefFile:
|
||||
p = file_names[ref->def_file_idx];
|
||||
break;
|
||||
|
||||
case vpiFile:
|
||||
p = file_names[0]; // Not implemented for now!
|
||||
p = file_names[ref->file_idx];
|
||||
break;
|
||||
|
||||
case vpiFullName:
|
||||
@@ -316,7 +323,9 @@ static void attach_to_scope_(struct __vpiScope*scope, vpiHandle obj)
|
||||
* symbol table and the name is used to construct the actual object.
|
||||
*/
|
||||
void
|
||||
compile_scope_decl(char*label, char*type, char*name, const char*tname, char*parent)
|
||||
compile_scope_decl(char*label, char*type, char*name, const char*tname,
|
||||
char*parent, long file_idx, long lineno,
|
||||
long def_file_idx, long def_lineno)
|
||||
{
|
||||
struct __vpiScope*scope = new struct __vpiScope;
|
||||
count_vpi_scopes += 1;
|
||||
@@ -342,6 +351,10 @@ compile_scope_decl(char*label, char*type, char*name, const char*tname, char*pare
|
||||
|
||||
scope->name = vpip_name_string(name);
|
||||
scope->tname = vpip_name_string(tname);
|
||||
scope->file_idx = (unsigned) file_idx;
|
||||
scope->lineno = (unsigned) lineno;
|
||||
scope->def_file_idx = (unsigned) def_file_idx;
|
||||
scope->def_lineno = (unsigned) def_lineno;
|
||||
scope->intern = 0;
|
||||
scope->nintern = 0;
|
||||
scope->threads = 0;
|
||||
@@ -414,4 +427,3 @@ void vpip_attach_to_current_scope(vpiHandle obj)
|
||||
{
|
||||
attach_to_scope_(current_scope, obj);
|
||||
}
|
||||
|
||||
|
||||
+33
-17
@@ -136,6 +136,15 @@ static int signal_get(int code, vpiHandle ref)
|
||||
case vpiArray:
|
||||
return rfp->parent != 0;
|
||||
|
||||
case vpiIndex: // This only works while we have a single index.
|
||||
if (rfp->parent) {
|
||||
s_vpi_value vp;
|
||||
vp.format = vpiIntVal;
|
||||
vpi_get_value(rfp->id.index, &vp);
|
||||
return vp.value.integer;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
case vpiSize:
|
||||
if (rfp->msb >= rfp->lsb)
|
||||
return rfp->msb - rfp->lsb + 1;
|
||||
@@ -636,6 +645,27 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
|
||||
? (rfp->msb - rfp->lsb + 1)
|
||||
: (rfp->lsb - rfp->msb + 1);
|
||||
|
||||
|
||||
vvp_vector4_t val = vec4_from_vpi_value(vp, wid);
|
||||
|
||||
/* If this is a vpiForce, then instead of writing to the
|
||||
signal input port, we write to the special "force" port. */
|
||||
int dest_port = 0;
|
||||
if (flags == vpiForceFlag)
|
||||
dest_port = 2;
|
||||
|
||||
/* This is the destination that I'm going to poke into. Make
|
||||
it from the vvp_net_t pointer, and assume a write to
|
||||
port-0. This is the port where signals receive input. */
|
||||
vvp_net_ptr_t destination (rfp->node, dest_port);
|
||||
|
||||
vvp_send_vec4(destination, val);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid)
|
||||
{
|
||||
vvp_vector4_t val (wid, BIT4_0);
|
||||
|
||||
switch (vp->format) {
|
||||
@@ -682,27 +712,13 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
|
||||
|
||||
default:
|
||||
fprintf(stderr, "vvp internal error: put_value: "
|
||||
"value type %u not implemented."
|
||||
" Signal is %s in scope %s\n",
|
||||
vp->format, vpi_get_str(vpiName, ref), rfp->scope->name);
|
||||
"value type %u not implemented here.\n",
|
||||
vp->format);
|
||||
assert(0);
|
||||
|
||||
}
|
||||
|
||||
/* If this is a vpiForce, then instead of writing to the
|
||||
signal input port, we write to the special "force" port. */
|
||||
int dest_port = 0;
|
||||
if (flags == vpiForceFlag)
|
||||
dest_port = 2;
|
||||
|
||||
/* This is the destination that I'm going to poke into. Make
|
||||
it from the vvp_net_t pointer, and assume a write to
|
||||
port-0. This is the port where signals receive input. */
|
||||
vvp_net_ptr_t destination (rfp->node, dest_port);
|
||||
|
||||
vvp_send_vec4(destination, val);
|
||||
|
||||
return ref;
|
||||
return val;
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_reg_rt = {
|
||||
|
||||
+4
-5
@@ -79,7 +79,7 @@ static int systask_get(int type, vpiHandle ref)
|
||||
return rfp->scope->time_units;
|
||||
|
||||
case vpiLineNo:
|
||||
return rfp->line_no;
|
||||
return rfp->lineno;
|
||||
|
||||
default:
|
||||
return vpiUndefined;
|
||||
@@ -98,7 +98,7 @@ static int sysfunc_get(int type, vpiHandle ref)
|
||||
return rfp->vwid;
|
||||
|
||||
case vpiLineNo:
|
||||
return rfp->line_no;
|
||||
return rfp->lineno;
|
||||
|
||||
default:
|
||||
return vpiUndefined;
|
||||
@@ -495,7 +495,7 @@ struct __vpiUserSystf* vpip_find_systf(const char*name)
|
||||
vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||
class vvp_net_t*fnet,
|
||||
unsigned argc, vpiHandle*argv,
|
||||
long file_idx, long line_no)
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
struct __vpiUserSystf*defn = vpip_find_systf(name);
|
||||
if (defn == 0) {
|
||||
@@ -561,7 +561,7 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||
obj->vwid = vwid;
|
||||
obj->fnet = fnet;
|
||||
obj->file_idx = (unsigned) file_idx;
|
||||
obj->line_no = (unsigned) line_no;
|
||||
obj->lineno = (unsigned) lineno;
|
||||
obj->userdata = 0;
|
||||
|
||||
compile_compiletf(obj);
|
||||
@@ -641,4 +641,3 @@ void* vpi_get_userdata(vpiHandle ref)
|
||||
|
||||
return rfp->userdata;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,9 @@ static int vthr_vec_get(int code, vpiHandle ref)
|
||||
case vpiSigned:
|
||||
return rfp->signed_flag;
|
||||
|
||||
case vpiConstType:
|
||||
return vpiBinaryConst; // If this is a constant it is Binary.
|
||||
|
||||
case vpiSize:
|
||||
return rfp->wid;
|
||||
|
||||
|
||||
+8
-73
@@ -401,6 +401,14 @@ void vthread_schedule_list(vthread_t thr)
|
||||
schedule_vthread(thr, 0);
|
||||
}
|
||||
|
||||
bool of_ABS_WR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned dst = cp->bit_idx[0];
|
||||
unsigned src = cp->bit_idx[1];
|
||||
|
||||
thr->words[dst].w_real = fabs(thr->words[src].w_real);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_AND(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
@@ -720,28 +728,6 @@ bool of_ASSIGN_X0(vthread_t thr, vvp_code_t cp)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* %assign/mv <memory>, <delay>, <bit>
|
||||
* This generates an assignment event to a memory. Index register 0
|
||||
* contains the width of the vector (and the word) and index register
|
||||
* 3 contains the canonical address of the word in memory.
|
||||
*/
|
||||
bool of_ASSIGN_MV(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned wid = thr->words[0].w_int;
|
||||
unsigned off = thr->words[1].w_int;
|
||||
unsigned adr = thr->words[3].w_int;
|
||||
|
||||
assert(wid > 0);
|
||||
|
||||
unsigned delay = cp->bit_idx[0];
|
||||
unsigned bit = cp->bit_idx[1];
|
||||
|
||||
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
||||
|
||||
schedule_assign_memory_word(cp->mem, adr, off, value, delay);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_BLEND(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
assert(cp->bit_idx[0] >= 4);
|
||||
@@ -2306,38 +2292,6 @@ bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t cp)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %load/mv <bit>, <mem-label>, <wid> ;
|
||||
*
|
||||
* <bit> is the thread bit address for the result
|
||||
* <mem-label> is the memory device to access, and
|
||||
* <wid> is the width of the word to read.
|
||||
*
|
||||
* The address of the word in the memory is in index register 3.
|
||||
*/
|
||||
bool of_LOAD_MV(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned bit = cp->bit_idx[0];
|
||||
unsigned wid = cp->bit_idx[1];
|
||||
unsigned adr = thr->words[3].w_int;
|
||||
|
||||
vvp_vector4_t word = memory_get_word(cp->mem, adr);
|
||||
|
||||
if (word.size() != wid) {
|
||||
fprintf(stderr, "internal error: mem width=%u, word.size()=%u, wid=%u\n",
|
||||
memory_word_width(cp->mem), word.size(), wid);
|
||||
}
|
||||
assert(word.size() == wid);
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1, bit += 1) {
|
||||
vvp_bit4_t val = word.value(idx);
|
||||
thr_put_bit(thr, bit, val);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* %load/nx <bit>, <vpi-label>, <idx> ; Load net/indexed.
|
||||
*
|
||||
@@ -3481,25 +3435,6 @@ bool of_SET_AV(vthread_t thr, vvp_code_t cp)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This implements the "%set/mv <label>, <bit>, <wid>" instruction. In
|
||||
* this case, the <label> is a memory label, and the <bit> and <wid>
|
||||
* are the thread vector of a value to be written in.
|
||||
*/
|
||||
bool of_SET_MV(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned bit = cp->bit_idx[0];
|
||||
unsigned wid = cp->bit_idx[1];
|
||||
unsigned off = thr->words[1].w_int;
|
||||
unsigned adr = thr->words[3].w_int;
|
||||
|
||||
/* Make a vector of the desired width. */
|
||||
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
||||
|
||||
memory_set_word(cp->mem, adr, off, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
|
||||
|
||||
+12
-3
@@ -882,20 +882,29 @@ class vvp_vpi_callback {
|
||||
vvp_vpi_callback();
|
||||
virtual ~vvp_vpi_callback();
|
||||
|
||||
void run_vpi_callbacks();
|
||||
virtual void run_vpi_callbacks();
|
||||
void add_vpi_callback(struct __vpiCallback*);
|
||||
|
||||
virtual void get_value(struct t_vpi_value*value) =0;
|
||||
|
||||
private:
|
||||
struct __vpiCallback*vpi_callbacks_;
|
||||
};
|
||||
|
||||
class vvp_vpi_callback_wordable : public vvp_vpi_callback {
|
||||
public:
|
||||
vvp_vpi_callback_wordable();
|
||||
~vvp_vpi_callback_wordable();
|
||||
|
||||
void run_vpi_callbacks();
|
||||
void attach_as_word(class __vpiArray* arr, unsigned long addr);
|
||||
|
||||
private:
|
||||
struct __vpiCallback*vpi_callbacks_;
|
||||
class __vpiArray* array_;
|
||||
unsigned long array_word_;
|
||||
};
|
||||
|
||||
class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback {
|
||||
class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback_wordable {
|
||||
|
||||
public:
|
||||
vvp_fun_signal_base();
|
||||
|
||||
+2
-2
@@ -84,7 +84,7 @@ static void __compile_var(char*label, char*name,
|
||||
define_functor_symbol(label, node);
|
||||
|
||||
vpiHandle obj = 0;
|
||||
if (! local_flag) {
|
||||
if (! local_flag && !array) {
|
||||
/* Make the vpiHandle for the reg. */
|
||||
obj = (signed_flag > 1) ?
|
||||
vpip_make_int(name, msb, lsb, node) :
|
||||
@@ -102,7 +102,7 @@ static void __compile_var(char*label, char*name,
|
||||
// it is attached to the addressed array.
|
||||
if (array) {
|
||||
assert(!name);
|
||||
array_attach_word(array, array_addr, obj);
|
||||
if (obj) array_attach_word(array, array_addr, obj);
|
||||
}
|
||||
free(label);
|
||||
if (name) free(name);
|
||||
|
||||
Reference in New Issue
Block a user