Compare commits

..
Author SHA1 Message Date
Stephen Williams d1daf6733f Allow VPI callbacks to var array words.
Functions like $monitor need to attach callbacks to array words if
those words are to be monitored. Have the array hold all the callbacks
for words in the array, under the assumption that the monitored words
are sparse.
2008-05-20 18:30:56 -07:00
Stephen Williams 007056d671 Remove last vestiges of the the .mem structures.
Before the .array support, we had .mem nodes. These are long since
removed because the arrays to all the jobs of the .mem nodes.
2008-05-20 16:57:50 -07:00
Stephen Williams 2dcb1514a2 Add support for passing array words to system tasks.
Array words don't have a vpiHandle with a label, so the %vpi_call
needs a special syntac for arguments that reference array words.
This syntax creates an array word reference that persists and can
be used at a VPI object by system tasks.
2008-05-20 16:21:54 -07:00
Stephen Williams d71a1cb9c1 Fix non-blocking assign to part select of memory word.
Memory words may have part selects assigned, but the code messed up
the testing for the validity of the part select base. This fixes do
detect constant bases so that base validity tests are handled at
compile time.
2008-05-20 11:51:17 -07:00
Stephen Williams 4c3d764a86 Add support for array iterator scan.
With the array vals_words method of getting compact vpiHandles to words
of a var array, it becomes easy to support the array iterators.
2008-05-19 19:04:42 -07:00
Stephen Williams 3189efacbc Fix memory word offset errors
Fix handling writing to a word part select,
Fix readmemb calculations for the word size.
2008-05-19 18:05:27 -07:00
Stephen Williams 96ec4b7eba Fix array inputs to mux devices.
The draw_input_from_net function was being used to access words of
a var array, which doesn't work. Have the draw_input_from_net punt
on that case, and by the way the mux inputs don't need to use that
function, instead they should use the general draw_net_input function
to get the input labels.
2008-05-19 17:37:23 -07:00
Stephen Williams 07c8fce530 Careful that select signal does not try to select reg words directly. 2008-05-19 11:44:03 -07:00
Stephen Williams 9a00829ee4 Use ivl_signal_dimensions to detect that signal is an array.
It is possible for an array to have 1 word in it, so using the array
count to detect an array is incorrect. Use the ivl_signal_dimensions
function, which is there exactly for that purpose.
2008-05-19 11:31:40 -07:00
Stephen Williams 680d3c8a3e Assign to variable array words using array indexing.
The non-array set statements no longer work on array words. Handle
the various cases properly.
2008-05-19 11:18:04 -07:00
Stephen Williams 6632e4c33b Allow ports to be declared before arrays.
It is possible for the code generator to create .array/port objects
before the .array object that the port refereces, so use the resolv_list
to arrange for binding during cleanup.
2008-05-16 19:06:12 -07:00
Stephen Williams 42913e46b8 Fix non-blocking assign to variable arrays.
Non-blocking assignment with constant index was still trying to access
the vpi handle directly.
2008-05-16 16:33:04 -07:00
Stephen Williams e2ad59466a Create handles to access words of an array, if needed.
VPI code may need to access words of a variable array. If so, create
a compact handle format that gains that access with minimal pain.
2008-05-16 16:20:22 -07:00
Stephen Williams 0cd946a7af Remove a useless call to vpi_iterate. 2008-05-16 16:18:07 -07:00
Stephen Williams 102cbb67b4 Rework variable arrays to not have vpi handles for every word.
Save tons of space per memory word by not creating a vpi handle for
each and every word of a variable array. (Net arrays still get a
vpiHandle for every word.) The consequence of this is that all
accesses to a variable array need to go through the indexing.

This commit handles the most common places where this impacts, but
there are still problems.
2008-05-16 10:38:32 -07:00
Stephen Williams 3113392594 Minor improvement to mingw.txt 2008-05-15 16:59:08 -07:00
Cary R 72b4256872 Return 0 when vpi_handle_by_name() is called with an unsupported object.
vpi_handle_by_name() was assuming it was always given a valid scope
object. In the context of vpi_chk_error() this is not required and
some users use/abuse the interface by calling the function with invalid
objects expecting a 0 return value. This patch adds an explicit check
for the supported types vpiScope and as an extension vpiModule.
Anything else should be flagged as an error once we have vpi_chk_error()
implemented, but for now it just returns 0.
2008-05-15 10:46:53 -07:00
Cary R ca880c73fc Fix $ungetc() arguments to be in the correct order.
The arguments to $ungetc() were backwards! This patch fixes that
and adds a bit more checking to the compile_tf routine. It still
needs more work, but that can wait for the major system function
clean up I have planned when I can find the time.
2008-05-15 10:38:41 -07:00
Stephen Williams cef0d0071b Handle declarations within scopes under while and repeat statements.
The PWile and PRepeat statements need elaborate_sig() methods to recurse
into the contained statements.
2008-05-14 20:19:51 -07:00
Cary R 2934ceb548 A constant thread vector is binary.
Thread vectors can be treated as constants the problem
was that they did not set a constant type. They now
return vpiBinaryConst.
2008-05-14 11:56:50 -07:00
Stephen Williams 6b908aeec3 Arithmetic operands can do unsigned work and have signed result.
It is a quirk of the $signed() system function that the argument
is converted to signed, but the operation that is performed is
not changed. So arithmetic operators on unsigned arguments inside
a $signed() expression still perform unsigned arithmetic.
2008-05-14 11:51:53 -07:00
Cary R a6dd97a5a6 Fix comparisons that use sb_to_idx()
A recent change to sb_to_idx() made it return a signed value
where it previously returned an unsigned value. This patch adds
explicit casts to remove the two signed vs unsigned comparison
warning messages.
2008-05-13 11:04:56 -07:00
Stephen Williams 2b4f7f8aed Revert "One more signed vs unsigned comparison fix"
This reverts commit 3c5bf034ca.
A latter patch is more complete.
2008-05-13 10:58:33 -07:00
Cary R add84b153c Make sure stringify_flag is initialized.
stringify_flag should not be used uninitialized.
Found with valgrind.
2008-05-13 10:50:59 -07:00
Larry Doolittle 3c5bf034ca One more signed vs unsigned comparison fix
Fix
  elab_expr.cc:1561: warning: comparison between signed and unsigned integer expressions
caused by revised prototype of NetNet::sb_to_idx() in
 commit dfb7bf5211
2008-05-12 16:29:10 -07:00
Stephen Williams 84a7efdb4f Merge branch 'verilog-ams' 2008-05-09 17:46:45 -07:00
Stephen Williams dfb7bf5211 Handle part selects of nets that fall of the ends of the identifier.
The Verilog LRM specifies that it is legal to give constant part
selects that are beyond the bounds of the identifier being selected.
But elaboration was flagging that as an error. This patch changes it
to a warning, and handles the cases by generating 'bx bits as needed.
2008-05-09 17:42:37 -07:00
Stephen Williams a33619a0f5 Properly pad results of function calls.
The elaborator improperly allowed user function call nodes to take on
the expression width requested of them. The result was that generated
code had junk pad bits in certain cases.
2008-05-09 15:25:42 -07:00
Stephen Williams a1495bb007 Unary minus of a constant does make the number signed.
It is wrong to assume that the result of a unary minus is signed.
Doing so can cause incorrect results in subsequent math.
2008-05-09 14:18:39 -07:00
Stephen Williams 8e1f22cd82 AC_CHECK_FUNCS_ONCE is a little too modern for many uses. 2008-05-09 09:55:41 -07:00
Stephen Williams db10de1a6a Fix calculation of XOR when z is present
When calculating 0^z with constant arguments, make sure the result is
x. This problem only happens when the arguments are constants and the
expression is calculated at compile time.
2008-05-09 09:16:11 -07:00
Stephen Williams bbed408d68 When padding logic constants, sign extend x/z properly.
If there is an x or z bin in the sign position of a logic number to
be padded, pad with the x or z, not zero.
2008-05-09 08:25:25 -07:00
Stephen Williams ba3660b948 Merge branch 'master' into verilog-ams 2008-05-08 19:56:11 -07:00
Stephen Williams 73dcace781 Prevent macro expand in strings, and add a stringify syntax
Verilog does not allow macro expansion in strings, and that's that.
But sometimes people want strings of a macro expansion, so add a
stringify syntax that does the trick.
2008-05-08 18:43:07 -07:00
Stephen Williams fd3ca037aa Document the __VAMS_ENABLE__ macro. 2008-05-08 10:28:22 -07:00
Stephen Williams 2d068ca89f Add support for scaled real numbers.
Verilog-AMS supports scaled real numbers, where the "e<N>" (scientific
notation) is replaced with engineering scales from "a" (atto-) to
m (milli-) and "K" (kilo-) to "T" (tera-). This syntax can be handled
way down in the lexor.
2008-05-07 22:11:19 -07:00
Stephen Williams dea1161c7e Merge branch 'verilog-ams' 2008-05-07 17:50:56 -07:00
Stephen Williams 3a61b94e98 Realign generation flags to correspond to IEEE1364 nomenclature.
IEEE1364 has specific names for the various generations of Verilog that
are supported. Icarus Verilog should stick to those names for selection
the language feature set.

In the process, the extensions that were tied to the 2x generations
are pulled out out and given their own enable flags. The makes all the
feature control more regular and understandable.
2008-05-07 17:46:56 -07:00
Cary R 3a8a6976e1 Add $vvp_cpu_wordsize function
This patch adds a new system function $vvp_cpu_wordsize. It returns
the size of the underlying CPU word (long) in bits. This function
can be used to write fully portable tests for the test suite. Other
functions will be added as needed.
2008-05-07 09:42:02 -07:00
Stephen Williams 6cc244766c Fix build error branching around initializations. 2008-05-07 07:31:01 -07:00
Stephen Williams 6e3ec755e2 Define __VAMS_ENABLE__ when verilog-amd i enabled. 2008-05-06 22:34:48 -07:00
Stephen Williams ca517b5519 Handle corner cases of abs(), min() and max()
The abs() function needs to be able to turn -0.0 into 0.0. This proved
to be too clunky (and perhaps impossible) to do with tests and jumps,
so add an %abs/wr opcode to do it using fabs().

The min/max functions need to take special care with the handling
of NaN operands. These matter, so generate the extra code to handle
them.
2008-05-06 22:19:59 -07:00
Stephen Williams 10ab5cf698 Merge branch 'verilog-ams' 2008-05-06 21:00:12 -07:00
Stephen Williams 523de1b69c Handle the abs() function in net context.
In net context we have to create a node that does the abs() function
for us. Elaborate that node and handle it all the way down to vvp.
2008-05-06 20:37:00 -07:00
Stephen Williams 3e591f730e sign extended expressions are signed.
Fix when sign extending an expression that the result is also signed.
This bug caused some arithmetic operations (with extended arguments)
to not notice that they are signed.

Also be more robust in noticing that comparisons are signed and should
generate the right code.
2008-05-06 13:27:04 -07:00
Cary R 34e90bb3a6 Allow genvars to also be constants.
This patch adds genvars to the list of constant values.
2008-05-06 07:35:23 -07:00
Cary R 4f8b91e65c Add file and line information for parameters, etc.
This patch adds file and line information for parameters and
local parameters. It also adds file/line stubs for signals in
the tgt-* files. It adds the pform code needed to eventually
do genvar checks and passing of genvar file/line information.
It verifies that a genvar does not have the same name as a
parameter/local parameter.
2008-05-06 07:14:27 -07:00
Stephen Williams e91243e1c6 Elaborate abs() is continuous assign expressions.
In continuous assign expressions, the abs() operator can't easily be
burried in generic unary handling, so add the IVL_LPM_ABS type and
generate it as needed.
2008-05-05 22:00:39 -07:00
Stephen Williams 5484ee1732 Include va_math if compiling Verilog-AMS
The va_math module implements functions that are optional in base
Verilog but included in Verilog-AMS. So automatically include the
module if -gverilog-ams is given.
2008-05-05 19:26:17 -07:00
Stephen Williams a43f336c6c Include va_math if compiling Verilog-AMS
The va_math module implements functions that are optional in base
Verilog but included in Verilog-AMS. So automatically include the
module if -gverilog-ams is given.
2008-05-04 22:10:54 -07:00
Stephen Williams cc7187c172 Add support for abs() in logic threads.
Add the code generator code to handle the abs() function in signed
logic. Handle some of the interesting special cases as well.
2008-05-04 22:00:01 -07:00
Stephen Williams d60df2d75b Implement abs/min/max operators for real values.
Implement in behavioral the abs/min/max operators for real values.
The parser treats these builtin functions as operators, unary or
binary, and elaborates them appropriately.

Also add enough code generator support to handle real valued expressions
in thread context.
2008-05-03 21:54:42 -07:00
Stephen Williams 6d433364ac Fix some bugs with passing -gverilog-ams to the ivl core. 2008-05-03 21:51:47 -07:00
Stephen Williams bbc80a84a6 Rename $log to $log10.
Verilog-2005 defines the base-10 log function to be $log10. This makes
sense because in C the log() function is the natural log. So add the
$log10 function.

Since there may be legacy code that uses the $log function, leave it
defined, but we should consider at least printing a warning when the
$log function is used.
2008-05-03 18:29:52 -07:00
Stephen Williams c993fb8325 Handle Traditional Verilog-A math functions
Verilog-AMS recommends that users use the system-function style
math functions, but supports traditional style math functions for
portability. Add the keywords and parse the traditional Verilog-A
functions, and handle them as calls to the equivilent system
function.
2008-05-03 18:05:51 -07:00
Stephen Williams f662d76b2e Add infrastructure for enabling Verilog-AMS
Add the -gverilog-ams flag to the driver, and the begin_keywords support
for VAMS-2.3 keywords. With this, the infrastructure is in place to
start pulling in features from Verilog-AMS.
2008-05-02 16:28:48 -07:00
Stephen Williams 0c29e540ea Check ketwords against active keyword subset mask.
The begin_keywords directives manage a mask of keyword sets that are
active at a given moment. This patch makes the lexor actually test
the given keyword against the mask. If it matches, return the keyword
id, if it is disabled then it is an IDENTIFIER.
2008-05-02 15:29:09 -07:00
Stephen Williams 1a8be6d28c Merge branch 'master' of ssh://[email protected]/home/u/icarus/steve/git/verilog 2008-05-02 14:55:49 -07:00
Stephen Williams 6491c5d43c Sort changelog for SuSE
The RPM program for SUSE is picky about the order of entries in the
changelog section.
2008-05-02 14:55:26 -07:00
GuntherDannoritzer a319939573 Fix up verilog.spec and root Makefile.in for package managers.
Package builders/managers find the DESTDIR variable convenient for
installing into a temporary target for building a package. This adds
the DESTDIR varilable to the root makefile.

Also, clean up the verilog.spec file to reduce redundancy so that
maintence for releases is easier.
2008-05-01 21:54:34 -07:00
Cary R 9db9aa4ccb Allow zero width replications only in a concatenation.
1364-2001 does not allow a replication count of zero, but
1364-2005 allows them when the replication is enclosed in
a concatenation with other valid bits. This patch adds
code to perform these checks for procedural expressions.
Because of the NetNet object must have a width greater
than zero a replication used in a continuous assignment
can never have a count of zero.
2008-05-01 20:33:04 -07:00
Larry Doolittle cb5260b2ce minor improvements to scripts/MAKE_SNAPSHOT.sh
could still use more love setting defaults and handling errors
2008-05-01 20:23:30 -07:00
Cary R c0d3bb370f Clean up some VPI issues.
This patch makes sure that objects either support vpiFile
and vpiLineNo or adds dummy code so that a runtime error
will not occur when accessing these properties. It also
returns 1 for the size of real variables and adds a
simplified vpiIndex that matches the Memory interface.
2008-05-01 20:18:59 -07:00
Larry Doolittle b99206ac8e avoid two unnecesary compile-time warnings 2008-05-01 18:34:03 -07:00
Stephen Williams 149bfa05d8 Support for the begin_keywords directive.
The begin_keywords directive allows the source code to select keyword
subsets so that a bit of code that uses identifiers that class with a
newer version of the standard can still be compiled.
2008-04-30 22:07:09 -07:00
Cary R 86a4025b58 Push file and line information for scopes to the runtime.
This patch adds code to push the file and line information
for scope objects (modules, functions, tasks, etc.) to the
runtime. For modules, this includes the definition fields.
2008-04-29 21:51:34 -07:00
Stephen Williams 2a5948d704 Add va_math.txt based on the README from the va_math submission. 2008-04-29 21:34:35 -07:00
Stephen Williams f5263c9447 Add the va_math module and constants.vams include file.
The va_math.vpi module implements systen-function versions of the
Verilog-A math functions. This library was contributed by Cary R.

Also add the constants.vams include file. This is pretty much
direct from the Verilog-AMS LRM.
2008-04-29 21:20:39 -07:00
95 changed files with 3396 additions and 2169 deletions
+24 -21
View File
@@ -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)
+5 -2
View File
@@ -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&);
+6 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+43
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+9
View File
@@ -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);
+3
View File
@@ -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*);
+8
View File
@@ -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
+27
View File
@@ -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
View File
@@ -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)
{
+98 -12
View File
@@ -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
View File
@@ -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;
}
+61 -6
View File
@@ -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;
}
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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:
+63 -3
View File
@@ -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_;
+224 -26
View File
@@ -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;
}
+13 -6
View File
@@ -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;
}
+9 -10
View File
@@ -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
View File
@@ -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;
}
+4 -4
View File
@@ -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
View File
@@ -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)
+54
View File
@@ -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_;
+40
View File
@@ -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) {
+17
View File
@@ -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
+6
View File
@@ -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() << "): "
+1
View File
@@ -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
View File
@@ -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:
+30
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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));
+41
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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;
+67
View File
@@ -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
View File
@@ -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
View File
@@ -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
};
+1
View File
@@ -14,3 +14,4 @@ $dist_poisson vpiSysFuncInt
$dist_chi_square vpiSysFuncInt
$dist_t vpiSysFuncInt
$dist_erlang vpiSysFuncInt
$vvp_cpu_wordsize vpiSysFuncInt
+372
View File
@@ -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
};
+32
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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)
+35
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4
View File
@@ -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
View File
@@ -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; }
-29
View File
@@ -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,
-6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
-449
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);