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
Stephen Williams f95a6fed14 Prepare for snapshot 20080429 2008-04-29 12:03:22 -07:00
Cary R 436e2fca13 Add ifnone functionality.
This patch adds ifnone functionality. It does not produce an
error when both an ifnone and an unconditional simple module
path are given. For this case the ifnone delays are ignored.
2008-04-29 11:55:32 -07:00
Stephen Williams 64c92f9fdd A script for making snapshots
Include in git a script for making snapshots. This script makes a
bundle that can compile outside of git.
2008-04-28 21:54:09 -07:00
Cary R 603ca0f2de Add better error recovery for failed task/function definition.
This patch does a better job of recovering from an error in a
task or function definition. This prevents the compiler from
printing many irrelevant error messages.
2008-04-27 21:30:23 -07:00
Cary R efba4bfd09 Allow multiple ports in single ANSI decl for tasks and functions
This patch adds the functionality to tasks/functions to handle the
declaration of multiple ports using a single ANSI declaration. It
also deletes the old range vector before it adds the new one. The
tasks and functions are different than modules so we need to copy
the range for them.
2008-04-27 21:26:17 -07:00
Cary R 785aad94c5 Ignore a few more compiler directives.
This patch adds `default_decay_time, `default_trireg_strength,
`delay_mode_zero and `line as ignored compiler directives.
2008-04-27 21:18:21 -07:00
Cary R ffbf37b06b Add vpiScalarVal to signal_put_value().
This patch adds functionality for vpiScalarVal to signal_put_value().
It also factors out the scalar to bit4 code from vpiVectorVal.
2008-04-27 21:11:12 -07:00
Stephen Williams c3ac01d31b Make casts from double to unsigned bits portable.
Several places in Icarus Verilog try to get the bits of the integer
part of a double by casting to unsigned or unsigned long. But that
causes some compilers to generate smart code that converts all values
less then 0 to 0, even though we are after the bits, not the math
value. So be careful to do this cast only to non-negative values and
uminus the bits if necessary to get exactly what we want.

Signed-off-by: Stephen Williams <[email protected]>
2008-04-27 18:21:32 -07:00
Stephen Williams 81e12bf7f6 Handle multiple active specify delays.
Fix handling of cases where multiple specified delays are activated
for a given output. Need to apply the standard selection criteria
that gets the minimum value.
2008-04-25 17:17:51 -07:00
Stephen Williams abaab602bc Fix >= compare not detecting right X bits.
Oops, never properly checking that the right value has XZ bits.
2008-04-24 11:05:11 -07:00
Stephen Williams bd170d05ad optimize vvp_vector4_t magnitude compare and bitwise not.
Update the magnitide compare and bitwise not operators to use
optimized methods where possible.
2008-04-23 16:50:22 -07:00
Stephen Williams 7b81eb3494 Optimize the SUB instruction
The %sub instruction didn't have the efficent implementation that
the %add instructions used. Update subtraction to use the array
method, so that it gets the same performance benefits.
2008-04-23 14:03:52 -07:00
Stephen Williams b775d178d2 More efficient way to set arithmetic results into vector4.
The vvp_vector4_t often receives the results of vector arithmetic.
Add an optimized method for setting that data into the vector. Take
into account that arithmetic results have no X/Z bits, etc.
2008-04-23 13:50:05 -07:00
Stephen Williams 10ea9904f1 Clean up more vvp_bit4_t encoding dependencies. 2008-04-23 11:16:24 -07:00
Stephen Williams e7d463704c The inputs to logical and/or are condition expressions.
Logical and/or take as inputs condition expressions, which are scalar
expressions. Be sure to reduce vectors using proper logic to get the
right condition value.
2008-04-22 21:03:18 -07:00
Cary R c38e8182c2 Add checks that verify an always statement has delay.
This patch adds check to determine if an always block has delay
in it or not. If there is no delay a runtime infinite loop will
occur. For the indeterminate case it will print a warning message
if the new -Winfloop flag is given. This flag is not part of the
-Wall check!
2008-04-22 19:53:23 -07:00
Cary R 7b705a0212 Generate mixed real/vector expressions when needed.
When generating a real expression you can have bits of the
expression that use vector only operands. When this happens
evaluate that part of the expression as a vector and then
convert it to a real value.
2008-04-22 19:42:57 -07:00
Stephen Williams 5ddd35565f Protect left shift from shifting too far.
On some systems, 1UL<<X will make a mess if X is the size of
an unsigned long. This especially seems to be a problem on i386
systems. Protect those shifts in the vvp_net.cc.
2008-04-22 17:31:08 -07:00
Stephen Williams a12a6d925a Fix left shift of unsized constants in sef-determined context.
When left-shifting unsized constants in self-determined contexts, the
constant value is normally pared down to its minimum required width.
But this practically guarantees loss of bits. Instead, detect this
special case and give the unsized constant a width of an integer.

Still allow for the super-special case that the shifted value and the
shift amount are constants. In that case, the result width (and value)
can be calculated precisely and there is no need to resort to default
widths.
2008-04-22 11:23:24 -07:00
Stephen Williams 5ab0c20a7d Merge branch 'vector4_format' 2008-04-20 21:46:02 -07:00
Cary R 35e511d0c0 Check delay expressions correctly and give a better message.
This patch uses the true delay expression count not the truncated
one to check that the number of delay expressions is correct.
It also prints the actual number of expressions it found when
printing the error message.
2008-04-20 21:39:17 -07:00
Stephen Williams 935c3dc02d Optimize some common vvp_bit4_t operators.
By slightly altering the vvp_bit4_t encoding, a few simple
optimizations become possible. By making Z==2 and X==3, the
conversion from X/Z to X is a simple shift-or, and this can
be used to reduce the size of some of the bit4 operators.
2008-04-20 21:36:53 -07:00
Stephen Williams 6d2ef15951 Remove dead code related to bit arrays/vectors
In previous incarnations of the vvp runtime, bit vectors were passed
around as arrays of unsigned char that charried bit4 vectors. That
is no longer used. Remove the last vestiges of that dead code.
2008-04-20 20:43:53 -07:00
Stephen Williams 40fd07d46e Remove most dependencies on vvp_bit4_t encoding.
Remove dependencies on vvp_bit4_encoding outside of the vvp_net
core types. The table_functor_s class was the worst offfender and
was barely used, so it is now removed completely. There are a few
opcodes in vhtread.cc that also make vvvp_bit4_t encoding
assumptions (and used casts) and those have been fixed. There
were also various VPI interface functions that are fixed.
2008-04-20 19:21:41 -07:00
Stephen Williams 5e30016910 Rework vvp_vector4_t to use planar a/b bits instead of interleaved.
The vvp_vector4_t holds 4-value logic. This patch changes the encoding
of 4-value bits in the vector to use separate A- and B bit vectors,
with the B- vector signaling the A- bits that are not 0/1. This
allows rapid conversion to 2-value logic, and rapid tests for X
and Z values.
2008-04-20 16:30:27 -07:00
thiede 33466250f5 Support localparam integer types.
Support localparam integer types exactly the same way that they
are handled for parameters. (This patch was submitted to pr1946144.)
2008-04-18 21:54:25 -07:00
Stephen Williams bdab7698d2 User defined functions can have ANSI-style ports
Update the rules for parsing user function definitions to allow
Verilog-2001 ANSI style port declarations. In the process, also
unify with the user task port declaration so that the types don't
diverge. The rules are the same for both, with the extra constraint
that function ports must all be input. This latter rule is checked
later, during elaboration, so that the task/function pform code
can be shared, and better error messages can be generated.
2008-04-18 21:33:03 -07:00
Cary R 54918cf5b9 Add unlink from driver to deassign and zero link pointer.
This patch fixes deassign to allow it to unlink from a driver.
It also zeros the cassign_link and force_link pointers after
they have been unlinked. Not doing this will cause an assert
if deassign/release are called multiple times (variable only).
2008-04-17 20:36:03 -07:00
Stephen Williams 844447b995 More reliably handle make install from read-only directory
commonly, the make install is run in a compiled directory by a
different user (i.e. an administrator) that doesn't necessarily
have write access to the build directory. This patch fixes it so
that the test that the version.h is up to date doesn't need to
write a temporary file in the build directory.

It also makes sure that if there is a real need to update the
verion.h, and it is not writable, then properly fail the build.
2008-04-17 20:33:39 -07:00
Cary R 6eb9825ab7 Add force/release and assign/deassign for real values.
This patch adds assign/deassign for real variables and force/release
for real variables and nets.
2008-04-17 20:18:20 -07:00
Stephen Williams 23e60aa381 Fix parsing of precompiled macro definitions
Passing preprocessor definitions forward into library cells was broken
by this bug in processing the precompiled macro values that were written
by the main preprocessor.
2008-04-17 11:52:51 -07:00
Stephen Williams 373123af6b Detect thread bit allocation failures
Detect thread bit allocation failures and fail gracefully. Print an
error message that points at the expression in question, and return
with an error code so that the compiler exits with an error.
2008-04-15 21:51:03 -07:00
Stephen Williams 54cf66d8b4 Merge branch 'master' of [email protected]:git/verilog 2008-04-15 19:19:38 -07:00
Stephen Williams dffe1be819 Trim results of unsized constant add to prevent width expansion
When constant values are added to get another constant value, and the
expression is not otherwise a fixed size, then trim the result to
prevent unbounded expansion of unsized expression with.

In the process, find and fix a bug in the vtrim function that caused
an assert if trimming were not possible for an unsigned value.
2008-04-15 19:18:03 -07:00
Cary R d41f8fe52b Only pad parameter constants out to their defined width.
This patch fixes the elaboration of parameters in a continuous
assignment to only pad the constants to their defined width.
Previously they were padded to the l-value width which resulted
in a vvp runtime error. This appears to be because the width
for padding is the defined width, but the constant is printed
using its internal width which previously could be larger than
its defined width.

These constants are local nets so I added that flag as well.
2008-04-15 18:05:53 -07:00
Larry Doolittle 6ca53c6810 Don't crash on duplicate module
Fix for pr1938138,
pform.cc:278: failed assertion lexical_scope == 0
2008-04-15 17:56:54 -07:00
Cary R 9bb8e8146f Add assign/deassign to bit/part selects and other fixes
This patch adds the ability to assign/deassign a bit or part select.
It also cleans up the code and fixes some problem in the forcing of
strength aware nets.
2008-04-15 17:46:44 -07:00
Cary R 321114e4db Add an underscore between multiple strength values.
When printing the strength information for a multi bit net this patch
adds an underscore between the individual bit strength values. This
makes it easier to see the individual bit values.
2008-04-15 17:31:35 -07:00
Cary R ef3aacfe36 Make %v print all the bits of a vector.
This patch reworks the %v code to print the strength information
for all the bits of a vector. The code previously only printed
the LSB information.
2008-04-15 17:23:58 -07:00
J Varshney bfb33230aa Revise handling of version.h to avoid build problems.
A patch to insert the version string from git broke compilation when
the source was not a git repository or when building in a read-only
source tree.  This patch avoids breaking compilation by using a
graceful failure mechanism for generating the version string and does
not write to the source tree.
2008-04-11 20:51:09 -07:00
Cary R 44767d8f70 Make MUXZ and MUXR use enum for select type.
Rework the MUXZ and MUXR code to use an enum instead of plain
integers for the select input state. This makes it more obvious
what is actually going on.
2008-04-09 21:47:47 -07:00
Cary R fecd941a28 Make sure MUXZ runs at time zero if needed.
This patch adds a flag to the MUXZ object to make sure that it will
run at time zero if needed. If this is not done the default Z result
may not be overridden by an X result.
2008-04-09 21:47:39 -07:00
Cary R 2be8534021 Add %assign/av/d opcode.
This patch adds a %assign/av/d opcode. This is a version of %assign/av
that allows a delay expression. Ultimately this allows a dynamically
indexed array to have a delay expression (non-constant delay value).
2008-04-09 21:24:37 -07:00
Cary R 8cece424d1 In the context of a force/assign you cannot reuse a saved signal value.
This patch removes the overly optimistic lookaside save for a signal
that has been set (%set/v). This is incorrect because if a force or
assign are active the value will not be set as expected.
2008-04-09 21:10:11 -07:00
Stephen Williams e2dfeac86c Part select from vectored parameters correct.
Make sure that constant bit selects of parameter names use the
proper vector range.
2008-04-08 21:20:49 -07:00
Stephen Williams a914eda5ef Get part select from vectored parameters correct.
Parameters with vector descriptions that are not zero based and
are used in net contexts should generate the properly ranged
temporary signals. This causes subsequent part selects to work
out properly.
2008-04-08 20:50:36 -07:00
Stephen Williams ba8a41ca28 Some elab_pexpr debug text. 2008-04-08 20:42:42 -07:00
Stephen Williams a67d573ae6 Eval_tree debug is controled by debug_eval_tree flag. 2008-04-08 20:42:08 -07:00
Cary R f5418fe337 Catch unsupported bit/part select lvalue for assign/deassign.
This patch adds code to print a message when an assign/deassign is used
to drive/release a bit/part select.
2008-04-07 20:52:54 -07:00
Stephen Williams 7035ded57a Do not replace explicit parameters with implicit wires.
During elaborate_sig, the code to detect implicit wires did not
properly account for the possibility that the name is that of an
explicitly declared parameter.
2008-04-06 19:26:22 -07:00
J Varshney ad3a73f74f Append last git tag and abbreviated commit-id to version string. 2008-04-06 09:30:55 -07:00
J Varshney 43e8a08c97 Tell make to find ivl.def and vvp.def in srcdir. 2008-04-06 09:22:50 -07:00
Cary R 208c6a349d Add <> to general T_SYMBOL RE and move it after the special cases.
This patch add (I believe back in) the < and > characters to the
general T_SYMBOL regular expression. The match was also moved after
the special T_SYMBOL cases so that flex would match them correctly.
Flex matching rules are longest or if a tie the first.
2008-04-04 21:59:13 -07:00
Cary R 640231bbfa Add code to prevent broken synthesis in devel. from core dumping.
This patch adds code to prevent the broken synthesis code in
the development branch from core dumping. Broken code here
refers to the Icarus code not a Verilog file.
2008-04-04 21:38:59 -07:00
Cary R bdc48135e5 Fix two comparisons in tgt-vvp/eval_expr.c to use correct variable.
This patch fixes two comparison that were using the wrong variable
to determine when the end of the object had been reached.
2008-04-04 21:31:14 -07:00
Cary R f7e840cd0a Fix another delete[]/free problem.
This patch fixes a delete[] vs free problem in the NexusSet
class. The items_ array was being allocated with malloc/realloc
and freed with delete[]. The quick fix was to replace delete[]
with a call to free(). A better fix would probably be to rework
the class to use a vector.
2008-04-04 21:31:14 -07:00
Cary R 3c1e7c4260 A NetScope will get a default nettype from a parent.
The default nettype was not always being set. This patch
modifies the NetScope constructor to get the default
nettype from a parent if it exists. It is set to NONE if
a parent does not exist.
2008-04-04 21:31:14 -07:00
Cary R 5a1ec9b958 A IVL_EX_CONCAT is always unsigned.
The signedness of an IVL_EX_CONCAT was not being set. This patch
forces it to always be unsigned as the standard specifies.
2008-04-04 21:31:13 -07:00
Michael 1bc56fcc93 Delete all temporary files even when using -E flag
The -E flag causes the driver to exit early. Be careful to delete
all the various temporary files even in this case.
2008-04-04 21:22:46 -07:00
Stephen Williams 13958cf374 Elaborate_sig skips ports that are missing on primitives
It is illegal for primitives to not have ports bound, but that
error will be taken care of later, during elaborate.
2008-03-28 21:34:18 -05:00
Cary R b5b5a9935c Fix malloc/free and new/delete problems, plus some initializations.
This patch fixes some allocation problems (mostly in the parser
and lexor relating to identifiers). It also fixes a couple places
where uninitialized variables were used. All found with valgrind.
There are still 100 tests that have problems. Many of these appear
to be related.
2008-03-27 20:58:16 -07:00
Cary R bb14ac1fe0 Add functionality to alias an individual word of an array.
This patch adds the functionality to alias an individual word
of an array.
2008-03-26 21:44:57 -07:00
Cary R 04e8623ed6 Make macro argument substitution more sane.
Macro argument substitution used to just use strstr() to
find an argument that needed to be substituted. This is too
aggressive. It would do argument substitution in the middle
of keywords and other identifiers. A new routine is used
that verifies the character preceding the match is not
a normal identifier character [a-zA-Z0-9_$].
2008-03-26 18:27:05 -07:00
Cary R 225fcf6bf0 Pad CA bit arguments and make reductions and ! self-determined.
Binary bit based operators were not padding arguments if they had
different widths. The reduction operators and ! were not correctly
evaluating their arguments in a self-determined context.
2008-03-26 18:23:19 -07:00
Cary R 8c1cca423d Check for a negative repeat value.
This patch adds checks for a negative repeat value and prints
an error message under this condition.
2008-03-26 18:12:38 -07:00
Cary R 7bc9742710 Pad the R-value of a for loop initial assign like other assigns.
The for loop initial value R-value was not being padded correctly.
This code is a copy of the code used in a regular assignment.
2008-03-26 18:09:03 -07:00
Cary R 12f8af645f Add support for real parameters in vvp.
vvp did not have the ability to handle real parameters.
This patch fixes that omission. Parameters are only used
by vpi calls to get compile time information.
2008-03-26 18:04:57 -07:00
Cary R 259e4294e3 Make of_ZOMBIE use scheduled thread deletion.
This patch modifies of_ZOMBIE() to use the same scheduled deletion
as vthread_reap().
2008-03-26 18:02:43 -07:00
Stephen Williams ea74eb771e Fix a couple problems with signed multiply
Problems with signed expressions that are set to parameters and
that include multipliciation exposed a few bugs in the calculation
of signed multiply. Fix this and add some improved diagnostics.
2008-03-25 21:35:08 -07:00
Stephen Williams 32b115d8fe Parameters get their types (signedness) from expressions.
Parameters get their signedness from the expression that is assigned
to them unless the type is explicitly expressed where the parameter
is declared.
2008-03-25 21:30:41 -07:00
Stephen Williams 14e3a886bd Find implicit nets in expressions passed to ports.
It is questionable, but probably legal, for expressions passed as
arguments to input ports of various kinds of gates to implicitly
declare nets. This patch allows the scan through different types
of expressions for implicit nets.

The elaborate_sig handling here does not test for the legality of
having a non-trivial expression as argument to a port. For example,
it is definitely NOT legal to have r-value expressions passed to
output or inout ports. But that will be checked for later when the
instance is elaborated for real.
2008-03-23 17:52:48 -07:00
Stephen Williams 140fd45460 Implicit declaration handling in ports to UDP.
Scan port expressions for implicit nets using elaborate_sig.
2008-03-20 21:44:35 -07:00
Cary R 5b2f249dcc Thread deletion is now scheduled after rosync.
Threads used to be deleted when they finished processing code.
The problem with this is that some of the code could be
rescheduled to run at rosync ($strobe, etc.). This allowed the
thread data the code depended on to be reaped too soon. This
patch uses a new queue to schedule thread deletion. The queue
is processed after rosync has finished.
2008-03-20 20:45:41 -07:00
Cary R 01eb298228 Make muxz and muxr functors use scheduled events.
This patch makes the muxz and muxr functors schedule events
instead of directly calling vvp_send_*(). This prevents the
code from going into an infinite loop when the output feeds
back to the select.
2008-03-20 20:26:45 -07:00
Cary R 48990d8e2d Implement CA - ternary short circuit for constant T/F expressions.
This patch only applies to the ternary operator when used in a
continuous assignment. It adds short circuiting when the expression
is a constant true or false. It does not optimize the special case of
a constant 'bx expression with constant T/F expressions.
2008-03-20 20:07:54 -07:00
Cary R 77722a62c2 Enhance dump() for function definitions.
This patch enhances dump() for function definitions, by indicating a
signed result with a prepended "+" and also printing the MSB and LSB.
This matches other dump() routines. It also prints the arguments with
the same information. The arguments also include their type "input",
"output" or "inout".
2008-03-20 19:42:11 -07:00
Stephen Williams a2ea980a7a Merge branch 'implicit-sig' 2008-03-18 21:44:34 -07:00
Cary R 86301be3d2 Remove unused return_event_flag.
This patch removes the unused return_event_flag variable.
2008-03-18 21:44:13 -07:00
Stephen Williams bbb488f730 Handle implicit nets in the named arguments of module instances. 2008-03-18 21:40:31 -07:00
Stephen Williams 13d4a7352c Elaborate implicit signals that are arguments to module instances.
Module instances are like gates, so the expressions pass in need
to be checked for implicit nets.
2008-03-18 21:25:13 -07:00
Stephen Williams d26ae866f8 Move implicit net creation from elaboration to elaborate_sig
If implicit nets are declared during elaboration, then the success
of binding during elaboration will depend on the order of the code
in the source file.
2008-03-18 20:50:40 -07:00
Stephen Williams 8e6c2652ab Merge branch 'master' of [email protected]:git/verilog 2008-03-14 21:06:27 -07:00
Stephen Williams 9b1baea6da Minor remove of unused vvp_net_t member. 2008-03-12 21:30:42 -07:00
126 changed files with 6576 additions and 4365 deletions
+45 -24
View File
@@ -57,7 +57,7 @@ CXXFLAGS = -Wall @CXXFLAGS@
PICFLAGS = @PICFLAG@
LDFLAGS = @rdynamic@ @LDFLAGS@
all: dep ivl@EXEEXT@
all: dep version.h ivl@EXEEXT@
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
for dir in ivlpp ; \
do (cd $$dir ; $(MAKE) $@); done
@@ -124,9 +124,9 @@ ifeq (@WIN32@,yes)
# The first step makes an ivl.exe that dlltool can use to make an
# export and import library, and the last link makes a, ivl.exe
# that really exports the things that the import library imports.
ivl@EXEEXT@: $O ivl.def
ivl@EXEEXT@: $O $(srcdir)/ivl.def
$(CXX) -o ivl@EXEEXT@ $O $(dllib) @EXTRALIBS@
dlltool --dllname ivl@EXEEXT@ --def ivl.def \
dlltool --dllname ivl@EXEEXT@ --def $(srcdir)/ivl.def \
--output-lib libivl.a --output-exp ivl.exp
$(CXX) $(LDFLAGS) -o ivl@EXEEXT@ ivl.exp $O $(dllib) @EXTRALIBS@
else
@@ -182,6 +182,24 @@ iverilog-vpi.ps: $(srcdir)/iverilog-vpi.man
iverilog-vpi.pdf: iverilog-vpi.ps
ps2pdf iverilog-vpi.ps iverilog-vpi.pdf
# For VERSION_TAG in driver/main.c, first try git-describe, then look for a
# version.h file in the source tree (included in snapshots and releases), and
# finally use nothing.
.PHONY: version.h
version.h:
@if test -d $(srcdir)/.git; then \
echo "Using git-describe for VERSION_TAG"; \
tmp=`git --git-dir $(srcdir)/.git describe \
| sed -e 's;\(.*\);#define VERSION_TAG "\1";'`; \
echo "$$tmp" | diff - $@ > /dev/null 2>&1 || echo "$$tmp" > $@ || exit 1; \
elif test -r $(srcdir)/$@; then \
echo "Using $(srcdir)/$@ for VERSION_TAG"; \
diff $(srcdir)/$@ $@ > /dev/null 2>&1 || cp $(srcdir)/$@ $@; \
else \
echo "Using empty VERSION_TAG"; \
echo '#define VERSION_TAG ""' > $@; \
fi
ifeq (@MING32@,yes)
INSTALL_DOC = $(prefix)/iverilog-vpi.pdf $(mandir)/man1/iverilog-vpi.1
INSTALL_DOCDIR = $(mandir)/man1
@@ -199,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.
@@ -258,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&);
+7 -2
View File
@@ -43,7 +43,7 @@ bool PExpr::is_constant(Module*) const
return false;
}
NetNet* PExpr::elaborate_lnet(Design*des, NetScope*, bool) const
NetNet* PExpr::elaborate_lnet(Design*des, NetScope*) const
{
cerr << get_fileline() << ": error: expression not valid in assign l-value: "
<< *this << endl;
@@ -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;
}
+22 -14
View File
@@ -74,6 +74,10 @@ class PExpr : public LineInfo {
unsigned min, unsigned lval,
bool&unsized_flag) const;
// During the elaborate_sig phase, we may need to scan
// expressions to find implicit net declarations.
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
// Procedural elaboration of the expression. The expr_width is
// the width of the context of the expression (i.e. the
// l-value width of an assignment),
@@ -107,8 +111,7 @@ class PExpr : public LineInfo {
// This method elaborates the expression as gates, but
// restricted for use as l-values of continuous assignments.
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
bool implicit_net_ok =false) const;
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
// This is similar to elaborate_lnet, except that the
// expression is evaluated to be bi-directional. This is
@@ -157,8 +160,8 @@ class PEConcat : public PExpr {
virtual verinum* eval_const(Design*des, NetScope*sc) const;
virtual void dump(ostream&) const;
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
bool implicit_net_ok =false) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
unsigned width,
@@ -177,7 +180,6 @@ class PEConcat : public PExpr {
private:
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
bool implicit_net_ok,
bool bidirectional_flag) const;
private:
svector<PExpr*>parms_;
@@ -264,9 +266,10 @@ class PEIdent : public PExpr {
unsigned min, unsigned lval,
bool&unsized_flag) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
// Identifiers are allowed (with restrictions) is assign l-values.
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
bool implicit_net_ok =false) const;
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
@@ -379,13 +382,12 @@ class PEIdent : public PExpr {
private:
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
bool implicit_net_ok,
bool bidirectional_flag) const;
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;
};
@@ -472,6 +474,8 @@ class PEUnary : public PExpr {
virtual void dump(ostream&out) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
unsigned width,
const NetExpr* rise,
@@ -531,6 +535,8 @@ class PEBinary : public PExpr {
unsigned min, unsigned lval,
bool&unsized_flag) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
unsigned width,
const NetExpr* rise,
@@ -538,7 +544,7 @@ class PEBinary : public PExpr {
const NetExpr* decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetEBinary*elaborate_expr(Design*des, NetScope*,
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const;
@@ -548,8 +554,8 @@ class PEBinary : public PExpr {
PExpr*left_;
PExpr*right_;
NetEBinary*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetEBinary*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp);
@@ -615,8 +621,8 @@ class PEBComp : public PEBinary {
unsigned min, unsigned lval,
bool&flag) const;
NetEBinary* elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const;
NetExpr* elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const;
};
class PEBShift : public PEBinary {
@@ -646,6 +652,8 @@ class PETernary : public PExpr {
unsigned min, unsigned lval,
bool&unsized_flag) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
unsigned width,
const NetExpr* rise,
+3
View File
@@ -129,6 +129,7 @@ class PGAssign : public PGate {
void dump(ostream&out, unsigned ind =4) const;
virtual void elaborate(Design*des, NetScope*scope) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
private:
};
@@ -166,6 +167,7 @@ class PGBuiltin : public PGate {
virtual void dump(ostream&out, unsigned ind =4) const;
virtual void elaborate(Design*, NetScope*scope) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
private:
Type type_;
@@ -234,6 +236,7 @@ class PGModule : public PGate {
void elaborate_udp_(Design*, PUdp *udp, NetScope*scope) const;
void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const;
bool elaborate_sig_mod_(Design*des, NetScope*scope, Module*mod) const;
bool elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const;
NetNet*resize_net_to_port_(Design*des, NetScope*scope,
NetNet*sig, unsigned port_wid,
+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
+24 -5
View File
@@ -1,7 +1,7 @@
#ifndef __compiler_H
#define __compiler_H
/*
* Copyright (c) 1999-2007 Stephen Williams ([email protected])
* Copyright (c) 1999-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
@@ -76,6 +76,9 @@ extern bool warn_timescale;
/* Warn about legal but questionable module port bindings. */
extern bool warn_portbinding;
/* Warn about structures that may have infinite loops. */
extern bool warn_inf_loop;
/* This is true if verbose output is requested. */
extern bool verbose_flag;
@@ -97,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
+59 -3
View File
@@ -112,6 +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 (has_condit()) o << " if";
else o << " ifnone";
}
o << " src "
<< "(" << transition_delays_[IVL_PE_01]
<< "," << transition_delays_[IVL_PE_10]
@@ -243,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()
@@ -840,9 +853,35 @@ void NetForever::dump(ostream&o, unsigned ind) const
void NetFuncDef::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "function definition for " << scope_path(scope_) << endl;
if (result_sig_)
o << setw(ind+2) << "" << "Return signal: "
<< result_sig_->name() << endl;
if (result_sig_) {
o << setw(ind+2) << "" << "Return signal: ";
if (result_sig_->get_signed()) o << "+";
o << result_sig_->name() << "[" << result_sig_->msb() << ":"
<< result_sig_->lsb() << "]" << endl;
}
o << setw(ind+2) << "" << "Arguments: ";
if (port_count() == 0) o << "<none>";
o << endl;
for (unsigned idx = 0; idx < port_count(); idx += 1) {
o << setw(ind+4) << "" << "Arg[" << idx+1 << "] = ";
switch (port(idx)->port_type()) {
default:
o << "implicit-port? ";
break;
case NetNet::PINPUT:
o << "input ";
break;
case NetNet::POUTPUT:
o << "output ";
break;
case NetNet::PINOUT:
o << "inout ";
break;
}
if (port(idx)->get_signed()) o << "+";
o << port(idx)->name() << "[" << port(idx)->msb() << ":"
<< port(idx)->lsb() << "]" << endl;
}
if (statement_)
statement_->dump(o, ind+2);
else
@@ -1052,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 << ")";
@@ -1237,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;
+2 -2
View File
@@ -21,7 +21,7 @@
#
SHELL = /bin/sh
VERSION = 0.8
VERSION = 0.9.devel
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -68,7 +68,7 @@ cfparse.h cfparse.c: cfparse.y
bison --verbose -t -d -o cfparse.c --name-prefix=cf $(srcdir)/cfparse.y
main.o: main.c globals.h
main.o: main.c globals.h ../version.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c -DIVL_ROOT='"@libdir@/ivl"' -DIVL_INC='"@includedir@"' -DIVL_LIB='"@libdir@"' -DDLLIB='"@DLLIB@"' $(srcdir)/main.c
build_string.o: build_string.c globals.h
+29 -6
View File
@@ -1,11 +1,11 @@
.TH iverilog 1 "$Date: 2007/06/05 01:56:12 $" Version "$Date: 2007/06/05 01:56:12 $"
.TH iverilog 1 "April 22nd, 2008" Version "0.9.devel"
.SH NAME
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
@@ -251,6 +254,21 @@ inherit timescale from another file. Both probably mean that
timescales are inconsistent, and simulation timing can be confusing
and dependent on compilation order.
.TP 8
.B infloop
This enables warnings for \fRalways\fP statements that may have runtime
infinite loops (has paths with no or zero delay). This class of warnings
is not included in \fB-Wall\fP and hence does not have a \fBno-\fP variant.
A fatal error message will always be printed when the compiler can
determine that there will definitely be an infinite loop (all paths have
no or zero delay).
When you suspect an always statement is producing a runtime infinite loop
use this flag to find the always statements that need to have their logic
verified. It is expected that many of the warnings will be false
positives, since the code treats the value of all variables and signals
as indeterminate.
.SH "SYSTEM FUNCTION TABLE FILES"
If the source file name as a \fB.sft\fP suffix, then it is taken to be
a system function table file. A System function table file is used to
@@ -369,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
+65 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2007 Stephen Williams ([email protected])
* Copyright (c) 2000-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,6 +18,7 @@
*/
# include "config.h"
# include "version.h"
const char NOTICE[] =
" This program is free software; you can redistribute it and/or modify\n"
@@ -108,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;
@@ -357,6 +360,11 @@ static void process_warning_switch(const char*name)
} else if (strcmp(name,"timescale") == 0) {
if (! strchr(warning_flags, 't'))
strcat(warning_flags, "t");
/* Since the infinite loop check is not part of 'all' it
* does not have a no- version. */
} else if (strcmp(name,"infloop") == 0) {
if (! strchr(warning_flags, 'l'))
strcat(warning_flags, "l");
} else if (strcmp(name,"no-implicit") == 0) {
char*cp = strchr(warning_flags, 'i');
if (cp) while (*cp) {
@@ -424,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";
@@ -457,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;
}
@@ -557,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. */
@@ -701,8 +740,8 @@ int main(int argc, char **argv)
pbase = base;
if (version_flag || verbose_flag) {
printf("Icarus Verilog version " VERSION " ($Name: $)\n\n");
printf("Copyright 1998-2007 Stephen Williams\n");
printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n");
printf("Copyright 1998-2008 Stephen Williams\n");
puts(NOTICE);
if (version_flag)
@@ -721,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);
@@ -806,8 +854,11 @@ int main(int argc, char **argv)
rc = system(cmd);
remove(source_path);
fclose(iconfig_file);
if ( ! getenv("IVERILOG_ICONFIG"))
if ( ! getenv("IVERILOG_ICONFIG")) {
remove(iconfig_path);
remove(defines_path);
remove(compiled_defines_path);
}
if (rc != 0) {
if (WIFEXITED(rc)) {
@@ -837,4 +888,3 @@ int main(int argc, char **argv)
return 0;
}
+135 -25
View File
@@ -96,7 +96,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
* and right sides, and creating one of a variety of different NetExpr
* types.
*/
NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope,
NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope,
int expr_wid, bool) const
{
assert(left_);
@@ -110,7 +110,7 @@ NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
NetEBinary*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid);
NetExpr*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid);
return tmp;
}
@@ -128,7 +128,7 @@ void PEBinary::suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp)
lp->cast_signed(false);
}
NetEBinary* PEBinary::elaborate_eval_expr_base_(Design*des,
NetExpr* PEBinary::elaborate_eval_expr_base_(Design*des,
NetExpr*lp,
NetExpr*rp,
int expr_wid) const
@@ -146,7 +146,7 @@ NetEBinary* PEBinary::elaborate_eval_expr_base_(Design*des,
* operands are elaborated as necessary, and all I need to do is make
* the correct NetEBinary object and connect the parameters.
*/
NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
NetExpr* PEBinary::elaborate_expr_base_(Design*des,
NetExpr*lp, NetExpr*rp,
int expr_wid) const
{
@@ -157,7 +157,7 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
<< *this << " expr_wid=" << expr_wid << endl;
}
NetEBinary*tmp;
NetExpr*tmp;
switch (op_) {
default:
@@ -167,6 +167,8 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
case 'a':
case 'o':
lp = condition_reduce(lp);
rp = condition_reduce(rp);
tmp = new NetEBLogic(op_, lp, rp);
tmp->set_line(*this);
break;
@@ -185,7 +187,7 @@ NetEBinary* 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 "
@@ -200,6 +202,56 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
break;
case 'l': // <<
if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {
if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
// Handle the super-special case that both
// operands are constants. Precalculate the
// entire value here.
verinum lpval = lpc->value();
unsigned shift = rpc->value().as_ulong();
verinum result = lpc->value() << shift;
// If the l-value has explicit size, or
// there is a context determined size, use that.
if (lpval.has_len() || expr_wid > 0) {
int use_len = lpval.len();
if (expr_wid < use_len)
use_len = expr_wid;
result = verinum(result, lpval.len());
}
tmp = new NetEConst(result);
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Precalculate " << *this
<< " to constant " << *tmp << endl;
} else {
// Handle the special case that the left
// operand is constant. If it is unsized, we
// may have to expand it to an integer width.
verinum lpval = lpc->value();
if (lpval.len() < integer_width && !lpval.has_len()) {
lpval = verinum(lpval, integer_width);
lpc = new NetEConst(lpval);
lpc->set_line(*lp);
}
tmp = new NetEBShift(op_, lpc, rp);
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Adjust " << *this
<< " to this " << *tmp
<< " to allow for integer widths." << endl;
}
} else {
// Left side is not constant, so handle it the
// default way.
tmp = new NetEBShift(op_, lp, rp);
}
tmp->set_line(*this);
break;
case 'r': // >>
case 'R': // >>>
tmp = new NetEBShift(op_, lp, rp);
@@ -259,6 +311,12 @@ NetEBinary* 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;
@@ -269,8 +327,8 @@ unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, bool&) const
return 1;
}
NetEBinary* PEBComp::elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const
NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const
{
assert(left_);
assert(right_);
@@ -628,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) {
@@ -655,6 +716,23 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
des->errors += 1;
}
if (rep->value().is_negative()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "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;
}
repeat = rep;
}
@@ -692,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;
}
@@ -1128,6 +1215,13 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
ivl_assert(*this, index_tail.msb);
ivl_assert(*this, !index_tail.lsb);
const NetEConst*par_me =dynamic_cast<const NetEConst*>(par_msb);
const NetEConst*par_le =dynamic_cast<const NetEConst*>(par_lsb);
ivl_assert(*this, par_me || !par_msb);
ivl_assert(*this, par_le || !par_lsb);
ivl_assert(*this, par_me || !par_le);
/* Handle the case where a parameter has a bit
select attached to it. Generate a NetESelect
object to select the bit as desired. */
@@ -1149,7 +1243,20 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
verinum rv = re->value();
verinum::V rb = verinum::Vx;
long par_mv = lv.len()-1;
long par_lv = 0;
if (par_me) {
par_mv = par_me->value().as_long();
par_lv = par_le->value().as_long();
}
/* Convert the index to cannonical bit address. */
long ridx = rv.as_long();
if (par_mv >= par_lv) {
ridx -= par_lv;
} else {
ridx = par_mv - ridx + par_lv;
}
if ((ridx >= 0) && ((unsigned long) ridx < lv.len())) {
rb = lv[ridx];
@@ -1167,13 +1274,6 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
} else {
const NetEConst*par_me =dynamic_cast<const NetEConst*>(par_msb);
const NetEConst*par_le =dynamic_cast<const NetEConst*>(par_lsb);
assert(par_me || !par_msb);
assert(par_le || !par_lsb);
assert(par_me || !par_le);
if (par_me) {
long par_mv = par_me->value().as_long();
long par_lv = par_le->value().as_long();
@@ -1349,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;
@@ -1458,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.
@@ -1735,13 +1836,23 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope,
NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
int expr_wid, bool) const
{
/* Reduction operators and ! always have a self determined width. */
switch (op_) {
case '!':
case '&': // Reduction AND
case '|': // Reduction OR
case '^': // Reduction XOR
case 'A': // Reduction NAND (~&)
case 'N': // Reduction NOR (~|)
case 'X': // Reduction NXOR (~^)
expr_wid = -1;
default:
break;
}
NetExpr*ip = expr_->elaborate_expr(des, scope, expr_wid, false);
if (ip == 0) return 0;
/* Should we evaluate expressions ahead of time,
* just like in PEBinary::elaborate_expr() ?
*/
NetExpr*tmp;
switch (op_) {
default:
@@ -1756,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;
+253 -77
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;
@@ -1578,12 +1578,20 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
return 0;
}
if (erep->value().is_negative()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "may not be negative (" << erep->value().as_long()
<< ")." << endl;
des->errors += 1;
return 0;
}
repeat = erep->value().as_ulong();
delete etmp;
if (repeat == 0) {
cerr << get_fileline() << ": error: Concatenation repeat "
"may not be 0."
"may not be zero."
<< endl;
des->errors += 1;
return 0;
@@ -1681,7 +1689,6 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
}
}
osig->local_flag(true);
return osig;
}
@@ -1764,7 +1771,9 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
const NetExpr*par = 0;
NetEvent* eve = 0;
symbol_search(des, scope, path_, sig, par, eve);
const NetExpr*id_msb;
const NetExpr*id_lsb;
symbol_search(des, scope, path_, sig, par, eve, id_msb, id_lsb);
/* If this is a parameter name, then create a constant node
that connects to a signal with the correct name. */
@@ -1774,11 +1783,27 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
assert(pc);
verinum pvalue = pc->value();
/* If the desired lwidth is more than the width of the
constant value, extend the value to fit the desired
output. */
if (lwidth > pvalue.len()) {
verinum tmp ((uint64_t)0, lwidth);
/* If the parameter has declared dimensions, then apply
those to the dimensions of the net that we create. */
long msb = pvalue.len()-1;
long lsb = 0;
if (id_msb || id_lsb) {
assert(id_msb && id_lsb);
const NetEConst*tmp = dynamic_cast<const NetEConst*>(id_msb);
ivl_assert(*this, tmp);
msb = tmp->value().as_long();
tmp = dynamic_cast<const NetEConst*>(id_lsb);
ivl_assert(*this, tmp);
lsb = tmp->value().as_long();
}
/* If the constant is smaller than its defined width extend
the value. If needed this will be padded later to fit
the real signal width. */
unsigned pwidth = msb > lsb ? msb - lsb : lsb - msb;
if (pwidth > pvalue.len()) {
verinum tmp ((uint64_t)0, pwidth);
for (unsigned idx = 0 ; idx < pvalue.len() ; idx += 1)
tmp.set(idx, pvalue.get(idx));
@@ -1786,9 +1811,10 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
}
sig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, pvalue.len());
NetNet::IMPLICIT, msb, lsb);
sig->set_line(*this);
sig->data_type(IVL_VT_LOGIC);
sig->local_flag(true);
NetConst*cp = new NetConst(scope, scope->local_symbol(),
pvalue);
cp->set_line(*this);
@@ -1868,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
@@ -1937,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 "
@@ -1964,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;
}
@@ -2188,7 +2302,6 @@ NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope,
* make the l-value connections.
*/
NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
bool implicit_net_ok,
bool bidirectional_flag) const
{
assert(scope);
@@ -2222,8 +2335,7 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
if (bidirectional_flag) {
nets[idx] = parms_[idx]->elaborate_bi_net(des, scope);
} else {
nets[idx] = parms_[idx]->elaborate_lnet(des, scope,
implicit_net_ok);
nets[idx] = parms_[idx]->elaborate_lnet(des, scope);
}
if (nets[idx] == 0)
errors += 1;
@@ -2284,15 +2396,14 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
return osig;
}
NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope,
bool implicit_net_ok) const
NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope) const
{
return elaborate_lnet_common_(des, scope, implicit_net_ok, false);
return elaborate_lnet_common_(des, scope, false);
}
NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope) const
{
return elaborate_lnet_common_(des, scope, true, true);
return elaborate_lnet_common_(des, scope, true);
}
/*
@@ -2337,25 +2448,18 @@ NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope,
NetNet* PEIdent::make_implicit_net_(Design*des, NetScope*scope) const
{
NetNet::Type nettype = scope->default_nettype();
NetNet*sig = 0;
assert(nettype != NetNet::NONE);
if (!error_implicit && nettype!=NetNet::NONE) {
sig = new NetNet(scope, peek_tail_name(path_),
NetNet::IMPLICIT, 1);
/* Implicit nets are always scalar logic. */
sig->data_type(IVL_VT_LOGIC);
NetNet*sig = new NetNet(scope, peek_tail_name(path_),
NetNet::IMPLICIT, 1);
sig->set_line(*this);
/* Implicit nets are always scalar logic. */
sig->data_type(IVL_VT_LOGIC);
if (warn_implicit) {
cerr << get_fileline() << ": warning: implicit "
"definition of wire logic " << scope_path(scope)
<< "." << peek_tail_name(path_) << "." << endl;
}
} else {
cerr << get_fileline() << ": error: Net " << path_
<< " is not defined in this context." << endl;
des->errors += 1;
return 0;
if (warn_implicit) {
cerr << get_fileline() << ": warning: implicit "
"definition of wire logic " << scope_path(scope)
<< "." << peek_tail_name(path_) << "." << endl;
}
return sig;
@@ -2369,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
@@ -2433,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;
}
@@ -2478,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;
@@ -2506,7 +2615,6 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
* so most of the work for both is done here.
*/
NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
bool implicit_net_ok,
bool bidirectional_flag) const
{
assert(scope);
@@ -2526,19 +2634,10 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
}
if (sig == 0) {
if (implicit_net_ok) {
sig = make_implicit_net_(des, scope);
if (sig == 0)
return 0;
} else {
cerr << get_fileline() << ": error: Net " << path_
<< " is not defined in this context." << endl;
des->errors += 1;
return 0;
}
cerr << get_fileline() << ": error: Net " << path_
<< " is not defined in this context." << endl;
des->errors += 1;
return 0;
}
assert(sig);
@@ -2604,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;
@@ -2671,15 +2779,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
* Identifiers in continuous assignment l-values are limited to wires
* and that ilk. Detect registers and memories here and report errors.
*/
NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
bool implicit_net_ok) const
NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope) const
{
return elaborate_lnet_common_(des, scope, implicit_net_ok, false);
return elaborate_lnet_common_(des, scope, false);
}
NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const
{
return elaborate_lnet_common_(des, scope, true, true);
return elaborate_lnet_common_(des, scope, true);
}
/*
@@ -2732,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
@@ -2907,6 +3014,30 @@ NetNet* PEString::elaborate_net(Design*des, NetScope*scope,
return net;
}
/* Common processing for the case when a single argument is always
* selected in a ternary operator. */
static void process_single_ternary(Design*des, const PExpr*base,
unsigned width, NetNet*&sig)
{
/* We must have a type for the signal. */
if (sig->data_type() == IVL_VT_NO_TYPE) {
cerr << base->get_fileline() << ": internal error: constant "
<< "selected ternary clause has NO TYPE." << endl;
des->errors += 1;
sig = 0;
}
/* Use the signal width if one is not provided.
* Pad or crop as needed. */
if (width == 0) width = sig->vector_width();
if (sig->vector_width() < width) sig = pad_to_width(des, sig, width);
if (width < sig->vector_width()) sig = crop_to_width(des, sig, width);
sig->set_line(*base);
}
/*
* Elaborate the ternary operator in a netlist by creating a LPM_MUX
* with width matching the result, size == 2 and 1 select input. These
@@ -2939,18 +3070,24 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
case C_0:
fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
if (fal_sig == 0) return 0;
tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
process_single_ternary(des, this, width, fal_sig);
return fal_sig;
break;
case C_1:
tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
if (tru_sig == 0) return 0;
fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
process_single_ternary(des, this, width, tru_sig);
return tru_sig;
break;
default:
tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
/* We should really see if these are constant values and
* mix them as needed so we can omit the MUX? below, but
* since this is a very uncommon case, I'm going to pass
* on this for now. */
break;
}
expr_sig = expr->synthesize(des);
@@ -3108,10 +3245,6 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
Link::strength_t drive0,
Link::strength_t drive1) const
{
NetExpr*expr = elab_and_eval(des, scope, expr_, width);
if (expr == 0)
return 0;
// Some unary operands allow the operand to be
// self-determined, and some do not.
unsigned owidth = 0;
@@ -3122,6 +3255,9 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
break;
}
NetExpr*expr = elab_and_eval(des, scope, expr_, owidth);
if (expr == 0) return 0;
NetNet* sig = 0;
NetLogic*gate;
@@ -3178,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;
@@ -3256,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;
}
@@ -3431,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"),
+6 -1
View File
@@ -53,7 +53,7 @@ NetExpr*PEBinary::elaborate_pexpr (Design*des, NetScope*scope) const
return 0;
}
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp, -2);
NetExpr*tmp = elaborate_expr_base_(des, lp, rp, -2);
return tmp;
}
@@ -193,6 +193,11 @@ NetExpr*PEIdent::elaborate_pexpr(Design*des, NetScope*scope) const
delete res;
return 0;
}
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Bit select [" << *tmp << "]"
<< " in parameter expression." << endl;
res = new NetESelect(res, tmp, 1);
res->set_line(*this);
break;
+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)
+169 -2
View File
@@ -230,11 +230,129 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
return flag;
}
bool PExpr::elaborate_sig(Design*des, NetScope*scope) const
{
return true;
}
bool PEConcat::elaborate_sig(Design*des, NetScope*scope) const
{
bool flag = true;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
flag = parms_[idx]->elaborate_sig(des, scope) && flag;
return flag;
}
bool PEIdent::elaborate_sig(Design*des, NetScope*scope) const
{
NetNet* sig = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
// If implicit net creation is turned off, then stop now.
if (scope->default_nettype() == NetNet::NONE)
return true;
if (error_implicit)
return true;
symbol_search(des, scope, path_, sig, par, eve);
if (eve != 0)
return false;
if (par != 0)
return true;
if (sig == 0)
sig = make_implicit_net_(des, scope);
return sig != 0;
}
bool PEBinary::elaborate_sig(Design*des, NetScope*scope) const
{
bool flag = true;
flag = left_->elaborate_sig(des, scope) && flag;
flag = right_->elaborate_sig(des, scope) && flag;
return flag;
}
bool PETernary::elaborate_sig(Design*des, NetScope*scope) const
{
bool flag = true;
flag = tru_->elaborate_sig(des, scope) && flag;
flag = fal_->elaborate_sig(des, scope) && flag;
return flag;
}
bool PEUnary::elaborate_sig(Design*des, NetScope*scope) const
{
return expr_->elaborate_sig(des, scope);
}
bool PGate::elaborate_sig(Design*des, NetScope*scope) const
{
return true;
}
bool PGBuiltin::elaborate_sig(Design*des, NetScope*scope) const
{
bool flag = true;
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
const PExpr* pin_expr = pin(idx);
if (pin_expr == 0) {
// If there is no pin expression for this port,
// then skip it. Do not bother generating an error
// message here, that will be done during
// elaboration where these semantic details are tested.
continue;
}
ivl_assert(*this, pin_expr);
flag = pin_expr->elaborate_sig(des, scope) && flag;
}
return flag;
}
bool PGAssign::elaborate_sig(Design*des, NetScope*scope) const
{
/* Normally, l-values to continuous assignments are NOT allowed
to implicitly declare nets. However, so many tools do allow
it that Icarus Verilog will allow it, at least if extensions
are enabled. */
if (gn_icarus_misc_flag)
return pin(0)->elaborate_sig(des, scope);
return true;
}
bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
Module*rmod) const
{
bool flag = true;
// First, elaborate the signals that may be created implicitly
// by ports to this module instantiation. Handle the case that
// the ports are passed by name (pins_ != 0) or position.
if (pins_)
for (unsigned idx = 0 ; idx < npins_ ; idx += 1) {
const PExpr*tmp = pins_[idx].parm;
if (tmp == 0)
continue;
flag = tmp->elaborate_sig(des, scope) && flag;
}
else
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
const PExpr*tmp = pin(idx);
if (tmp == 0)
continue;
flag = tmp->elaborate_sig(des, scope) && flag;
}
NetScope::scope_vec_t instance = scope->instance_arrays[get_name()];
for (unsigned idx = 0 ; idx < instance.count() ; idx += 1) {
@@ -260,6 +378,28 @@ bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
return flag;
}
bool PGModule::elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const
{
bool flag = true;
if (pins_)
for (unsigned idx = 0 ; idx < npins_ ; idx += 1) {
const PExpr*tmp = pins_[idx].parm;
if (tmp == 0)
continue;
flag = tmp->elaborate_sig(des, scope) && flag;
}
else
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
const PExpr*tmp = pin(idx);
if (tmp == 0)
continue;
flag = tmp->elaborate_sig(des, scope) && flag;
}
return flag;
}
bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
{
bool flag = true;
@@ -453,6 +593,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
perm_string pname = (*ports_)[idx]->basename();
NetNet*tmp = scope->find_signal(pname);
ports[idx] = 0;
if (tmp == 0) {
cerr << get_fileline() << ": internal error: function "
<< scope_path(scope) << " is missing port "
@@ -460,9 +602,27 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
scope->dump(cerr);
cerr << get_fileline() << ": Continuing..." << endl;
des->errors += 1;
continue;
}
if (tmp->port_type() == NetNet::NOT_A_PORT) {
cerr << get_fileline() << ": internal error: function "
<< scope_path(scope) << " port " << pname
<< " is a port but is not a port?" << endl;
des->errors += 1;
scope->dump(cerr);
continue;
}
ports[idx] = tmp;
if (tmp->port_type() != NetNet::PINPUT) {
cerr << tmp->get_fileline() << ": error: function "
<< scope_path(scope) << " port " << pname
<< " is not an input port." << endl;
cerr << tmp->get_fileline() << ": : Function arguments "
<< "must be input ports." << endl;
des->errors += 1;
}
}
@@ -598,9 +758,16 @@ void PForStatement::elaborate_sig(Design*des, NetScope*scope) const
statement_->elaborate_sig(des, scope);
}
bool PGate::elaborate_sig(Design*des, NetScope*scope) const
void PRepeat::elaborate_sig(Design*des, NetScope*scope) const
{
return true;
if (statement_)
statement_->elaborate_sig(des, scope);
}
void PWhile::elaborate_sig(Design*des, NetScope*scope) const
{
if (statement_)
statement_->elaborate_sig(des, scope);
}
/*
+60 -37
View File
@@ -85,16 +85,8 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
assert(pin(0));
assert(pin(1));
/* Normally, l-values to continuous assignments are NOT allowed
to implicitly declare nets. However, so many tools do allow
it that Icarus Verilog will allow it, at least if extensions
are enabled. */
bool implicit_lval_ok = false;
if (generation_flag == GN_VER2001X)
implicit_lval_ok = true;
/* Elaborate the l-value. */
NetNet*lval = pin(0)->elaborate_lnet(des, scope, implicit_lval_ok);
NetNet*lval = pin(0)->elaborate_lnet(des, scope);
if (lval == 0) {
return;
}
@@ -410,7 +402,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return;
}
NetNet*lval_sig = pin(0)->elaborate_lnet(des, scope, true);
NetNet*lval_sig = pin(0)->elaborate_lnet(des, scope);
assert(lval_sig);
/* Detect the special case that the l-value width exactly
@@ -1140,7 +1132,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
assignment, as the port will continuous assign
into the port. */
sig = pins[idx]->elaborate_lnet(des, scope, true);
sig = pins[idx]->elaborate_lnet(des, scope);
if (sig == 0) {
cerr << pins[idx]->get_fileline() << ": error: "
<< "Output port expression must support "
@@ -1475,7 +1467,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
<< endl;
} else {
NetNet*sig = pins[0]->elaborate_lnet(des, scope, true);
NetNet*sig = pins[0]->elaborate_lnet(des, scope);
if (sig == 0) {
cerr << get_fileline() << ": error: "
<< "Output port expression is not valid." << endl;
@@ -1517,6 +1509,10 @@ bool PGModule::elaborate_sig(Design*des, NetScope*scope) const
if (mod != pform_modules.end())
return elaborate_sig_mod_(des, scope, (*mod).second);
map<perm_string,PUdp*>::const_iterator udp = pform_primitives.find(type_);
if (udp != pform_primitives.end())
return elaborate_sig_udp_(des, scope, (*udp).second);
return true;
}
@@ -1715,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);
@@ -2049,14 +2045,8 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
return 0;
}
if (expr->expr_width() > 1) {
assert(expr->expr_width() > 1);
verinum zero (verinum::V0, expr->expr_width());
NetEConst*ezero = new NetEConst(zero);
ezero->set_width(expr->expr_width());
NetEBComp*cmp = new NetEBComp('n', expr, ezero);
expr = cmp;
}
// Make sure the condition expression evaluates to a condition.
expr = condition_reduce(expr);
// Well, I actually need to generate code to handle the
// conditional, so elaborate.
@@ -2947,6 +2937,15 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
assert(etmp->expr_width() >= lv->lwidth());
}
/* Based on the specific type of the l-value, do cleanup
processing on the r-value. */
if (etmp->expr_type() != IVL_VT_REAL) {
unsigned wid = count_lval_width(lv);
etmp->set_width(wid);
etmp = pad_to_width(etmp, wid);
assert(etmp->expr_width() >= wid);
}
NetAssign*init = new NetAssign(lv, etmp);
init->set_line(*this);
@@ -3272,6 +3271,29 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const
verinum(1));
} while (0);
/* If this is an always block and we have no or zero delay then
* a runtime infinite loop will happen. If we possible have some
* delay then print a warning that an infinite loop is possible.
*/
if (type() == PProcess::PR_ALWAYS) {
DelayType dly_type = top->statement()->delay_type();
if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) {
cerr << get_fileline() << ": error: always statement"
<< " does not have any delay." << endl;
cerr << get_fileline() << ": : A runtime infinite"
<< " loop will occur." << endl;
des->errors += 1;
return false;
} else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) {
cerr << get_fileline() << ": warning: always statement"
<< " may not have any delay." << endl;
cerr << get_fileline() << ": : A runtime infinite"
<< " loop may be possible." << endl;
}
}
return true;
}
@@ -3285,16 +3307,6 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
if (!gn_specify_blocks_flag)
return;
/* Check for various path types that are not supported. */
if (conditional && !condition) {
cerr << get_fileline() << ": sorry: ifnone specify paths"
<< " are not supported." << endl;
cerr << get_fileline() << ": : Use -g no-specify to ignore"
<< " specify blocks." << endl;
des->errors += 1;
return;
}
ivl_assert(*this, conditional || (condition==0));
ndelays = delays.size();
@@ -3326,7 +3338,7 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
delete cur;
}
switch (ndelays) {
switch (delays.size()) {
case 1:
case 2:
case 3:
@@ -3335,15 +3347,14 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
break;
default:
cerr << get_fileline() << ": error: Incorrect delay configuration."
<< endl;
<< " Given " << delays.size() << " delay expressions." << endl;
ndelays = 1;
des->errors += 1;
break;
}
NetNet*condit_sig = 0;
if (conditional) {
ivl_assert(*this, condition);
if (conditional && condition) {
NetExpr*tmp = elab_and_eval(des, scope, condition, -1);
ivl_assert(*condition, tmp);
@@ -3364,7 +3375,9 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
cerr << get_fileline() << ": debug: Path to " << (*cur);
if (condit_sig)
cerr << " if " << condit_sig->name();
cerr << endl;
else if (conditional)
cerr << " ifnone";
cerr << " from ";
}
NetNet*dst_sig = scope->find_signal(*cur);
@@ -3384,7 +3397,8 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
}
NetDelaySrc*path = new NetDelaySrc(scope, scope->local_symbol(),
src.size(), condit_sig);
src.size(), condit_sig,
conditional);
path->set_line(*this);
// The presence of the data_source_expression indicates
@@ -3427,6 +3441,11 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
NetNet*src_sig = scope->find_signal(*cur_src);
assert(src_sig);
if (debug_elaborate) {
if (cur_src != src.begin()) cerr << " and ";
cerr << src_sig->name();
}
if ( (src_sig->port_type() != NetNet::PINPUT)
&& (src_sig->port_type() != NetNet::PINOUT) ) {
@@ -3439,6 +3458,9 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
connect(src_sig->pin(0), path->pin(idx));
idx += 1;
}
if (debug_elaborate) {
cerr << endl;
}
if (condit_sig)
connect(condit_sig->pin(0), path->pin(idx));
@@ -3685,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);
+32 -10
View File
@@ -95,12 +95,14 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
return 0;
}
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluate expr=" << *this
<< " --- prune=" << prune_to_width
<< " has_width=" << (has_width()? "true" : "false") << endl;
}
/* Result might have known width. */
if (has_width()) {
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluate expr=" << *this
<< " --- prune=" << prune_to_width << endl;
}
unsigned lwid = lc->expr_width();
unsigned rwid = rc->expr_width();
unsigned wid = (rwid > lwid) ? rwid : lwid;
@@ -108,6 +110,10 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
wid += 1;
verinum val2=verinum(val,wid);
val=val2;
} else {
/* No fixed width, so trim the bits losslessly. */
verinum val2 = trim_vnum(val);
val = val2;
}
return new NetEConst(val);
@@ -808,13 +814,18 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
verinum lval = lc->value();
verinum rval = rc->value();
NetExpr*tmp = 0;
switch (op_) {
case '/':
return new NetEConst(lval / rval);
tmp = new NetEConst(lval / rval);
break;
case '%':
return new NetEConst(lval % rval);
tmp = new NetEConst(lval % rval);
break;
}
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
}
return 0;
@@ -919,7 +930,13 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width)
verinum lval = lc->value();
verinum rval = rc->value();
return new NetEConst(lval * rval);
NetEConst*tmp = new NetEConst(lval * rval);
if (debug_eval_tree)
cerr << get_fileline() << ": debug: Evaluate "
<< lval << " * " << rval << " --> " << *tmp << endl;
return tmp;
}
NetExpr* NetEBPow::eval_tree_real_()
@@ -1148,7 +1165,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
return 0;
}
if (debug_elaborate) {
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: evaluating expression: "
<< *this << endl;
}
@@ -1200,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. */
+20 -20
View File
@@ -157,46 +157,39 @@ NetNet* NetEBBits::synthesize(Design*des)
NetScope*scope = lsig->scope();
assert(scope);
if (lsig->vector_width() != rsig->vector_width()) {
cerr << get_fileline() << ": internal error: bitwise (" << op_
<< ") widths do not match: " << lsig->vector_width()
<< " != " << rsig->vector_width() << endl;
cerr << get_fileline() << ": : width="
<< lsig->vector_width() << ": " << *left_ << endl;
cerr << get_fileline() << ": : width="
<< rsig->vector_width() << ": " << *right_ << endl;
des->errors += 1;
return 0;
}
unsigned width = lsig->vector_width();
if (rsig->vector_width() > width) width = rsig->vector_width();
lsig = pad_to_width(des, lsig, width);
rsig = pad_to_width(des, rsig, width);
assert(lsig->vector_width() == rsig->vector_width());
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, lsig->vector_width());
NetNet::IMPLICIT, width);
osig->local_flag(true);
osig->data_type(expr_type());
perm_string oname = scope->local_symbol();
unsigned wid = lsig->vector_width();
NetLogic*gate;
switch (op()) {
case '&':
gate = new NetLogic(scope, oname, 3, NetLogic::AND, wid);
gate = new NetLogic(scope, oname, 3, NetLogic::AND, width);
break;
case 'A':
gate = new NetLogic(scope, oname, 3, NetLogic::NAND, wid);
gate = new NetLogic(scope, oname, 3, NetLogic::NAND, width);
break;
case '|':
gate = new NetLogic(scope, oname, 3, NetLogic::OR, wid);
gate = new NetLogic(scope, oname, 3, NetLogic::OR, width);
break;
case '^':
gate = new NetLogic(scope, oname, 3, NetLogic::XOR, wid);
gate = new NetLogic(scope, oname, 3, NetLogic::XOR, width);
break;
case 'O':
gate = new NetLogic(scope, oname, 3, NetLogic::NOR, wid);
gate = new NetLogic(scope, oname, 3, NetLogic::NOR, width);
break;
case 'X':
gate = new NetLogic(scope, oname, 3, NetLogic::XNOR, wid);
gate = new NetLogic(scope, oname, 3, NetLogic::XNOR, width);
break;
default:
assert(0);
@@ -242,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) {
@@ -281,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) {
@@ -297,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) {
@@ -439,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;
@@ -930,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*);
+9
View File
@@ -118,9 +118,12 @@ ivl_nexus_ptr_sig
ivl_parameter_basename
ivl_parameter_expr
ivl_parameter_file
ivl_parameter_lineno
ivl_path_condit
ivl_path_delay
ivl_path_is_condit
ivl_path_scope
ivl_path_source
ivl_path_source_negedge
@@ -131,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
@@ -158,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
+30
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,
@@ -395,6 +396,8 @@ typedef const struct ivl_attribute_s*ivl_attribute_t;
* ivl_path_condit
* This returns the nexus that tracks the condition for the
* delay. If the delay path is unconditional, this returns nil.
* ivl_path_is_condit
* Is this a conditional structure? Needed for ifnone.
*
* ivl_path_source_posedge
* ivl_path_source_negedge
@@ -404,6 +407,7 @@ extern ivl_scope_t ivl_path_scope(ivl_delaypath_t obj);
extern ivl_nexus_t ivl_path_source(ivl_delaypath_t obj);
extern uint64_t ivl_path_delay(ivl_delaypath_t obj, ivl_path_edge_t pt);
extern ivl_nexus_t ivl_path_condit(ivl_delaypath_t obj);
extern int ivl_path_is_condit(ivl_delaypath_t obj);
extern int ivl_path_source_posedge(ivl_delaypath_t obj);
extern int ivl_path_source_negedge(ivl_delaypath_t obj);
@@ -1336,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
@@ -1388,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
@@ -1462,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);
@@ -1571,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);
@@ -1592,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);
+68 -25
View File
@@ -1,6 +1,6 @@
%{
/*
* Copyright (c) 1999-2007 Stephen Williams ([email protected])
* Copyright (c) 1999-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
@@ -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} {}
@@ -849,6 +849,34 @@ static int define_continue_flag = 0;
#define _STR1(x) #x
#define _STR2(x) _STR1(x)
/*
* Find an argument, but only if it is not directly preceded by something
* that would make it part of another simple identifier ([a-zA-Z0-9_$]).
*/
static char *find_arg(char*ptr, char*head, char*arg)
{
char *cp = ptr;
while (1) {
/* Look for a candidate match, just return if none is found. */
cp = strstr(cp, arg);
if (!cp) break;
/* If we are not at the start of the string verify that this
* match is not in the middle of another identifier.
*/
if (cp != head &&
(isalnum(*(cp-1)) || *(cp-1) == '_' || *(cp-1) == '$')) {
cp++;
continue;
}
break;
}
return cp;
}
/*
* Collect the definition. Normally, this returns 0. If there is a
* continuation, then return 1 and this function may be called again
@@ -968,7 +996,7 @@ static void do_define()
{
int argl = def_argl[arg];
cp = strstr(head, def_argv(arg));
cp = find_arg(head, head, def_argv(arg));
while (cp && *cp)
{
@@ -994,7 +1022,7 @@ static void do_define()
*cp++ = ARG_MARK;
*cp++ = arg;
cp = strstr(cp, def_argv(arg));
cp = find_arg(cp, head, def_argv(arg));
}
}
define_cnt += added_cnt;
@@ -1143,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;
}
}
@@ -1320,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];
@@ -1336,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);
}
}
}
@@ -1436,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;
@@ -1509,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
@@ -1607,6 +1647,8 @@ void load_precompiled_defines(FILE* src)
name = cp;
*cp++ = ch;
while ((ch = fgetc(src)) != EOF && ch != ':')
*cp++ = ch;
@@ -1669,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)
{
+22 -18
View File
@@ -1,5 +1,5 @@
const char COPYRIGHT[] =
"Copyright (c) 1999-2007 Stephen Williams ([email protected])";
"Copyright (c) 1999-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
@@ -202,23 +202,27 @@ int main(int argc, char*argv[])
FILE*precomp_out = NULL;
/* Define preprocessor keywords that I plan to just pass. */
define_macro("celldefine", "`celldefine", 1, 0);
define_macro("default_nettype", "`default_nettype", 1, 0);
define_macro("delay_mode_distributed", "`delay_mode_distributed", 1, 0);
define_macro("delay_mode_unit", "`delay_mode_unit", 1, 0);
define_macro("delay_mode_path", "`delay_mode_path", 1, 0);
define_macro("disable_portfaults", "`disable_portfaults", 1, 0);
define_macro("enable_portfaults", "`enable_portfaults", 1, 0);
define_macro("endcelldefine", "`endcelldefine", 1, 0);
define_macro("endprotect", "`endprotect", 1, 0);
define_macro("nosuppress_faults", "`nosuppress_faults", 1, 0);
define_macro("nounconnected_drive", "`nounconnected_drive", 1, 0);
define_macro("protect", "`protect", 1, 0);
define_macro("resetall", "`resetall", 1, 0);
define_macro("suppress_faults", "`suppress_faults", 1, 0);
define_macro("timescale", "`timescale", 1, 0);
define_macro("unconnected_drive", "`unconnected_drive", 1, 0);
define_macro("uselib", "`uselib", 1, 0);
define_macro("celldefine", "`celldefine", 1, 0);
define_macro("default_decay_time", "`default_decay_time", 1, 0);
define_macro("default_nettype", "`default_nettype", 1, 0);
define_macro("default_trireg_strength", "`default_trireg_strength", 1, 0);
define_macro("delay_mode_distributed", "`delay_mode_distributed", 1, 0);
define_macro("delay_mode_unit", "`delay_mode_unit", 1, 0);
define_macro("delay_mode_path", "`delay_mode_path", 1, 0);
define_macro("delay_mode_zero", "`delay_mode_zero", 1, 0);
define_macro("disable_portfaults", "`disable_portfaults", 1, 0);
define_macro("enable_portfaults", "`enable_portfaults", 1, 0);
define_macro("endcelldefine", "`endcelldefine", 1, 0);
define_macro("endprotect", "`endprotect", 1, 0);
define_macro("line", "`line", 1, 0);
define_macro("nosuppress_faults", "`nosuppress_faults", 1, 0);
define_macro("nounconnected_drive", "`nounconnected_drive", 1, 0);
define_macro("protect", "`protect", 1, 0);
define_macro("resetall", "`resetall", 1, 0);
define_macro("suppress_faults", "`suppress_faults", 1, 0);
define_macro("timescale", "`timescale", 1, 0);
define_macro("unconnected_drive", "`unconnected_drive", 1, 0);
define_macro("uselib", "`uselib", 1, 0);
include_cnt = 2;
include_dir = malloc(include_cnt*sizeof(char*));
+126 -31
View File
@@ -4,7 +4,7 @@
%{
/*
* Copyright (c) 1998-2007 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
@@ -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
@@ -48,6 +48,11 @@
*/
extern YYLTYPE yylloc;
static char* strdupnew(char const *str)
{
return str ? strcpy(new char [strlen(str)+1], str) : 0;
}
static const char* set_file_name(char*text)
{
perm_string path = filename_strings.make(text);
@@ -78,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;
%}
@@ -88,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(); }
@@ -205,22 +216,11 @@ W [ \t\b\f\r]+
int rc = lexor_keyword_code(yytext, yyleng);
switch (rc) {
case IDENTIFIER:
yylval.text = strdup(yytext);
yylval.text = strdupnew(yytext);
if (strncmp(yylval.text,"PATHPULSE$", 10) == 0)
rc = PATHPULSE_IDENTIFIER;
break;
case K_bool:
case K_logic:
case K_wone:
if (! gn_cadence_types_enabled()) {
yylval.text = strdup(yytext);
rc = IDENTIFIER;
} else {
yylval.text = 0;
}
break;
case K_edge:
BEGIN(EDGES);
break;
@@ -235,7 +235,7 @@ W [ \t\b\f\r]+
\\[^ \t\b\f\r\n]+ {
yylval.text = strdup(yytext+1);
yylval.text = strdupnew(yytext+1);
return IDENTIFIER; }
\$([a-zA-Z0-9$_]+) {
@@ -255,7 +255,7 @@ W [ \t\b\f\r]+
return K_Ssetup;
if (strcmp(yytext,"$width") == 0)
return K_Swidth;
yylval.text = strdup(yytext);
yylval.text = strdupnew(yytext);
return SYSTEM_IDENTIFIER; }
@@ -275,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; }
@@ -296,21 +336,76 @@ W [ \t\b\f\r]+
/* These are directives that I do not yet support. I think that IVL
should handle these, not an external preprocessor. */
^{W}?`celldefine{W}?.* { }
^{W}?`celldefine{W}?.* { }
^{W}?`default_decay_time{W}?.* { }
^{W}?`default_trireg_strength{W}?.* { }
^{W}?`delay_mode_distributed{W}?.* { }
^{W}?`delay_mode_unit{W}?.* { }
^{W}?`delay_mode_path{W}?.* { }
^{W}?`disable_portfaults{W}?.* { }
^{W}?`enable_portfaults{W}?.* { }
^{W}?`endcelldefine{W}?.* { }
`endprotect { }
^{W}?`nosuppress_faults{W}?.* { }
^{W}?`nounconnected_drive{W}?.* { }
`protect { }
^{W}?`resetall{W}?.* { }
^{W}?`suppress_faults{W}?.* { }
^{W}?`unconnected_drive{W}?.* { }
^{W}?`uselib{W}?.* { }
^{W}?`delay_mode_unit{W}?.* { }
^{W}?`delay_mode_path{W}?.* { }
^{W}?`delay_mode_zero{W}?.* { }
^{W}?`disable_portfaults{W}?.* { }
^{W}?`enable_portfaults{W}?.* { }
^{W}?`endcelldefine{W}?.* { }
`endprotect { }
^{W}?`line{W}?.* { }
^{W}?`nosuppress_faults{W}?.* { }
^{W}?`nounconnected_drive{W}?.* { }
`protect { }
^{W}?`resetall{W}?.* { }
^{W}?`suppress_faults{W}?.* { }
^{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
@@ -978,5 +1073,5 @@ void reset_lexor()
yylloc.first_line = 1;
/* Announce the first file name. */
yylloc.text = set_file_name(strdup(vl_file.c_str()));
yylloc.text = set_file_name(strdupnew(vl_file.c_str()));
}
+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;
}
+3 -32
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003 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
@@ -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: a_fetch_value.c,v 1.5 2003/06/17 16:55:07 steve Exp $"
#endif
# include <acc_user.h>
# include <vpi_user.h>
@@ -104,7 +101,8 @@ static char* fetch_strength_value(handle obj)
val.format = vpiStrengthVal;
vpi_get_value(obj, &val);
vpip_format_strength(str, &val);
/* Should this iterate over the bits? It now matches the old code. */
vpip_format_strength(str, &val, 0);
if (pli_trace) {
fprintf(pli_trace, "acc_fetch_value(<%s>, \"%%v\") --> %s\n",
@@ -125,30 +123,3 @@ char* acc_fetch_value(handle obj, const char*fmt, s_acc_value*value)
vpi_printf("XXXX acc_fetch_value(..., \"%s\", ...)\n", fmt);
return "<acc_fetch_value>";
}
/*
* $Log: a_fetch_value.c,v $
* Revision 1.5 2003/06/17 16:55:07 steve
* 1) setlinebuf() for vpi_trace
* 2) Addes error checks for trace file opens
* 3) removes now extraneous flushes
* 4) fixes acc_next() bug
*
* Revision 1.4 2003/05/18 00:16:35 steve
* Add PLI_TRACE tracing of PLI1 modules.
*
* Add tf_isetdelay and friends, and add
* callback return values for acc_vcl support.
*
* Revision 1.3 2003/04/24 02:02:37 steve
* Clean up some simple warnings.
*
* Revision 1.2 2003/04/20 02:49:07 steve
* acc_fetch_value support for %v format.
*
* Revision 1.1 2003/04/12 18:57:14 steve
* More acc_ function stubs.
*
*/
+66 -110
View File
@@ -1,6 +1,6 @@
const char COPYRIGHT[] =
"Copyright (c) 1998-2005 Stephen Williams ([email protected])";
"Copyright (c) 1998-2008 Stephen Williams ([email protected])";
/*
* This source code is free software; you can redistribute it
@@ -18,9 +18,6 @@ const char COPYRIGHT[] =
* 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: main.cc,v 1.95 2007/04/19 02:52:53 steve Exp $"
#endif
# include "config.h"
@@ -88,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;
@@ -113,6 +112,7 @@ FILE *depend_file = NULL;
bool warn_implicit = false;
bool warn_timescale = false;
bool warn_portbinding = false;
bool warn_inf_loop = false;
bool error_implicit = false;
@@ -199,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;
@@ -220,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;
@@ -434,6 +456,9 @@ static void read_iconfig_file(const char*ipath)
case 'i':
warn_implicit = true;
break;
case 'l':
warn_inf_loop = true;
break;
case 'p':
warn_portbinding = true;
break;
@@ -591,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)
@@ -604,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
@@ -619,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;
}
@@ -830,103 +886,3 @@ int main(int argc, char*argv[])
return des? des->errors : 1;
}
/*
* $Log: main.cc,v $
* Revision 1.95 2007/04/19 02:52:53 steve
* Add support for -v flag in command file.
*
* Revision 1.94 2007/03/07 04:24:59 steve
* Make integer width controllable.
*
* Revision 1.93 2006/09/28 04:35:18 steve
* Support selective control of specify and xtypes features.
*
* Revision 1.92 2005/07/14 23:38:43 steve
* Display as version 0.9.devel
*
* Revision 1.91 2005/07/07 16:22:49 steve
* Generalize signals to carry types.
*
* Revision 1.90 2005/06/28 04:25:55 steve
* Remove reference to SystemVerilog.
*
* Revision 1.89 2005/04/24 23:44:02 steve
* Update DFF support to new data flow.
*
* Revision 1.88 2005/01/22 01:06:55 steve
* Change case compare from logic to an LPM node.
*
* Revision 1.87 2004/12/11 02:31:26 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.86 2004/10/04 01:10:53 steve
* Clean up spurious trailing white space.
*
* Revision 1.85 2004/09/25 01:58:44 steve
* Add a debug_elaborate flag
*
* Revision 1.84 2004/09/10 23:51:42 steve
* Fix the evaluation of constant ternary expressions.
*
* Revision 1.83 2004/09/05 17:44:42 steve
* Add support for module instance arrays.
*
* Revision 1.82 2004/03/10 04:51:24 steve
* Add support for system function table files.
*
* Revision 1.81 2004/02/18 17:11:56 steve
* Use perm_strings for named langiage items.
*
* Revision 1.80 2004/02/15 00:19:29 steve
* Report elaboration errors without crashing.
*
* Revision 1.79 2003/11/26 01:37:14 steve
* Properly initialize vpi_module_list with system.
*
* Revision 1.78 2003/11/13 05:55:33 steve
* Move the DLL= flag to target config files.
*
* Revision 1.77 2003/11/13 04:09:49 steve
* Pass flags through the temporary config file.
*
* Revision 1.76 2003/11/13 03:10:38 steve
* ivl -F and -t flags are onpassed throught the -C file.
*
* Revision 1.75 2003/11/10 20:59:03 steve
* Design::get_flag returns const char* instead of string.
*
* Revision 1.74 2003/11/01 04:22:30 steve
* Accept functors in the config file.
*
* Revision 1.73 2003/10/26 22:43:42 steve
* Improve -V messages,
*
* Revision 1.72 2003/09/26 02:17:14 steve
* Delete pform when done with it.
*
* Revision 1.71 2003/09/25 00:25:14 steve
* Summary list of missing modules.
*
* Revision 1.70 2003/09/23 05:57:36 steve
* Pass -m flag from driver via iconfig file.
*
* Revision 1.69 2003/09/22 01:12:08 steve
* Pass more ivl arguments through the iconfig file.
*
* Revision 1.68 2003/06/20 00:53:19 steve
* Module attributes from the parser
* through to elaborated form.
*
* Revision 1.67 2003/04/24 05:25:27 steve
* Dump design even on errors.
*
* Revision 1.66 2003/03/01 06:25:30 steve
* Add the lex_strings string handler, and put
* scope names and system task/function names
* into this table. Also, permallocate event
* names from the beginning.
*/
+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>
+3 -5
View File
@@ -377,10 +377,6 @@ void NetScope::evaluate_parameters(Design*des)
assert(nexpr);
delete expr;
(*cur).second.expr = nexpr;
// Set the signedness flag.
(*cur).second.expr
->cast_signed( (*cur).second.signed_flag );
}
break;
@@ -393,7 +389,9 @@ void NetScope::evaluate_parameters(Design*des)
}
/* If the parameter has range information, then make
sure the value is set right. */
sure the value is set right. Note that if the
parameter doesn't have an explicit range, then it
will get the signedness from the expression itself. */
if (range_flag) {
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
wid += 1;
+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)
{
+2 -85
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-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: net_link.cc,v 1.21 2007/06/02 03:42:13 steve Exp $"
#endif
# include "config.h"
@@ -431,7 +428,7 @@ NexusSet::~NexusSet()
{
if (nitems_ > 0) {
assert(items_ != 0);
delete[] items_;
free(items_);
} else {
assert(items_ == 0);
}
@@ -541,83 +538,3 @@ bool NexusSet::intersect(const NexusSet&that) const
return false;
}
/*
* $Log: net_link.cc,v $
* Revision 1.21 2007/06/02 03:42:13 steve
* Properly evaluate scope path expressions.
*
* Revision 1.20 2007/03/26 18:17:50 steve
* Remove pretense of general use for t_cookie.
*
* Revision 1.19 2006/02/02 02:43:58 steve
* Allow part selects of memory words in l-values.
*
* Revision 1.18 2005/09/25 23:40:11 steve
* Simplify NexusSet set handling.
*
* Revision 1.17 2005/06/13 23:22:37 steve
* Fix compile errors.
*
* Revision 1.16 2005/04/24 23:44:02 steve
* Update DFF support to new data flow.
*
* Revision 1.15 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.14 2004/02/18 17:11:56 steve
* Use perm_strings for named langiage items.
*
* Revision 1.13 2003/01/14 21:16:18 steve
* Move strstream to ostringstream for compatibility.
*
* Revision 1.12 2002/10/21 01:42:08 steve
* Synthesizer support for synchronous begin-end blocks.
*
* Revision 1.11 2002/08/18 22:07:16 steve
* Detect temporaries in sequential block synthesis.
*
* Revision 1.10 2002/08/12 01:34:59 steve
* conditional ident string using autoconfig.
*
* Revision 1.9 2002/07/03 03:08:47 steve
* Clear drive cache on link or unlink.
*
* Revision 1.8 2002/06/30 02:21:31 steve
* Add structure for asynchronous logic synthesis.
*
* Revision 1.7 2002/06/24 01:49:39 steve
* Make link_drive_constant cache its results in
* the Nexus, to improve cprop performance.
*
* Revision 1.6 2002/04/21 04:59:08 steve
* Add support for conbinational events by finding
* the inputs to expressions and some statements.
* Get case and assignment statements working.
*
* Revision 1.5 2001/07/25 03:10:49 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.4 2000/10/06 23:46:50 steve
* ivl_target updates, including more complete
* handling of ivl_nexus_t objects. Much reduced
* dependencies on pointers to netlist objects.
*
* Revision 1.3 2000/08/26 00:54:03 steve
* Get at gate information for ivl_target interface.
*
* Revision 1.2 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.1 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
*/
+48 -19
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-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: net_scope.cc,v 1.38 2007/06/02 03:42:13 steve Exp $"
#endif
# include "config.h"
# include "compiler.h"
@@ -44,11 +41,13 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t)
lcounter_ = 0;
if (up) {
default_nettype_ = up->default_nettype();
time_unit_ = up->time_unit();
time_prec_ = up->time_precision();
sib_ = up_->sub_;
up_->sub_ = this;
} else {
default_nettype_ = NetNet::NONE;
time_unit_ = 0;
time_prec_ = 0;
assert(t == MODULE);
@@ -79,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;
@@ -88,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;
}
@@ -110,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;
@@ -140,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;
}
@@ -403,4 +433,3 @@ string NetScope::local_hsymbol()
return string(name()) + "." + string(local_symbol());
}
#endif
+237 -8
View File
@@ -235,11 +235,12 @@ NetBus::~NetBus()
{
}
NetDelaySrc::NetDelaySrc(NetScope*s, perm_string n,
unsigned npins, bool condit_src)
NetDelaySrc::NetDelaySrc(NetScope*s, perm_string n, unsigned npins,
bool condit_src, bool conditional)
: NetObj(s, n, npins + (condit_src?1:0))
{
condit_flag_ = false;
conditional_ = conditional;
posedge_ = false;
negedge_ = false;
for (unsigned idx = 0 ; idx < npins ; idx += 1) {
@@ -379,6 +380,11 @@ const Link& NetDelaySrc::src_pin(unsigned idx) const
}
bool NetDelaySrc::is_condit() const
{
return conditional_;
}
bool NetDelaySrc::has_condit() const
{
return condit_flag_;
}
@@ -398,8 +404,8 @@ const Link& NetDelaySrc::condit_pin() const
NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
: NetObj(s, n, 1), sig_next_(0), sig_prev_(0),
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), msb_(npins-1), lsb_(0), dimensions_(0), s0_(0), e0_(0),
local_flag_(false), eref_count_(0), lref_count_(0)
signed_(false), isint_(false), msb_(npins-1), lsb_(0), dimensions_(0),
s0_(0), e0_(0), local_flag_(false), eref_count_(0), lref_count_(0)
{
assert(s);
assert(npins>0);
@@ -438,7 +444,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
: NetObj(s, n, 1),
sig_next_(0), sig_prev_(0), type_(t),
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
msb_(ms), lsb_(ls), dimensions_(0), s0_(0), e0_(0),
isint_(false), msb_(ms), lsb_(ls), dimensions_(0), s0_(0), e0_(0),
local_flag_(false), eref_count_(0), lref_count_(0)
{
assert(s);
@@ -484,8 +490,8 @@ static unsigned calculate_count(long s, long e)
NetNet::NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls, long array_s, long array_e)
: NetObj(s, n, calculate_count(array_s, array_e)),
sig_next_(0), sig_prev_(0), type_(t),
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
sig_next_(0), sig_prev_(0), type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
msb_(ms), lsb_(ls), dimensions_(1), s0_(array_s), e0_(array_e),
local_flag_(false), eref_count_(0), lref_count_(0)
{
@@ -642,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_;
@@ -1040,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:
@@ -2288,6 +2312,7 @@ NetEUnary::NetEUnary(char op, NetExpr*ex)
switch (op_) {
case '-':
case '+':
case 'm': // abs()
cast_signed(ex->has_sign());
break;
default:
@@ -2417,3 +2442,207 @@ const NetProc*NetTaskDef::proc() const
{
return proc_;
}
/*
* These are the delay_type() functions. They are used to determine
* the type of delay for the given object.
*/
/*
* This function implements the following table:
*
* in_A in_B out
* NO NO NO
* NO ZERO ZERO
* NO POS POS
* NO DEF POS
* ZERO NO ZERO
* ZERO ZERO ZERO
* ZERO POS POS
* ZERO DEF POS
* POS NO POS
* POS ZERO POS
* POS POS POS
* POS DEF POS
* DEF NO POS
* DEF ZERO POS
* DEF POS POS
* DEF DEF DEF
*
* It is used to combine two delay values.
*/
static DelayType combine_delays(const DelayType a, const DelayType b)
{
/* The default is POSSIBLE_DELAY. */
DelayType result = POSSIBLE_DELAY;
/* If both are no or zero delay then we return ZERO_DELAY. */
if ((a == NO_DELAY || a == ZERO_DELAY) &&
(b == NO_DELAY || b == ZERO_DELAY)) {
result = ZERO_DELAY;
}
/* Except if both are no delay then we return NO_DELAY. */
if (a == NO_DELAY && b == NO_DELAY) {
result = NO_DELAY;
}
/* If both are definite delay then we return DEFINITE_DELAY. */
if (a == DEFINITE_DELAY && b == DEFINITE_DELAY) {
result = DEFINITE_DELAY;
}
return result;
}
/*
* This is used to see what we can find out about the delay when it
* is given as an expression. We also use this for loop expressions.
*/
static DelayType delay_type_from_expr(const NetExpr*expr)
{
DelayType result = POSSIBLE_DELAY;
if (const NetEConst*e = dynamic_cast<const NetEConst*>(expr)) {
if (e->value().is_zero()) result = ZERO_DELAY;
else result = DEFINITE_DELAY;
}
if (const NetECReal*e = dynamic_cast<const NetECReal*>(expr)) {
if (e->value().as_double() == 0.0) result = ZERO_DELAY;
else result = DEFINITE_DELAY;
}
return result;
}
/*
* The looping structures can use the same basic code so put it here
* instead of duplicating it for each one (repeat and while).
*/
static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc)
{
DelayType result;
switch (delay_type_from_expr(expr)) {
/* We have a constant false expression so the body never runs. */
case ZERO_DELAY:
result = NO_DELAY;
break;
/* We have a constant true expression so the body always runs. */
case DEFINITE_DELAY:
result = proc->delay_type();
break;
/* We don't know if the body will run so reduce a DEFINITE_DELAY
* to a POSSIBLE_DELAY. All other stay the same. */
case POSSIBLE_DELAY:
result = combine_delays(NO_DELAY, proc->delay_type());
break;
/* This should never happen since delay_type_from_expr() only
* returns three different values. */
default:
assert(0);
}
return result;
}
/* The default object does not have any delay. */
DelayType NetProc::delay_type() const
{
return NO_DELAY;
}
DelayType NetBlock::delay_type() const
{
DelayType result = NO_DELAY;
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
DelayType dt = cur->delay_type();
if (dt > result) result = dt;
}
return result;
}
DelayType NetCase::delay_type() const
{
DelayType result = NO_DELAY;
bool def_stmt = false;
unsigned nstmts = nitems();
for (unsigned idx = 0; idx < nstmts; idx += 1) {
if (!expr(idx)) def_stmt = true;
if (idx == 0) {
result = stat(idx)->delay_type();
} else {
result = combine_delays(result, stat(idx)->delay_type());
}
}
/* If we don't have a default statement we don't know for sure
* that we have a delay. */
if (!def_stmt) result = combine_delays(NO_DELAY, result);
return result;
}
DelayType NetCondit::delay_type() const
{
DelayType result;
if (else_) {
result = combine_delays(if_->delay_type(), else_->delay_type());
} else {
result = if_->delay_type();
}
return result;
}
DelayType NetEvWait::delay_type() const
{
return DEFINITE_DELAY;
}
DelayType NetForever::delay_type() const
{
return statement_->delay_type();
}
DelayType NetPDelay::delay_type() const
{
if (expr_) {
return delay_type_from_expr(expr_);
} else {
if (delay() > 0) {
return DEFINITE_DELAY;
} else {
if (statement_) {
return statement_->delay_type();
} else {
return NO_DELAY;
}
}
}
}
DelayType NetRepeat::delay_type() const
{
return get_loop_delay_type(expr_, statement_);
}
DelayType NetTaskDef::delay_type() const
{
return proc_->delay_type();
}
DelayType NetUTask::delay_type() const
{
return task()->task_def()->delay_type();
}
DelayType NetWhile::delay_type() const
{
return get_loop_delay_type(cond_, proc_);
}
+81 -5
View File
@@ -382,8 +382,8 @@ class NetNode : public NetObj {
class NetDelaySrc : public NetObj {
public:
explicit NetDelaySrc(NetScope*s, perm_string n,
unsigned nsrc, bool condit_src);
explicit NetDelaySrc(NetScope*s, perm_string n, unsigned nsrc,
bool condit_src, bool conditional);
~NetDelaySrc();
// These functions set the delays from the values in the
@@ -415,6 +415,7 @@ class NetDelaySrc : public NetObj {
const Link&src_pin(unsigned) const;
bool is_condit() const;
bool has_condit() const;
Link&condit_pin();
const Link&condit_pin() const;
@@ -423,6 +424,7 @@ class NetDelaySrc : public NetObj {
private:
uint64_t transition_delays_[12];
bool condit_flag_;
bool conditional_;
bool posedge_;
bool negedge_;
@@ -508,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
@@ -576,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
@@ -1640,6 +1663,7 @@ class NetUDP : public NetNode {
PUdp *udp;
};
enum DelayType { NO_DELAY, ZERO_DELAY, POSSIBLE_DELAY, DEFINITE_DELAY };
/* =========
* A process is a behavioral-model description. A process is a
@@ -1689,6 +1713,9 @@ class NetProc : public virtual LineInfo {
virtual void dump(ostream&, unsigned ind) const;
// Recursively checks to see if there is delay in this element.
virtual DelayType delay_type() const;
private:
friend class NetBlock;
NetProc*next_;
@@ -1896,6 +1923,7 @@ class NetBlock : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private:
const Type type_;
@@ -1939,6 +1967,7 @@ class NetCase : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private:
@@ -2012,6 +2041,7 @@ class NetCondit : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private:
NetExpr* expr_;
@@ -2229,6 +2259,7 @@ class NetEvWait : public NetProc {
const svector<NetEvProbe*>&events);
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private:
NetProc*statement_;
@@ -2296,6 +2327,7 @@ class NetForever : public NetProc {
virtual NexusSet* nex_input(bool rem_out = true);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private:
NetProc*statement_;
@@ -2368,6 +2400,7 @@ class NetPDelay : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
bool emit_proc_recurse(struct target_t*) const;
@@ -2392,6 +2425,7 @@ class NetRepeat : public NetProc {
virtual NexusSet* nex_input(bool rem_out = true);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private:
NetExpr*expr_;
@@ -2473,6 +2507,7 @@ class NetTaskDef {
NetNet*port(unsigned idx);
void dump(ostream&, unsigned) const;
DelayType delay_type() const;
private:
NetScope*scope_;
@@ -2541,6 +2576,7 @@ class NetUTask : public NetProc {
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private:
NetScope*task_;
@@ -2565,6 +2601,7 @@ class NetWhile : public NetProc {
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private:
NetExpr* cond_;
@@ -2648,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 {
@@ -2815,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.
@@ -3127,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 {
@@ -3257,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,
@@ -3303,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;
@@ -3364,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;
@@ -3393,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_;
+19
View File
@@ -123,6 +123,25 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
return res;
}
NetExpr* condition_reduce(NetExpr*expr)
{
if (expr->expr_width() == 1)
return expr;
verinum zero (verinum::V0, expr->expr_width());
NetEConst*ezero = new NetEConst(zero);
ezero->cast_signed(expr->has_sign());
ezero->set_line(*expr);
ezero->set_width(expr->expr_width());
NetEBComp*cmp = new NetEBComp('n', expr, ezero);
cmp->cast_signed(false);
cmp->set_line(*expr);
return cmp;
}
NetExpr* elab_and_eval(Design*des, NetScope*scope,
const PExpr*pe, int expr_wid, int prune_width)
{
+7
View File
@@ -64,6 +64,13 @@ extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w);
extern NetNet*pad_to_width_signed(Design*des, NetNet*n, unsigned w);
/*
* Take the input expression and return a variation that assures that
* the expression is 1-bit wide and logical. This reflects the needs
* of conditions i.e. for "if" statements or logical operators.
*/
extern NetExpr*condition_reduce(NetExpr*expr);
/*
* This function transforms an expression by cropping the high bits
* off with a part select. The result has the width w passed in. This
+429 -164
View File
File diff suppressed because it is too large Load Diff
+15 -9
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
@@ -350,8 +350,8 @@ void pform_endmodule(const char*name)
msg << "Module " << name << " was already declared here: "
<< (*test).second->get_fileline() << endl;
VLerror(msg.str().c_str());
pform_cur_module = 0;
return;
} else {
pform_modules[mod_name] = pform_cur_module;
}
// The current lexical scope should be this module by now, and
@@ -360,15 +360,16 @@ void pform_endmodule(const char*name)
lexical_scope = pform_cur_module->pscope_parent();
ivl_assert(*pform_cur_module, lexical_scope == 0);
pform_modules[mod_name] = pform_cur_module;
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;
@@ -1640,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;
@@ -1656,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;
@@ -1677,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)
@@ -1926,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;
}
+63
View File
@@ -0,0 +1,63 @@
#!/bin/sh
# This script makes snapshots from a git repository. The input is
# the number for a snapshot and the path to a temporary directory.
# for example:
#
# sh scripts/MAKE_SNAPSHOT.sh 20080428 ~/tmp
#
# The above assumes that there is a tag "s20080428" at the point
# to be snaphot. (The tag has the "s", but the argument to this
# script does not have the "s"). This script extracts based on the
# tag, uses the temporary directory to stage intermediate results,
# and finally creates a file called verilog-20080428.tar.gz that
# contains the snapshot ready to go.
#
# The complete steps to make a snapshot YYYYMMDD generally are:
#
# git tag -a sYYYYMMDD
# (Make the tag in the local git repository.)
#
# sh scripts/MAKE_SNAPSHOT.sh YYYYMMDD ~/tmp
# (Make the snapshot bundle verilog-YYYYMMDD.tar.gz)
#
# git push --tags
# (Publish the tag to the repository.)
#
id=$1
destdir=$2
# The git tag to use is the snapshot id with a prepended "s".
tag="s$id"
# The prefix is the directory that contains the extracted files
# of the bundle. This is also the name of the bundle file itself.
prefix="verilog-$id"
if [ ! -d $destdir ]; then
echo "ERROR: Directory $destdir does not exist."
exit 1
fi
if [ -e $destdir/$prefix ]; then
echo "ERROR: $destdir/$prefix already exists."
exit 1
fi
echo "Exporting $tag to $destdir/$prefix..."
git-archive --prefix="$prefix/" $tag | ( cd "$destdir" && tar xf - )
versionh="$destdir/$prefix/version.h"
echo "Create $versionh ..."
echo "#define VERSION_TAG \"$tag\"" > $versionh
echo "Running autoconf.sh..."
( cd $destdir/$prefix && sh autoconf.sh )
echo "Making bundle $prefix.tar.gz..."
tar czf $prefix.tar.gz --exclude=autom4te.cache -C "$destdir" $prefix
echo "Removing temporary $destdir/$prefix..."
rm -rf "$destdir/$prefix"
echo done
+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)
+4 -1
View File
@@ -1,7 +1,7 @@
%{
/*
* Copyright (c) 2000-2005 Stephen Williams ([email protected])
* Copyright (c) 2000-2007 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
@@ -263,6 +263,9 @@ struct tokenize : public proc_match_t {
last_->next_ = cur;
last_ = cur;
/* Because synthesis is broken this is needed to prevent
* a seg. fault. */
if (!dev->if_clause()) return 0;
dev -> if_clause() -> match_proc(this);
if (dev->else_clause()) {
+60
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);
@@ -1356,6 +1374,12 @@ extern "C" ivl_nexus_t ivl_path_condit(ivl_delaypath_t obj)
return obj->condit;
}
extern "C" int ivl_path_is_condit(ivl_delaypath_t obj)
{
assert(obj);
return obj->conditional ? 1 : 0;
}
extern uint64_t ivl_path_delay(ivl_delaypath_t obj, ivl_path_edge_t edg)
{
assert(obj);
@@ -1450,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);
@@ -1463,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);
@@ -1709,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_;
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-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
@@ -183,6 +183,7 @@ void dll_target::expr_concat(const NetEConcat*net)
cur->type_ = IVL_EX_CONCAT;
cur->value_ = IVL_VT_VECTOR;
cur->width_ = net->expr_width();
cur->signed_ = 0;
cur->u_.concat_.rept = net->repeat();
cur->u_.concat_.parms = net->nparms();
@@ -474,4 +475,3 @@ void dll_target::expr_unary(const NetEUnary*net)
expr_->u_.unary_.op_ = net->op();
expr_->u_.unary_.sub_ = sub;
}
+44 -1
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;
@@ -1246,6 +1251,8 @@ void dll_target::udp(const NetUDP*net)
u->sequ = net->is_sequential();
if (u->sequ)
u->init = net->get_initial();
else
u->init = 'x';
u->name = net->udp_name();
string inp;
char out;
@@ -1300,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;
@@ -2140,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());
@@ -2212,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) {
@@ -2380,7 +2422,7 @@ bool dll_target::signal_paths(const NetNet*net)
/* If this path has a condition, then hook it up. */
ivl_nexus_t path_condit = 0;
if (src->is_condit()) {
if (src->has_condit()) {
const Nexus*nt = src->condit_pin().nexus();
path_condit = nt->t_cookie();
}
@@ -2397,6 +2439,7 @@ bool dll_target::signal_paths(const NetNet*net)
obj->path[ptr].scope = lookup_scope_(src->scope());
obj->path[ptr].src = nex->t_cookie();
obj->path[ptr].condit = path_condit;
obj->path[ptr].conditional = src->is_condit();
obj->path[ptr].posedge = src->is_posedge();
obj->path[ptr].negedge = src->is_negedge();
for (unsigned pe = 0 ; pe < 12 ; pe += 1) {
+18
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*);
@@ -178,6 +179,7 @@ struct ivl_delaypath_s {
ivl_scope_t scope;
ivl_nexus_t src;
ivl_nexus_t condit;
bool conditional;
bool posedge;
bool negedge;
uint64_t delay[12];
@@ -508,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
@@ -536,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_;
@@ -576,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;
@@ -712,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:
+32 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2005 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-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: stub.c,v 1.148 2007/06/12 02:23:40 steve Exp $"
#endif
/*
* This is a sample target module. All this does is write to the
@@ -178,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);
@@ -799,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;
@@ -1166,6 +1193,7 @@ static void show_signal(ivl_signal_t net)
if (posedge) fprintf(out, " posedge");
if (negedge) fprintf(out, " negedge");
if (con) fprintf(out, " (if %s)", ivl_nexus_name(con));
else if (ivl_path_is_condit(path)) fprintf(out, " (ifnone)");
fprintf(out, " %" PRIu64 ",%" PRIu64 ",%" PRIu64
" %" PRIu64 ",%" PRIu64 ",%" PRIu64
" %" PRIu64 ",%" PRIu64 ",%" PRIu64
@@ -1549,4 +1577,3 @@ int target_design(ivl_design_t des)
return stub_errors;
}
+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");
}
+9
View File
@@ -112,6 +112,15 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid)
res.base = allocate_vector(wid);
res.wid = wid;
if (res.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits for function result.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
return res;
}
assert(res.base != 0);
unsigned load_wid = swid;
if (load_wid > ivl_signal_width(retval))
+116 -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");
}
@@ -303,6 +276,13 @@ struct vector_info draw_vpi_func_call(ivl_expr_t fnet, unsigned wid)
res.base = allocate_vector(wid);
res.wid = wid;
if (res.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits for system function result.\n",
ivl_expr_file(fnet), ivl_expr_lineno(fnet), wid);
vvp_errors += 1;
}
sprintf(call_string, " %%vpi_func %u %u \"%s\", %u, %u",
ivl_file_table_index(ivl_expr_file(fnet)),
ivl_expr_lineno(fnet), ivl_expr_name(fnet), res.base, res.wid);
+246 -31
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);
@@ -277,6 +291,14 @@ static struct vector_info draw_eq_immediate(ivl_expr_t exp, unsigned ewid,
expressions. */
if (lv.base < 8) {
unsigned base = allocate_vector(ewid);
if (base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of equality compare.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
lv.base = base;
lv.wid = ewid;
@@ -285,6 +307,14 @@ static struct vector_info draw_eq_immediate(ivl_expr_t exp, unsigned ewid,
} else if (lv.wid < ewid) {
unsigned base = allocate_vector(ewid);
if (base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of equality compare.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
if (lv.base >= 8)
clr_vector(lv);
fprintf(vvp_out, " %%mov %u, %u, %u;\n", base,
@@ -309,6 +339,7 @@ static struct vector_info draw_binary_expr_eq_real(ivl_expr_t exp)
res.base = allocate_vector(1);
res.wid = 1;
assert(res.base);
lword = draw_eval_real(ivl_expr_oper1(exp));
rword = draw_eval_real(ivl_expr_oper2(exp));
@@ -441,6 +472,14 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t exp,
uses. This is because that bit may be clobbered by other
expressions. */
{ unsigned base = allocate_vector(ewid);
if (base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of equality compare.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
lv.base = base;
lv.wid = ewid;
@@ -467,6 +506,7 @@ static struct vector_info draw_binary_expr_land(ivl_expr_t exp, unsigned wid)
clr_vector(lv);
tmp.base = allocate_vector(1);
tmp.wid = 1;
assert(tmp.base);
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
lv.base, lv.wid);
lv = tmp;
@@ -478,6 +518,7 @@ static struct vector_info draw_binary_expr_land(ivl_expr_t exp, unsigned wid)
clr_vector(rv);
tmp.base = allocate_vector(1);
tmp.wid = 1;
assert(tmp.base);
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
rv.base, rv.wid);
rv = tmp;
@@ -514,6 +555,14 @@ static struct vector_info draw_binary_expr_land(ivl_expr_t exp, unsigned wid)
/* Write the result into a zero-padded result. */
{ unsigned base = allocate_vector(wid);
if (base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of padded logical AND.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
clr_vector(lv);
lv.base = base;
@@ -541,6 +590,7 @@ static struct vector_info draw_binary_expr_lor(ivl_expr_t exp, unsigned wid)
clr_vector(lv);
tmp.base = allocate_vector(1);
tmp.wid = 1;
assert(tmp.base);
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
lv.base, lv.wid);
lv = tmp;
@@ -555,6 +605,7 @@ static struct vector_info draw_binary_expr_lor(ivl_expr_t exp, unsigned wid)
clr_vector(rv);
tmp.base = allocate_vector(1);
tmp.wid = 1;
assert(tmp.base);
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
rv.base, rv.wid);
rv = tmp;
@@ -592,6 +643,14 @@ static struct vector_info draw_binary_expr_lor(ivl_expr_t exp, unsigned wid)
/* Write the result into a zero-padded result. */
{ unsigned base = allocate_vector(wid);
if (base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of padded logical OR.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
clr_vector(lv);
lv.base = base;
@@ -615,6 +674,8 @@ static struct vector_info draw_binary_expr_le_real(ivl_expr_t exp)
res.base = allocate_vector(1);
res.wid = 1;
assert(res.base);
clr_word(lword);
clr_word(rword);
@@ -695,6 +756,14 @@ static struct vector_info draw_binary_expr_le_bool(ivl_expr_t exp,
uses. This is because that bit may be clobbered by other
expressions. */
{ unsigned base = allocate_vector(wid);
if (base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of padded inequality compare.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, 5, 1;\n", base);
tmp.base = base;
tmp.wid = wid;
@@ -822,6 +891,14 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
uses. This is because that bit may be clobbered by other
expressions. */
{ unsigned base = allocate_vector(wid);
if (base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of padded inequality compare.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, 5, 1;\n", base);
lv.base = base;
lv.wid = wid;
@@ -858,6 +935,14 @@ static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
struct vector_info tmp;
tmp.base = allocate_vector(lv.wid);
tmp.wid = lv.wid;
if (tmp.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of binary logic.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, lv.base, tmp.wid);
lv = tmp;
@@ -867,17 +952,17 @@ static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
switch (ivl_expr_opcode(exp)) {
case '&':
fprintf(vvp_out, " %%and %u, %u, %u;\n",
fprintf(vvp_out, " %%and %u, %u, %u;\n",
lv.base, rv.base, wid);
break;
case '|':
fprintf(vvp_out, " %%or %u, %u, %u;\n",
fprintf(vvp_out, " %%or %u, %u, %u;\n",
lv.base, rv.base, wid);
break;
case '^':
fprintf(vvp_out, " %%xor %u, %u, %u;\n",
fprintf(vvp_out, " %%xor %u, %u, %u;\n",
lv.base, rv.base, wid);
break;
@@ -933,6 +1018,14 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
struct vector_info tmp;
tmp.base = allocate_vector(lv.wid);
tmp.wid = lv.wid;
if (tmp.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of left shift (<<).\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, lv.base, lv.wid);
lv = tmp;
@@ -960,6 +1053,14 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
struct vector_info tmp;
tmp.base = allocate_vector(lv.wid);
tmp.wid = lv.wid;
if (tmp.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of right shift (>>).\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), lv.wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, lv.base, lv.wid);
lv = tmp;
@@ -992,6 +1093,14 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
struct vector_info tmp;
tmp.base = allocate_vector(lv.wid);
tmp.wid = lv.wid;
if (tmp.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of right shift (>>>).\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), lv.wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, lv.base, lv.wid);
lv = tmp;
@@ -1030,6 +1139,13 @@ static struct vector_info draw_load_add_immediate(ivl_expr_t le,
imm = get_number_immediate(re);
lv.base = allocate_vector(wid);
lv.wid = wid;
if (lv.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of addition.\n",
ivl_expr_file(le), ivl_expr_lineno(le), wid);
vvp_errors += 1;
}
/* Load the signal value with a %load that adds the index
register to the value being loaded. */
@@ -1093,6 +1209,14 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
case 0:
case 1:
tmp = allocate_vector(wid);
if (tmp == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of subtraction.\n",
ivl_expr_file(le), ivl_expr_lineno(le), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
lv.base = tmp;
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
@@ -1136,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)
@@ -1205,6 +1329,14 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
tmp.base = allocate_vector(wid);
tmp.wid = wid;
if (tmp.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of arithmetic expression.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp.base,
lv.base, wid);
lv = tmp;
@@ -1343,6 +1475,14 @@ static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid,
/* Allocate a vector to hold the result. */
res.base = allocate_vector(wid);
res.wid = wid;
if (res.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of concatenation.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
/* Get the repeat count. This must be a constant that has been
evaluated at compile time. The operands will be repeated to
@@ -1464,6 +1604,13 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
vector. Allocate the vector and use %mov instructions to
load the constant bit values. */
res.base = allocate_vector(wid);
if (res.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for number value.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
if ((!number_is_unknown(exp)) && number_is_immediate(exp, 16)) {
int val = get_number_immediate(exp);
@@ -1490,7 +1637,7 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
break;
}
for (cnt = 1 ; idx+cnt < wid ; cnt += 1)
for (cnt = 1 ; idx+cnt < nwid ; cnt += 1)
if (bits[idx+cnt] != bits[idx])
break;
@@ -1546,6 +1693,13 @@ static struct vector_info draw_pad_expr(ivl_expr_t exp, unsigned wid)
res.base = allocate_vector(wid);
res.wid = wid;
if (res.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"to pad expression.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
res.base, subv.base, subv.wid);
@@ -1580,6 +1734,7 @@ static struct vector_info draw_realnum_expr(ivl_expr_t exp, unsigned wid)
res.base = allocate_vector(wid);
res.wid = wid;
assert(res.base);
addr = res.base;
run = 1;
@@ -1620,7 +1775,7 @@ static char *process_octal_codes(const char *in, unsigned width)
return out;
}
while (idx < str_len) {
while (ridx < str_len) {
/* An octal constant always has three digits. */
if (in[ridx] == '\\') {
out[idx] = (in[ridx+1]-'0')*64 + (in[ridx+2]-'0')*8 +
@@ -1666,6 +1821,13 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
vector. Allocate the vector and use %mov instructions to
load the constant bit values. */
res.base = allocate_vector(wid);
if (res.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for string value.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
/* Since this is a string, we know that all the bits are
defined and each character represents exactly 8 bits. Use
@@ -1746,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;
}
@@ -1819,6 +1976,14 @@ static struct vector_info draw_signal_expr(ivl_expr_t exp, unsigned wid,
res.base = allocate_vector(wid);
res.wid = wid;
if (res.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"to load variable/wire.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
save_expression_lookaside(res.base, exp, wid);
draw_signal_dest(exp, res, -1, 0L);
@@ -1846,6 +2011,13 @@ static struct vector_info draw_select_array(ivl_expr_t sube,
res.base = allocate_vector(wid);
res.wid = wid;
if (res.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"to hold selected value.\n",
ivl_expr_file(sube), ivl_expr_lineno(sube), wid);
vvp_errors += 1;
}
for (idx = 0 ; idx < wid ; idx += 1) {
fprintf(vvp_out, " %%load/avx.p %u, v%p, 0;\n", res.base+idx, sig);
@@ -1867,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
@@ -1891,6 +2065,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
res.base = allocate_vector(wid);
res.wid = wid;
assert(res.base);
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Only need %u of %u bits\n",
res.base, sig, use_word, bit_wid, bit_wid, ivl_expr_width(sube));
@@ -1907,6 +2082,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
/* Alas, do it the hard way. */
res.base = allocate_vector(wid);
res.wid = wid;
assert(res.base);
for (idx = 0 ; idx < res.wid ; idx += 1) {
if (idx >= bit_wid) {
@@ -1981,6 +2157,7 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
if (subv.base < 4) {
res.base = allocate_vector(subv.wid);
res.wid = subv.wid;
assert(res.base);
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base,
subv.base, res.wid);
subv = res;
@@ -2051,6 +2228,7 @@ static struct vector_info draw_ternary_expr(ivl_expr_t exp, unsigned wid)
struct vector_info tmp;
tmp.base = allocate_vector(wid);
tmp.wid = wid;
assert(tmp.base);
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, tru.base, wid);
tru = tmp;
@@ -2108,6 +2286,7 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t exp, unsigned wid)
|| ivl_expr_value(exp) == IVL_VT_BOOL);
res.base = allocate_vector(wid);
res.wid = wid;
assert(res.base);
fprintf(vvp_out, " %%vpi_func %u %u \"%s\", %u, %u;\n",
ivl_file_table_index(ivl_expr_file(exp)),
ivl_expr_lineno(exp), ivl_expr_name(exp),
@@ -2221,6 +2400,14 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
struct vector_info tmp;
tmp.base = allocate_vector(wid);
tmp.wid = wid;
if (tmp.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"to pad unary expression result.\n",
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, res.base, res.wid);
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
@@ -2246,6 +2433,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
if (res.base < 4) {
tmp.base = allocate_vector(res.wid);
tmp.wid = res.wid;
assert(res.base);
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, res.base, res.wid);
res = tmp;
@@ -2269,6 +2457,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
struct vector_info tmp;
tmp.base = allocate_vector(wid);
tmp.wid = wid;
assert(res.base);
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, res.base, res.wid);
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
@@ -2278,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));
+88 -1
View File
@@ -51,11 +51,40 @@ void clr_word(int res)
word_alloc_mask &= ~ (1U << res);
}
static int draw_binary_real(ivl_expr_t exp)
{
int l, r = -1;
/* If the opcode is a vector only opcode then the sub expression
* must not be a real expression, so use vector evaluation and
* then convert that result to a real value. */
switch (ivl_expr_opcode(exp)) {
case 'E':
case 'N':
case 'l':
case 'r':
case 'R':
case '&':
case '|':
case '^':
case 'A':
case 'O':
case 'X':
{
struct vector_info vi;
vi = draw_eval_expr(exp, STUFF_OK_XZ);
int res = allocate_word();
const char*sign_flag = ivl_expr_signed(exp)? "/s" : "";
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, vi.base, vi.wid);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
clr_vector(vi);
return res;
}
}
l = draw_eval_real(ivl_expr_oper1(exp));
r = draw_eval_real(ivl_expr_oper2(exp));
@@ -83,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));
@@ -359,6 +424,23 @@ static int draw_ternary_real(ivl_expr_t exp)
static int draw_unary_real(ivl_expr_t exp)
{
/* If the opcode is a ~ then the sub expression must not be a
* real expression, so use vector evaluation and then convert
* that result to a real value. */
if (ivl_expr_opcode(exp) == '~') {
struct vector_info vi;
vi = draw_eval_expr(exp, STUFF_OK_XZ);
int res = allocate_word();
const char*sign_flag = ivl_expr_signed(exp)? "/s" : "";
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, vi.base, vi.wid);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
clr_vector(vi);
return res;
}
ivl_expr_t sube = ivl_expr_oper1(exp);
int sub = draw_eval_real(sube);
@@ -374,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;
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
* Copyright (c) 2007-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
@@ -68,6 +68,7 @@ static void draw_modpath_record(const char*label, const char*driver,
src_drivers[idx] = draw_net_input(src);
if (con) con_drivers[idx] = draw_net_input(con);
else if (ivl_path_is_condit(path)) con_drivers[idx] = "";
else con_drivers[idx] = 0;
}
+6
View File
@@ -91,6 +91,9 @@ static unsigned allocate_vector_no_lookaside(unsigned wid, int skip_lookaside)
unsigned idx = 0;
while (idx < wid) {
if (base+idx >= MAX_VEC)
return 0;
assert((base + idx) < MAX_VEC);
if ((allocation_map[base+idx].alloc > 0)
|| (skip_lookaside && peek_exp(base+idx))) {
@@ -121,6 +124,9 @@ static unsigned allocate_vector_no_lookaside(unsigned wid, int skip_lookaside)
* again without worrying about trashing lookaside results. This
* should lead to preferentially allocating new bits instead of
* constantly overwriting intermediate results.
*
* If there is no space for a vector of the given width, then give up
* and return 0.
*/
unsigned allocate_vector(unsigned wid)
{
+4 -1
View File
@@ -27,6 +27,7 @@
# include <sys/stat.h>
FILE*vvp_out = 0;
int vvp_errors = 0;
inline static void draw_execute_header(ivl_design_t des)
{
@@ -79,6 +80,8 @@ int target_design(ivl_design_t des)
return -1;
}
vvp_errors = 0;
draw_execute_header(des);
{ int pre = ivl_design_time_precision(des);
@@ -113,6 +116,6 @@ int target_design(ivl_design_t des)
fclose(vvp_out);
return rc;
return rc + vvp_errors;
}
+5
View File
@@ -29,6 +29,11 @@
*/
extern FILE* vvp_out;
/*
* Keep a count of errors that would render the output unusable.
*/
extern int vvp_errors;
struct vector_info {
unsigned base;
unsigned wid;
+224 -42
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);
@@ -174,29 +209,79 @@ static void set_to_lvariable(ivl_lval_t lval,
} else {
save_signal_lookaside(bit, sig, use_word, wid);
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
sig, use_word, bit, wid);
/* save_signal width of 0 CLEARS the signal from the
lookaside. */
save_signal_lookaside(bit, sig, use_word, 0);
}
}
static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
unsigned bit, unsigned delay, unsigned width)
unsigned bit, unsigned delay, ivl_expr_t dexp,
ivl_expr_t part_off_ex, unsigned width)
{
unsigned skip_assign = transient_id++;
/* 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);
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;
}
/* 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");
if (dexp == 0) {
/* Constant delay... */
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);
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);
} else {
/* Calculated delay... */
int delay_index = allocate_word();
draw_eval_expr_into_integer(dexp, delay_index);
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);
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, " %%assign/av v%p, %u, %u;\n", lsig, delay, bit);
fprintf(vvp_out, "t_%u ;\n", skip_assign);
clear_expression_lookaside();
@@ -211,17 +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))) {
assert(!dexp);
assign_to_array_word(sig, word_ix, bit, delay, 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) {
@@ -278,7 +358,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
draw_eval_expr_into_integer(dexp, delay_index);
fprintf(vvp_out, " %%ix/load 0, %u;\n", width);
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off);
fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %u, %u;\n",
fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %d, %u;\n",
sig, use_word, delay_index, bit);
clr_word(delay_index);
}
@@ -351,6 +431,14 @@ static int show_stmt_assign_vector(ivl_statement_t net)
vec.base = allocate_vector(wid);
vec.wid = wid;
if (vec.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits for "
"r-value expression.\n", ivl_expr_file(rval),
ivl_expr_lineno(rval), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n",
vec.base, word, vec.wid);
@@ -581,6 +669,7 @@ static int show_stmt_block_named(ivl_statement_t net, ivl_scope_t scope)
static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
{
int rc = 0;
ivl_expr_t exp = ivl_stmt_cond_expr(net);
struct vector_info cond = draw_eval_expr(exp, 0);
unsigned count = ivl_stmt_case_count(net);
@@ -665,7 +754,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
/* Emit code for the default case. */
if (default_case < count) {
ivl_statement_t cst = ivl_stmt_case_stmt(net, default_case);
show_statement(cst, sscope);
rc += show_statement(cst, sscope);
}
/* Jump to the out of the case. */
@@ -680,7 +769,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx);
clear_expression_lookaside();
show_statement(cst, sscope);
rc += show_statement(cst, sscope);
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
local_base+count);
@@ -692,11 +781,12 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+count);
clear_expression_lookaside();
return 0;
return rc;
}
static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
{
int rc = 0;
ivl_expr_t exp = ivl_stmt_cond_expr(net);
int cond = draw_eval_real(exp);
unsigned count = ivl_stmt_case_count(net);
@@ -739,7 +829,7 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
fall through to this statement. */
if (default_case < count) {
ivl_statement_t cst = ivl_stmt_case_stmt(net, default_case);
show_statement(cst, sscope);
rc += show_statement(cst, sscope);
}
/* Jump to the out of the case. */
@@ -754,7 +844,7 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx);
clear_expression_lookaside();
show_statement(cst, sscope);
rc += show_statement(cst, sscope);
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count,
local_base+count);
@@ -768,6 +858,37 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
return 0;
}
static void force_real_to_lval(ivl_statement_t net, int res)
{
const char*command_name;
switch (ivl_statement_type(net)) {
case IVL_ST_CASSIGN:
command_name = "%cassign/wr";
break;
case IVL_ST_FORCE:
command_name = "%force/wr";
break;
default:
command_name = "ERROR";
assert(0);
break;
}
assert(ivl_stmt_lvals(net) == 1);
ivl_lval_t lval = ivl_stmt_lval(net, 0);
ivl_signal_t lsig = ivl_lval_sig(lval);
assert(ivl_lval_width(lval) == 1);
assert(ivl_lval_part_off(lval) == 0);
assert(ivl_lval_idx(lval) == 0);
/* L-Value must be a signal: reg or wire */
assert(lsig != 0);
fprintf(vvp_out, " %s v%p_0, %d;\n", command_name, lsig, res);
}
static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
{
unsigned lidx;
@@ -779,7 +900,7 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
switch (ivl_statement_type(net)) {
case IVL_ST_CASSIGN:
command_name = "%cassign/v";
command_name_x0 = "ERROR";
command_name_x0 = "%cassign/x0";
break;
case IVL_ST_FORCE:
command_name = "%force/v";
@@ -903,16 +1024,28 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
static int show_stmt_cassign(ivl_statement_t net)
{
ivl_expr_t rval;
struct vector_info rvec;
ivl_signal_t sig;
rval = ivl_stmt_rval(net);
assert(rval);
rvec = draw_eval_expr(rval, STUFF_OK_47);
sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
int res;
/* Write out initial continuous assign instructions to assign
the expression value to the l-value. */
force_vector_to_lval(net, rvec);
res = draw_eval_real(ivl_stmt_rval(net));
clr_word(res);
force_real_to_lval(net, res);
} else {
struct vector_info rvec;
rvec = draw_eval_expr(rval, STUFF_OK_47);
/* Write out initial continuous assign instructions to assign
the expression value to the l-value. */
force_vector_to_lval(net, rvec);
}
force_link_rval(net, rval);
@@ -926,6 +1059,18 @@ static int show_stmt_cassign(ivl_statement_t net)
*/
static int show_stmt_deassign(ivl_statement_t net)
{
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
assert(ivl_stmt_lvals(net) == 1);
ivl_lval_t lval = ivl_stmt_lval(net, 0);
assert(ivl_lval_width(lval) == 1);
assert(ivl_lval_part_off(lval) == 0);
assert(ivl_lval_idx(lval) == 0);
fprintf(vvp_out, " %%deassign/wr v%p_0;\n", sig);
return 0;
}
unsigned lidx;
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
@@ -937,7 +1082,14 @@ static int show_stmt_deassign(ivl_statement_t net)
assert(lsig != 0);
assert(ivl_lval_mux(lval) == 0);
assert(ivl_lval_part_off(lval) == 0);
unsigned use_wid = ivl_lval_width(lval);
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off = 0;
if (part_off_ex != 0) {
assert(number_is_immediate(part_off_ex, 64));
part_off = get_number_immediate(part_off_ex);
}
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
@@ -945,7 +1097,8 @@ static int show_stmt_deassign(ivl_statement_t net)
}
fprintf(vvp_out, " %%deassign v%p_%lu;\n", lsig, use_word);
fprintf(vvp_out, " %%deassign v%p_%lu, %u, %u;\n",
lsig, use_word, part_off, use_wid);
}
return 0;
@@ -1074,16 +1227,28 @@ static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope)
static int show_stmt_force(ivl_statement_t net)
{
ivl_expr_t rval;
struct vector_info rvec;
ivl_signal_t sig;
rval = ivl_stmt_rval(net);
assert(rval);
rvec = draw_eval_expr(rval, STUFF_OK_47);
sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
int res;
/* Write out initial continuous assign instructions to assign
the expression value to the l-value. */
force_vector_to_lval(net, rvec);
res = draw_eval_real(ivl_stmt_rval(net));
clr_word(res);
force_real_to_lval(net, res);
} else {
struct vector_info rvec;
rvec = draw_eval_expr(rval, STUFF_OK_47);
/* Write out initial continuous assign instructions to assign
the expression value to the l-value. */
force_vector_to_lval(net, rvec);
}
force_link_rval(net, rval);
@@ -1172,6 +1337,22 @@ static int show_stmt_noop(ivl_statement_t net)
static int show_stmt_release(ivl_statement_t net)
{
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
unsigned type = 0;
assert(ivl_stmt_lvals(net) == 1);
ivl_lval_t lval = ivl_stmt_lval(net, 0);
assert(ivl_lval_width(lval) == 1);
assert(ivl_lval_part_off(lval) == 0);
assert(ivl_lval_idx(lval) == 0);
if (ivl_signal_type(sig) == IVL_SIT_REG) type = 1;
fprintf(vvp_out, " %%release/wr v%p_0, %u;\n", sig, type);
return 0;
}
unsigned lidx;
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
@@ -1313,6 +1494,7 @@ static struct vector_info reduction_or(struct vector_info cvec)
clr_vector(cvec);
result.base = allocate_vector(1);
result.wid = 1;
assert(result.base);
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", result.base,
cvec.base, cvec.wid);
break;
+69 -19
View File
@@ -469,11 +469,10 @@ static char* draw_C8_to_string(ivl_net_const_t cptr,
return result;
}
static char* draw_Cr_to_string(ivl_net_const_t cptr)
static char* draw_Cr_to_string(double value)
{
char tmp[256];
double value = ivl_const_real(cptr);
uint64_t mant = 0;
if (isinf(value)) {
@@ -616,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);
}
@@ -641,7 +646,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
break;
case IVL_VT_REAL:
result = draw_Cr_to_string(cptr);
result = draw_Cr_to_string(ivl_const_real(cptr));
break;
default:
@@ -680,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:
@@ -988,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;
@@ -1121,19 +1129,31 @@ static void draw_net_in_scope(ivl_signal_t sig)
discover that the entire array can be collapsed,
so the word count for the signal and the alias
*must* match. */
assert(word_count == ivl_signal_array_count(nex_data->net));
if (iword == 0) {
fprintf(vvp_out, "v%p .array \"%s\", v%p; Alias to %s\n",
sig, vvp_mangle_name(ivl_signal_basename(sig)),
nex_data->net, ivl_signal_basename(nex_data->net));
if (word_count == ivl_signal_array_count(nex_data->net)) {
if (iword == 0) {
fprintf(vvp_out, "v%p .array \"%s\", v%p; Alias to %s\n",
sig, vvp_mangle_name(ivl_signal_basename(sig)),
nex_data->net,
ivl_signal_basename(nex_data->net));
}
/* An alias for an individual word. */
} else {
if (iword == 0) {
int first = ivl_signal_array_base(sig);
int last = first + word_count-1;
fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n",
sig,
vvp_mangle_name(ivl_signal_basename(sig)),
last, first);
}
fprintf(vvp_out, "v%p_%u .alias%s v%p %u, %d %d, "
"v%p_%u; Alias to %s\n", sig, iword,
datatype_flag, sig, iword, msb, lsb,
nex_data->net, nex_data->net_word,
ivl_signal_basename(nex_data->net));
}
/* An alias for the individual words? */
#if 0
fprintf(vvp_out, "v%p_%u .alias%s v%p, %d %d, v%p_%u;\n",
sig, iword, datatype_flag, sig,
msb, lsb, nex_data->net, nex_data->net_word);
#endif
} else {
/* Finally, we may have an alias that is a word
connected to another word. Again, this is a
@@ -1682,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];
@@ -2327,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:
@@ -2433,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");
@@ -2452,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);
@@ -2468,6 +2510,14 @@ 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\" %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;
default:
fprintf(vvp_out, "; parameter type %d unsupported\n",
ivl_expr_type(pex));
+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.20080314
Version: 0.9.0.%{rev_date}
Release: 0
License: GPL
Group: Productivity/Scientific/Electronics
Source: verilog-20080314.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-20080314
%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.
+25 -8
View File
@@ -429,6 +429,11 @@ bool verinum::is_zero() const
return true;
}
bool verinum::is_negative() const
{
return (bits_[nbits_-1] == V1) && has_sign();
}
verinum pad_to_width(const verinum&that, unsigned width)
{
if (that.len() >= width)
@@ -443,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)
@@ -500,12 +505,20 @@ verinum trim_vnum(const verinum&that)
unsigned top = that.len()-1;
while ((top > 0) && (that.get(top) == verinum::V0))
top -= 1;
/* Now top is the index of the highest non-zero bit. If
that turns out to the highest bit in the vector, then
tere is no trimming possible. */
if (top+1 == that.len())
return that;
/* Make tlen wide enough to include the highest non-zero
bit, plus one extra 0 bit. */
tlen = top+2;
/* This can only happen when the verinum is all zeros,
so make it a single bit wide. */
if (that.get(top) == verinum::V0) tlen -= 1;
}
verinum tmp (verinum::V0, tlen, false);
@@ -881,14 +894,18 @@ verinum operator * (const verinum&left, const verinum&right)
verinum result(verinum::V0, left.len() + right.len(), has_len_flag);
result.has_sign(left.has_sign() || right.has_sign());
for (unsigned rdx = 0 ; rdx < right.len() ; rdx += 1) {
verinum::V r_sign = sign_bit(right);
for (unsigned rdx = 0 ; rdx < result.len() ; rdx += 1) {
if (right.get(rdx) == verinum::V0)
verinum::V r_bit = rdx < right.len()? right.get(rdx) : r_sign;
if (r_bit == verinum::V0)
continue;
verinum::V l_sign = sign_bit(left);
verinum::V carry = verinum::V0;
for (unsigned ldx = 0 ; ldx < left.len() ; ldx += 1) {
result.set(ldx+rdx, add_with_carry(left[ldx],
for (unsigned ldx = 0 ; ldx < result.len()-rdx ; ldx += 1) {
verinum::V l_bit = ldx < left.len()? left[ldx] : l_sign;
result.set(ldx+rdx, add_with_carry(l_bit,
result[rdx+ldx],
carry));
}
@@ -1221,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;
+17
View File
@@ -71,6 +71,7 @@ class verinum {
// A number is "defined" if there are no x or z bits in its value.
bool is_defined() const;
bool is_zero() const;
bool is_negative() const;
// A number is "a string" if its value came directly from
// an ASCII description instead of a number value.
@@ -104,6 +105,19 @@ class verinum {
bool string_flag_;
};
/*
* This returns the sign bit of the verinum value. If the value is
* unsigned, then return an implicit sign bit of 0. Otherwise, return
* the high bit.
*/
inline verinum::V sign_bit(const verinum&val)
{
if (val.has_sign())
return val.get(val.len()-1);
else
return verinum::V0;
}
/* Return a verinum that has the same value as the input, but is at
least as wide as the requested width. This may involve sign
extension, if the value is signed. */
@@ -116,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
+4 -1
View File
@@ -215,7 +215,10 @@ static PLI_INT32 sys_rtoi_calltf(PLI_BYTE8*user)
vpi_get_value(arg, &value);
/* convert */
res.aval = (unsigned)value.value.real;
if (value.value.real >= 0.0)
res.aval = (unsigned)value.value.real;
else
res.aval = - (unsigned)-value.value.real;
res.bval = 0;
value.format = vpiVectorVal;
+52 -29
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_display.c,v 1.79 2007/04/18 02:40:20 steve Exp $"
#endif
# include "vpi_config.h"
@@ -320,11 +317,17 @@ static void format_time_real(unsigned mcd, int fsize,
}
static void format_strength(unsigned int mcd, s_vpi_value*value)
static void format_strength(unsigned int mcd, s_vpi_value*value,
unsigned size)
{
char str[4];
vpip_format_strength(str, value);
my_mcd_printf(mcd, "%s", str);
int bit;
for (bit = size-1; bit >= 0; bit -= 1) {
vpip_format_strength(str, value, (unsigned) bit);
my_mcd_printf(mcd, "%s", str);
if (bit > 0) my_mcd_printf(mcd, "_");
}
}
static void format_error_msg(const char*msg, int leading_zero,
@@ -695,7 +698,7 @@ static int format_str_char(vpiHandle scope, unsigned int mcd,
return 1;
}
format_strength(mcd, &value);
format_strength(mcd, &value, vpi_get(vpiSize, argv[idx]));
use_count = 1;
break;
@@ -1119,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
@@ -1322,12 +1326,16 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
s_vpi_value value;
char *result, *fmtb;
unsigned int size;
unsigned int max_size = 256; /* The initial size of the buffer. */
unsigned int ini_size = 256; /* The initial size of the buffer. */
/* Make sure the width fits in the initial buffer. */
if (width+1 > ini_size) ini_size = width + 1;
/* The default return value is the full format. */
result = malloc(max_size*sizeof(char));
result = malloc(ini_size*sizeof(char));
fmtb = format_as_string(ljust, plus, ld_zero, width, prec, fmt);
strcpy(result, fmtb);
size = strlen(result) + 1; /* fallback value if errors */
switch (fmt) {
case '%':
@@ -1386,13 +1394,13 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
}
/* If the default buffer is too small, make it big enough. */
size = strlen(cp) + 1;
if (size > max_size) result = realloc(result, size*sizeof(char));
if (size > ini_size) result = realloc(result, size*sizeof(char));
if (ljust == 0) sprintf(result, "%*s", width, cp);
else sprintf(result, "%-*s", width, cp);
size = strlen(result) + 1;
}
}
size = strlen(result) + 1;
break;
case 'c':
@@ -1416,9 +1424,9 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
value.value.str[strlen(value.value.str)-1]);
else sprintf(result, "%-*c", width,
value.value.str[strlen(value.value.str)-1]);
size = strlen(result) + 1;
}
}
size = strlen(result) + 1;
break;
case 'd':
@@ -1451,13 +1459,13 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
strcpy(&tbuf[1], value.value.str);
} else strcpy(&tbuf[0], value.value.str);
/* If the default buffer is too small make it big enough. */
if (size > max_size) result = realloc(result, size*sizeof(char));
if (size > ini_size) result = realloc(result, size*sizeof(char));
if (ljust == 0) sprintf(result, "%*s", width, tbuf);
else sprintf(result, "%-*s", width, tbuf);
free(tbuf);
size = strlen(result) + 1;
}
}
size = strlen(result) + 1;
break;
case 'e':
@@ -1485,9 +1493,9 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
while (*cp != '>') cp++;
*cp = '\0';
sprintf(result, fmtb+1, value.value.real);
size = strlen(result) + 1;
}
}
size = strlen(result) + 1;
break;
/* This Verilog format specifier is not currently supported!
@@ -1496,7 +1504,6 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
case 'L':
vpi_printf("WARNING: %%%c currently unsupported %s%s.\n", fmt,
info->name, fmtb);
size = strlen(result) + 1;
break;
case 'm':
@@ -1532,12 +1539,12 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
if (width == -1) width = 0;
/* If the default buffer is too small make it big enough. */
size = strlen(value.value.str) + 1;
if (size > max_size) result = realloc(result, size*sizeof(char));
if (size > ini_size) result = realloc(result, size*sizeof(char));
if (ljust == 0) sprintf(result, "%*s", width, value.value.str);
else sprintf(result, "%-*s", width, value.value.str);
size = strlen(result) + 1;
}
}
size = strlen(result) + 1;
break;
case 't':
@@ -1570,6 +1577,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
get_time_real(tbuf, value.value.real, prec, time_units);
if (ljust == 0) sprintf(result, "%*s", width, tbuf);
else sprintf(result, "%-*s", width, tbuf);
size = strlen(result) + 1;
}
} else {
value.format = vpiDecStrVal;
@@ -1581,16 +1589,15 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
get_time(tbuf, value.value.str, prec, time_units);
if (ljust == 0) sprintf(result, "%*s", width, tbuf);
else sprintf(result, "%-*s", width, tbuf);
size = strlen(result) + 1;
}
}
}
size = strlen(result) + 1;
break;
case 'u':
case 'U':
*idx += 1;
size = 0; /* fallback value if errors */
if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 ||
prec != -1) {
vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
@@ -1610,7 +1617,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
veclen = (vpi_get(vpiSize, info->items[*idx])+31)/32;
size = veclen * 4 + 1;
/* If the default buffer is too small, make it big enough. */
if (size > max_size) result = realloc(result, size*sizeof(char));
if (size > ini_size) result = realloc(result, size*sizeof(char));
cp = result;
for (word = 0; word < veclen; word += 1) {
bits = value.value.vector[word].aval &
@@ -1647,22 +1654,38 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
fmtb);
} else {
char tbuf[4];
char tbuf[4], *rbuf;
PLI_INT32 nbits;
unsigned rsize;
int bit;
/* If a width was not given use a width of zero. */
if (width == -1) width = 0;
vpip_format_strength(tbuf, &value);
if (ljust == 0) sprintf(result, "%*s", width, tbuf);
else sprintf(result, "%-*s", width, tbuf);
nbits = vpi_get(vpiSize, info->items[*idx]);
/* This is 4 chars for all but the last bit (strenght + "_")
* which only needs three chars (strength), but then you need
* space for the EOS '\0', so it is just number of bits * 4. */
rsize = nbits*4;
rbuf = malloc(rsize*sizeof(char));
if (rsize > ini_size) result = realloc(result, rsize*sizeof(char));
strcpy(rbuf, "");
for (bit = nbits-1; bit >= 0; bit -= 1) {
vpip_format_strength(tbuf, &value, bit);
strcat(rbuf, tbuf);
if (bit > 0) strcat(rbuf, "_");
}
if (ljust == 0) sprintf(result, "%*s", width, rbuf);
else sprintf(result, "%-*s", width, rbuf);
free(rbuf);
size = strlen(result) + 1;
}
}
size = strlen(result) + 1;
break;
case 'z':
case 'Z':
*idx += 1;
size = 0; /* fallback value if errors */
size = strlen(result) + 1; /* fallback value if errors */
if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 ||
prec != -1) {
vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
@@ -1682,7 +1705,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
veclen = (vpi_get(vpiSize, info->items[*idx])+31)/32;
size = 2 * veclen * 4 + 1;
/* If the default buffer is too small, make it big enough. */
if (size > max_size) result = realloc(result, size*sizeof(char));
if (size > ini_size) result = realloc(result, size*sizeof(char));
cp = result;
for (word = 0; word < veclen; word += 1) {
/* Write the aval followed by the bval in endian order. */
+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);
}
+8 -3
View File
@@ -187,7 +187,7 @@ long rtl_dist_uniform(long *seed, long start, long end)
if (r >= 0) {
i = (unsigned long) r;
} else {
i = (unsigned long) (r - 1);
i = - ( (unsigned long) (-(r - 1)) );
}
if (i < start) i = start;
if (i >= end) i = end - 1;
@@ -197,7 +197,7 @@ long rtl_dist_uniform(long *seed, long start, long end)
if (r >= 0) {
i = (unsigned long) r;
} else {
i = (unsigned long) (r - 1);
i = - ( (unsigned long) (-(r - 1)) );
}
if (i <= start) i = start + 1;
if (i > end) i = end;
@@ -208,7 +208,12 @@ long rtl_dist_uniform(long *seed, long start, long end)
if (r >= 0) {
i = (unsigned long) r;
} else {
i = (unsigned long) (r - 1);
/* At least some compilers will notice that (r-1)
is <0 when castling to unsigned long and
replace the result with a zero. This causes
much wrongness, so do the casting to the
positive version and invert it back. */
i = - ( (unsigned long) (-(r - 1)) );
}
}
+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
+4 -2
View File
@@ -1,7 +1,7 @@
#ifndef __vpi_user_H
#define __vpi_user_H
/*
* Copyright (c) 1999-2007 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
@@ -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
@@ -560,7 +562,7 @@ extern DLLEXPORT void (*vlog_startup_routines[])();
/* Format a scalar a la %v. The str points to a 4byte character
buffer. The value must be a vpiStrengthVal. */
extern void vpip_format_strength(char*str, s_vpi_value*value);
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
EXTERN_C_END
+4 -4
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)
@@ -85,9 +85,9 @@ ifeq (@WIN32@,yes)
# The first step makes an ivl.exe that dlltool can use to make an
# export and import library, and the last link makes a, ivl.exe
# that really exports the things that the import library imports.
vvp@EXEEXT@ libvpi.a: $O vvp.def
vvp@EXEEXT@ libvpi.a: $O $(srcdir)/vvp.def
$(CXX) -o vvp@EXEEXT@ $(LDFLAGS) $O $(dllib) $(LIBS)
dlltool --dllname vvp@EXEEXT@ --def vvp.def \
dlltool --dllname vvp@EXEEXT@ --def $(srcdir)/vvp.def \
--output-lib libvpi.a --output-exp vvp.exp
$(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS)
else
+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:
+440 -51
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
* Copyright (c) 2007-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: array.cc,v 1.2 2007/04/10 01:26:16 steve Exp $"
#endif
# include "array.h"
#include "symbols.h"
@@ -38,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;
@@ -58,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 {
@@ -75,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);
@@ -87,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,
@@ -125,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;
@@ -145,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);
}
@@ -201,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), \
@@ -216,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)
@@ -267,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,
@@ -275,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);
@@ -298,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);
@@ -328,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)
@@ -342,13 +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);
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;
@@ -361,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);
@@ -396,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);
@@ -414,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);
@@ -424,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);
@@ -446,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()
{
}
@@ -489,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)
@@ -529,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;
@@ -547,3 +921,18 @@ void compile_array_alias(char*label, char*name, char*src)
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);
}
+11 -6
View File
@@ -1,7 +1,7 @@
#ifndef __array_H // -*- c++ -*-
#define __array_H
/*
* Copyright (c) 2007 Stephen Williams (steve@icarus.com)
* Copyright (c) 2007-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: array.h,v 1.2 2007/04/10 01:26:16 steve Exp $"
#endif
#include "vvp_net.h"
#include "vpi_user.h"
@@ -31,12 +28,15 @@ 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);
extern void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word);
extern void array_attach_word(vvp_array_t array, unsigned long addr,
vpiHandle word);
extern void array_alias_word(vvp_array_t array, unsigned long addr,
vpiHandle word);
extern void array_set_word(vvp_array_t arr,
unsigned idx,
@@ -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);
+7 -3
View File
@@ -32,12 +32,14 @@ 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);
extern bool of_AND(vthread_t thr, vvp_code_t code);
extern bool of_ANDR(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_AV(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_AVD(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_D(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_MV(vthread_t thr, vvp_code_t code);
extern bool of_ASSIGN_V0(vthread_t thr, vvp_code_t code);
@@ -51,6 +53,8 @@ extern bool of_BLEND_WR(vthread_t thr, vvp_code_t code);
extern bool of_BREAKPOINT(vthread_t thr, vvp_code_t code);
extern bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t code);
extern bool of_CASSIGN_V(vthread_t thr, vvp_code_t code);
extern bool of_CASSIGN_WR(vthread_t thr, vvp_code_t code);
extern bool of_CASSIGN_X0(vthread_t thr, vvp_code_t code);
extern bool of_CMPIS(vthread_t thr, vvp_code_t code);
extern bool of_CMPIU(vthread_t thr, vvp_code_t code);
extern bool of_CMPS(vthread_t thr, vvp_code_t code);
@@ -64,6 +68,7 @@ extern bool of_CVT_IR(vthread_t thr, vvp_code_t code);
extern bool of_CVT_RI(vthread_t thr, vvp_code_t code);
extern bool of_CVT_VR(vthread_t thr, vvp_code_t code);
extern bool of_DEASSIGN(vthread_t thr, vvp_code_t code);
extern bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t code);
extern bool of_DELAY(vthread_t thr, vvp_code_t code);
extern bool of_DELAYX(vthread_t thr, vvp_code_t code);
extern bool of_DISABLE(vthread_t thr, vvp_code_t code);
@@ -73,6 +78,7 @@ extern bool of_DIV_WR(vthread_t thr, vvp_code_t code);
extern bool of_END(vthread_t thr, vvp_code_t code);
extern bool of_FORCE_LINK(vthread_t thr, vvp_code_t code);
extern bool of_FORCE_V(vthread_t thr, vvp_code_t code);
extern bool of_FORCE_WR(vthread_t thr, vvp_code_t code);
extern bool of_FORCE_X0(vthread_t thr, vvp_code_t code);
extern bool of_FORK(vthread_t thr, vvp_code_t code);
extern bool of_INV(vthread_t thr, vvp_code_t code);
@@ -91,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);
@@ -119,8 +124,8 @@ extern bool of_POW(vthread_t thr, vvp_code_t code);
extern bool of_POW_WR(vthread_t thr, vvp_code_t code);
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);
@@ -155,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;
+146 -235
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,13 +79,14 @@ 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} },
{ "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%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/mv",of_ASSIGN_MV,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_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} },
@@ -100,6 +98,8 @@ const static struct opcode_table_s opcode_table[] = {
{ "%breakpoint", of_BREAKPOINT, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cassign/link",of_CASSIGN_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
{ "%cassign/v",of_CASSIGN_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%cassign/wr",of_CASSIGN_WR,2,{OA_FUNC_PTR,OA_BIT1, OA_NONE} },
{ "%cassign/x0",of_CASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/wr", of_CMPWR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
@@ -112,7 +112,8 @@ const static struct opcode_table_s opcode_table[] = {
{ "%cvt/ir", of_CVT_IR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/ri", of_CVT_RI, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/vr", of_CVT_VR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%deassign",of_DEASSIGN,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%deassign",of_DEASSIGN,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%deassign/wr",of_DEASSIGN_WR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%delay", of_DELAY, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%div", of_DIV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
@@ -121,6 +122,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%force/link",of_FORCE_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
{ "%force/v",of_FORCE_V,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%force/wr",of_FORCE_WR,2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%force/x0",of_FORCE_X0,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
@@ -138,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} },
@@ -166,8 +167,8 @@ const static struct opcode_table_s opcode_table[] = {
{ "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%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} },
@@ -247,6 +248,13 @@ static vvp_net_t*lookup_functor_symbol(const char*label)
return val.net;
}
vpiHandle vvp_lookup_handle(const char*label)
{
symbol_value_t val = sym_get_value(sym_vpi, label);
if (val.ptr) return (vpiHandle) val.ptr;
return 0;
}
vvp_net_t* vvp_net_lookup(const char*label)
{
/* First, look to see if the symbol is a vpi object of some
@@ -307,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;
@@ -332,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);
@@ -341,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;
}
@@ -362,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);
}
@@ -376,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;
}
@@ -401,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);
}
@@ -414,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) {
@@ -449,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);
}
}
@@ -466,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;
}
@@ -503,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);
}
@@ -515,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;
}
@@ -543,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);
}
@@ -737,6 +695,47 @@ void compile_vpi_time_precision(long pre)
vpip_set_time_precision(pre);
}
/*
* Convert a Cr string value to double.
*
* The format is broken into mantissa and exponent.
* The exponent in turn includes a sign bit.
*
* The mantissa is a 64bit integer value (encoded in hex).
*
* The exponent included the sign bit (0x4000) and the binary
* exponent offset by 0x1000. The actual exponent is the
* encoded exponent - 0x1000.
*
* The real value is sign * (mant ** exp).
*/
double crstring_to_double(char*label)
{
char*cp = label+3;
assert(*cp == 'm');
cp += 1;
uint64_t mant = strtoull(cp, &cp, 16);
assert(*cp == 'g');
cp += 1;
int exp = strtoul(cp, 0, 16);
double tmp;
if (mant == 0 && exp == 0x3fff) {
tmp = INFINITY;
} else if (mant == 0 && exp == 0x7fff) {
tmp = -INFINITY;
} else if (exp == 0x3fff) {
tmp = nan("");
} else {
double sign = (exp & 0x4000)? -1.0 : 1.0;
exp &= 0x1fff;
tmp = sign * ldexp((double)mant, exp - 0x1000);
}
return tmp;
}
/*
* Run through the arguments looking for the nodes that are
* connected to my input ports. For each source functor that I
@@ -819,42 +818,13 @@ void input_connect(vvp_net_t*fdx, unsigned port, char*label)
}
/* Handle the Cr<> constant driver, which is a real-value
driver. The format is broken into mantissa and
exponent. The exponent in turn includes a sign bit.
The mantissa is a 64bit integer value (encoded in hex).
The exponent included the sign bit (0x4000) and the binary
exponent offset by 0x1000. The actual exponent is the
encoded exponent - 0x1000.
The real value is sign * (mant ** exp). */
driver. */
if ((strncmp(label, "Cr<", 3) == 0)
&& ((tp = strchr(label,'>')))
&& (tp[1] == 0)
&& (strspn(label+3, "0123456789abcdefmg")+3 == (unsigned)(tp-label))) {
char*cp = label+3;
assert(*cp == 'm');
cp += 1;
uint64_t mant = strtoull(cp, &cp, 16);
assert(*cp == 'g');
cp += 1;
int exp = strtoul(cp, 0, 16);
double tmp;
if (mant == 0 && exp == 0x3fff) {
tmp = INFINITY;
} else if (mant == 0 && exp == 0x7fff) {
tmp = -INFINITY;
} else if (exp == 0x3fff) {
tmp = nan("");
} else {
double sign = (exp & 0x4000)? -1.0 : 1.0;
exp &= 0x1fff;
tmp = sign * ldexp((double)mant, exp - 0x1000);
}
double tmp = crstring_to_double(label);
schedule_set_vector(ifdx, tmp);
free(label);
@@ -916,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)
{
@@ -1299,7 +1284,8 @@ struct __vpiModPath* compile_modpath(char*label, struct symb_s drv,
static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path,
char edge,
struct symb_s src,
struct numbv_s vals)
struct numbv_s vals,
bool ifnone)
{
vvp_fun_modpath*dst = path->modpath;
@@ -1352,7 +1338,7 @@ static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path,
/* Save the vpiEdge directory into the input path term. */
srcobj->path_term_in.edge = vpi_edge;
input_connect(net, 0, src.text);
dst->add_modpath_src(obj);
dst->add_modpath_src(obj, ifnone);
return srcobj;
}
@@ -1363,7 +1349,8 @@ void compile_modpath_src(struct __vpiModPath*dst, char edge,
struct symb_s condit_src,
struct symb_s path_term_in)
{
struct __vpiModPathSrc*obj = make_modpath_src(dst, edge, src, vals);
struct __vpiModPathSrc*obj =
make_modpath_src(dst, edge, src, vals, false);
input_connect(obj->net, 1, condit_src.text);
compile_vpi_lookup(&obj->path_term_in.expr, path_term_in.text);
}
@@ -1372,10 +1359,12 @@ void compile_modpath_src(struct __vpiModPath*dst, char edge,
struct symb_s src,
struct numbv_s vals,
int condit_src,
struct symb_s path_term_in)
struct symb_s path_term_in,
bool ifnone)
{
assert(condit_src == 0);
struct __vpiModPathSrc*obj = make_modpath_src(dst, edge, src, vals);
struct __vpiModPathSrc*obj =
make_modpath_src(dst, edge, src, vals, ifnone);
compile_vpi_lookup(&obj->path_term_in.expr, path_term_in.text);
}
@@ -1419,10 +1408,10 @@ void compile_resolver(char*label, char*type, unsigned argc, struct symb_s*argv)
obj = new resolv_functor(vvp_scalar_t(BIT4_1, 5));
} else if (strcmp(type,"triand") == 0) {
obj = new table_functor_s(ft_TRIAND);
obj = new resolv_triand;
} else if (strcmp(type,"trior") == 0) {
obj = new table_functor_s(ft_TRIOR);
obj = new resolv_trior;
} else {
fprintf(stderr, "invalid resolver type: %s\n", type);
@@ -1477,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
@@ -1676,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
@@ -1752,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)
@@ -1765,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;
@@ -1775,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)
@@ -1788,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;
@@ -1823,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);
@@ -1834,11 +1732,24 @@ 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,
long file_idx, long lineno)
{
double dvalue = crstring_to_double(value);
vpiHandle obj = vpip_make_real_param(name, dvalue, file_idx, lineno);
compile_vpi_symbol(label, obj);
vpip_attach_to_current_scope(obj);
free(label);
free(value);
}
+58 -15
View File
@@ -72,6 +72,7 @@ extern void wide_inputs_connect(vvp_wide_fun_core*core,
unsigned argc, struct symb_s*argv);
extern vvp_net_t* vvp_net_lookup(const char*label);
extern vpiHandle vvp_lookup_handle(const char*label);
/*
* Add a functor to the symbol table
@@ -148,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,
@@ -198,7 +201,8 @@ extern void compile_modpath_src(__vpiModPath*dst,
struct symb_s input,
struct numbv_s d,
int condit_input, /* match with '0' */
struct symb_s path_term_input);
struct symb_s path_term_input,
bool ifnone);
extern void compile_modpath_src(__vpiModPath*dst,
char edge,
struct symb_s input,
@@ -216,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);
@@ -231,9 +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);
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
@@ -287,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.
@@ -346,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
@@ -355,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,
@@ -366,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);
/*
@@ -407,5 +447,8 @@ extern void compile_alias(char*label, char*name,
extern void compile_alias_real(char*label, char*name,
int msb, int lsb,
unsigned argc, struct symb_s*argv);
extern void compile_aliasw(char*label, char*array_symbol,
unsigned long array_addr, int msb, int lsb,
unsigned argc, struct symb_s*argv);
#endif
+72 -14
View File
@@ -22,6 +22,7 @@
#include "vpi_priv.h"
#include <iostream>
#include <cstdlib>
#include <list>
#include <assert.h>
void vvp_delay_t::calculate_min_delay_()
@@ -349,7 +350,7 @@ void vvp_fun_delay::run_run_real_(struct vvp_fun_delay::event_*cur)
}
vvp_fun_modpath::vvp_fun_modpath(vvp_net_t*net)
: net_(net), src_list_(0)
: net_(net), src_list_(0), ifnone_list_(0)
{
}
@@ -361,16 +362,27 @@ vvp_fun_modpath::~vvp_fun_modpath()
src_list_ = tmp->next_;
delete tmp;
}
while (ifnone_list_) {
vvp_fun_modpath_src*tmp = ifnone_list_;
ifnone_list_ = tmp->next_;
delete tmp;
}
}
void vvp_fun_modpath::add_modpath_src(vvp_fun_modpath_src*that)
void vvp_fun_modpath::add_modpath_src(vvp_fun_modpath_src*that, bool ifnone)
{
assert(that->next_ == 0);
that->next_ = src_list_;
src_list_ = that;
if (ifnone) {
that->next_ = ifnone_list_;
ifnone_list_ = that;
} else {
that->next_ = src_list_;
src_list_ = that;
}
}
static vvp_time64_t delay_from_edge(vvp_bit4_t a, vvp_bit4_t b, vvp_time64_t array[12])
static vvp_time64_t delay_from_edge(vvp_bit4_t a, vvp_bit4_t b,
vvp_time64_t array[12])
{
typedef delay_edge_t bit4_table4[4];
const static bit4_table4 edge_table[4] = {
@@ -392,17 +404,42 @@ void vvp_fun_modpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
if (cur_vec4_.eeq(bit))
return;
/* Select a time delay source that applies. */
vvp_fun_modpath_src*src = 0;
/* Select a time delay source that applies. Notice that there
may be multiple delay sources that apply, so collect all
the candidates into a list first. */
list<vvp_fun_modpath_src*>candidate_list;
vvp_time64_t candidate_wake_time = 0;
for (vvp_fun_modpath_src*cur = src_list_ ; cur ; cur=cur->next_) {
/* Skip paths that are disabled by conditions. */
if (cur->condition_flag_ == false)
continue;
if (src == 0) {
src = cur;
} else if (cur->wake_time_ > src->wake_time_) {
src = cur;
if (candidate_list.empty()) {
candidate_list.push_back(cur);
candidate_wake_time = cur->wake_time_;
} else if (cur->wake_time_ == candidate_wake_time) {
candidate_list.push_back(cur);
} else if (cur->wake_time_ > candidate_wake_time) {
candidate_list.assign(1, cur);
candidate_wake_time = cur->wake_time_;
} else {
continue; /* Skip this entry. */
}
}
/* Only add the ifnone delay if it has a later wake_time_ or
* if there are no normal delays. */
vvp_time64_t ifnone_wake_time = candidate_wake_time;
for (vvp_fun_modpath_src*cur = ifnone_list_ ; cur ; cur=cur->next_) {
if (candidate_list.empty()) {
candidate_list.push_back(cur);
ifnone_wake_time = cur->wake_time_;
} else if (cur->wake_time_ == ifnone_wake_time &&
ifnone_wake_time > candidate_wake_time) {
candidate_list.push_back(cur);
} else if (cur->wake_time_ > ifnone_wake_time) {
candidate_list.assign(1, cur);
ifnone_wake_time = cur->wake_time_;
} else {
continue; /* Skip this entry. */
}
@@ -412,16 +449,24 @@ void vvp_fun_modpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
match. This may happen, for example, if the set of
conditional delays is incomplete, leaving some cases
uncovered. In that case, just pass the data without delay */
if (src == 0) {
if (candidate_list.empty()) {
cur_vec4_ = bit;
schedule_generic(this, 0, false);
return;
}
assert(src);
/* Now given that we have a list of candidate delays, find for
each if the 12 numbers the minimum from all the
candidates. This minimum set becomes the chosen delay to
use. */
vvp_time64_t out_at[12];
vvp_time64_t now = schedule_simtime();
typedef list<vvp_fun_modpath_src*>::const_iterator iter_t;
iter_t cur = candidate_list.begin();
vvp_fun_modpath_src*src = *cur;
for (unsigned idx = 0 ; idx < 12 ; idx += 1) {
out_at[idx] = src->wake_time_ + src->delay_[idx];
if (out_at[idx] <= now)
@@ -430,6 +475,19 @@ void vvp_fun_modpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
out_at[idx] -= now;
}
for (cur ++ ; cur != candidate_list.end() ; cur ++) {
src = *cur;
for (unsigned idx = 0 ; idx < 12 ; idx += 1) {
vvp_time64_t tmp = src->wake_time_ + src->delay_[idx];
if (tmp <= now)
tmp = 0;
else
tmp -= now;
if (tmp < out_at[idx])
out_at[idx] = tmp;
}
}
/* Given the scheduled output time, create an output event. */
vvp_time64_t use_delay = delay_from_edge(cur_vec4_.value(0),
bit.value(0),
+2 -1
View File
@@ -150,7 +150,7 @@ class vvp_fun_modpath : public vvp_net_fun_t, private vvp_gen_event_s {
vvp_fun_modpath(vvp_net_t*net);
~vvp_fun_modpath();
void add_modpath_src(vvp_fun_modpath_src*that);
void add_modpath_src(vvp_fun_modpath_src*that, bool ifnone);
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
@@ -163,6 +163,7 @@ class vvp_fun_modpath : public vvp_net_fun_t, private vvp_gen_event_s {
vvp_vector4_t cur_vec4_;
vvp_fun_modpath_src*src_list_;
vvp_fun_modpath_src*ifnone_list_;
private: // not implemented
vvp_fun_modpath(const vvp_fun_modpath&);
+1 -709
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001 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
@@ -16,639 +16,9 @@
* 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: draw_tt.c,v 1.23 2006/11/28 05:57:20 steve Exp $"
#endif
# include <stdio.h>
#if 0
static void draw_AND(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_AND[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if ((i0 == 0) || (i1 == 0) ||
(i2 == 0) || (i3 == 0))
val = 0;
else if ((i0 == 1) && (i1 == 1) &&
(i2 == 1) && (i3 == 1))
val = 1;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_NAND(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_NAND[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if ((i0 == 0) || (i1 == 0) ||
(i2 == 0) || (i3 == 0))
val = 1;
else if ((i0 == 1) && (i1 == 1) &&
(i2 == 1) && (i3 == 1))
val = 0;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_BUF(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_BUF[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if (i0 == 1)
val = 1;
else if (i0 == 0)
val = 0;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_BUFZ(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_BUFZ[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val = i0;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_BUFIF0(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_BUFIF0[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if (i2 == 0)
val = 3;
else if (i0 == 1)
val = 1;
else if (i0 == 0)
val = 0;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_BUFIF1(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_BUFIF1[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if (i2 == 1)
val = 3;
else if (i0 == 1)
val = 1;
else if (i0 == 0)
val = 0;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_PMOS(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_PMOS[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if (i2 == 0 || i0 == 3)
val = 3;
else if (i0 == 1)
val = 1;
else if (i0 == 0)
val = 0;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_NMOS(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_NMOS[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if (i2 == 1 || i0 == 3)
val = 3;
else if (i0 == 1)
val = 1;
else if (i0 == 0)
val = 0;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
static void draw_MUXX(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_MUXX[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if (i3 == 0)
val = 3;
else if (i3 == 2)
val = 2;
else if (i3 == 3)
val = 2;
else if (i2 >= 2) {
val = 2;
} else if (i2 == 0)
val = i0;
else
val = i1;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#if 0
static void draw_MUXZ(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_MUXZ[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if (i3 == 0)
val = 3;
else if (i3 == 2)
val = 2;
else if (i3 == 3)
val = 2;
else if (i2 >= 2) {
if (i0 == i1)
val = i0;
else
val = 2;
} else if (i2 == 0)
val = i0;
else
val = i1;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_EEQ(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_EEQ[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if (i3 != i2)
val = 0;
else if (i1 != i0)
val = 0;
else
val = 1;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_NOR(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_NOR[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if ((i0 == 1) || (i1 == 1) ||
(i2 == 1) || (i3 == 1))
val = 0;
else if ((i0 == 0) && (i1 == 0) &&
(i2 == 0) && (i3 == 0))
val = 1;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_NOT(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_NOT[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if (i0 == 1)
val = 0;
else if (i0 == 0)
val = 1;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_OR(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_OR[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if ((i0 == 1) || (i1 == 1) ||
(i2 == 1) || (i3 == 1))
val = 1;
else if ((i0 == 0) && (i1 == 0) &&
(i2 == 0) && (i3 == 0))
val = 0;
else
val = 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_XNOR(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_XNOR[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if ((i0 > 1) || (i1 > 1)
|| (i2 > 1) || (i3 > 1))
val = 2;
else
val = (i0 + i1 + i2 + i3) % 2 ^ 1;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
#if 0
static void draw_XOR(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_XOR[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if ((i0 > 1) || (i1 > 1)
|| (i2 > 1) || (i3 > 1))
val = 2;
else
val = (i0 + i1 + i2 + i3) % 2;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
#endif
static void draw_TRIAND(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_TRIAND[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if ((i0 == 0) || (i1 == 0) ||
(i2 == 0) || (i3 == 0))
val = 0;
else if ((i0 == 2) || (i1 == 2) ||
(i2 == 2) || (i3 == 2))
val = 2;
else if ((i0 == 3) && (i1 == 3) &&
(i2 == 3) && (i3 == 3))
val = 3;
else
val = 1;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
static void draw_TRIOR(void)
{
unsigned i0, i1, i2, i3;
printf("const unsigned char ft_TRIOR[64] = {");
for (i3 = 0 ; i3 < 4 ; i3 += 1)
for (i2 = 0 ; i2 < 4 ; i2 += 1) {
printf("\n ");
for (i1 = 0 ; i1 < 4 ; i1 += 1) {
unsigned idx = (i3 << 4) | (i2 << 2) | i1;
unsigned char byte = 0;
for (i0 = 0 ; i0 < 4 ; i0 += 1) {
unsigned val;
if ((i0 == 1) || (i1 == 1) ||
(i2 == 1) || (i3 == 1))
val = 1;
else if ((i0 == 2) || (i1 == 2) ||
(i2 == 2) || (i3 == 2))
val = 2;
else if ((i0 == 3) && (i1 == 3) &&
(i2 == 3) && (i3 == 3))
val = 3;
else
val = 0;
byte |= val << (i0*2);
}
printf("0x%02x, ", byte);
}
}
printf("};\n");
}
/*
* The hex_digits table is not a functor truth table per say, but a
@@ -749,85 +119,7 @@ static void draw_oct_table()
main()
{
printf("# include \"logic.h\"\n");
draw_MUXX();
draw_TRIAND();
draw_TRIOR();
draw_hex_table();
draw_oct_table();
return 0;
}
/*
* $Log: draw_tt.c,v $
* Revision 1.23 2006/11/28 05:57:20 steve
* Use new vvp_fun_XXX in place of old functor table for NAND/NOR/XNOR/EEQ.
*
* Revision 1.22 2005/09/19 21:45:09 steve
* Use lazy eval of BUF/NOT/OR/XOR gates.
*
* Revision 1.21 2005/06/12 21:56:16 steve
* Remove unused ft_MOS truth tables.
*
* Revision 1.20 2005/02/12 23:05:25 steve
* Cleanup unused truth tables.
*
* Revision 1.19 2005/02/12 22:50:52 steve
* Implement the vvp_fun_muxz functor.
*
* Revision 1.18 2005/01/29 17:52:06 steve
* move AND to buitin instead of table.
*
* Revision 1.17 2004/12/31 05:57:25 steve
* No need to draw BUF or BUFZ tables.
*
* Revision 1.16 2004/10/04 01:10:59 steve
* Clean up spurious trailing white space.
*
* Revision 1.15 2003/07/30 01:13:29 steve
* Add support for triand and trior.
*
* Revision 1.14 2002/08/29 03:04:01 steve
* Generate x out for x select on wide muxes.
*
* Revision 1.13 2002/08/12 01:35:08 steve
* conditional ident string using autoconfig.
*
* Revision 1.12 2002/01/12 04:02:16 steve
* Support the BUFZ logic device.
*
* Revision 1.11 2001/11/06 03:07:22 steve
* Code rearrange. (Stephan Boettcher)
*
* Revision 1.10 2001/10/09 02:28:17 steve
* Add the PMOS and NMOS functor types.
*
* Revision 1.9 2001/06/19 03:01:10 steve
* Add structural EEQ gates (Stephan Boettcher)
*
* Revision 1.8 2001/04/29 23:13:34 steve
* Add bufif0 and bufif1 functors.
*
* Revision 1.7 2001/04/26 05:12:02 steve
* Implement simple MUXZ for ?: operators.
*
* Revision 1.6 2001/04/21 02:04:01 steve
* Add NAND and XNOR functors.
*
* Revision 1.5 2001/04/15 16:37:48 steve
* add XOR support.
*
* Revision 1.4 2001/04/01 21:31:46 steve
* Add the buf functor type.
*
* Revision 1.3 2001/03/25 20:45:09 steve
* Add vpiOctStrVal access to signals.
*
* Revision 1.2 2001/03/25 19:37:26 steve
* Calculate NOR and NOT tables, and also the hex_digits table.
*
* Revision 1.1 2001/03/11 22:42:11 steve
* Functor values and propagation.
*
*/
+11 -10
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; }
@@ -133,6 +134,7 @@
".net/s" { return K_NET_S; }
".param/l" { return K_PARAM_L; }
".param/str" { return K_PARAM_STR; }
".param/real" { return K_PARAM_REAL; }
".part" { return K_PART; }
".part/pv" { return K_PART_PV; }
".part/v" { return K_PART_V; }
@@ -159,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
@@ -188,13 +187,7 @@
return T_NUMBER; }
/* Symbols are pretty much what is left. They are used to refer to
labels so the rule must match a string that a label would match. */
[.$_a-zA-Z\\][.$_a-zA-Z\\0-9/]* {
yylval.text = strdup(yytext);
assert(yylval.text);
return T_SYMBOL; }
"&A" { return K_A; }
/* Handle some specialized constant/literals as symbols. */
@@ -223,6 +216,14 @@
assert(yylval.text);
return T_SYMBOL; }
/* Symbols are pretty much what is left. They are used to refer to
labels so the rule must match a string that a label would match. */
[.$_a-zA-Z\\][.$_a-zA-Z\\0-9<>/]* {
yylval.text = strdup(yytext);
assert(yylval.text);
return T_SYMBOL; }
/* Accept the common assembler style comments, treat them as white
space. Of course, also skip white space. The semi-colon is
special, though, in that it is also a statement terminator. */
+74 -93
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
@@ -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: logic.cc,v 1.38 2007/02/12 05:08:27 steve Exp $"
#endif
# include "logic.h"
# include "compile.h"
@@ -34,52 +31,6 @@
# include <malloc.h>
#endif
/*
* Implementation of the table functor, which provides logic with up
* to 4 inputs.
*/
table_functor_s::table_functor_s(truth_t t)
: table(t)
{
count_functors_logic += 1;
}
table_functor_s::~table_functor_s()
{
}
/*
* WARNING: This function assumes that the table generator encodes the
* values 0/1/x/z the same as the vvp_bit4_t enumeration values.
*/
void table_functor_s::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&val)
{
input_[ptr.port()] = val;
vvp_vector4_t result (val.size());
for (unsigned idx = 0 ; idx < val.size() ; idx += 1) {
unsigned lookup = 0;
for (unsigned pdx = 4 ; pdx > 0 ; pdx -= 1) {
lookup <<= 2;
if (idx < input_[pdx-1].size())
lookup |= input_[pdx-1].value(idx);
}
unsigned off = lookup / 4;
unsigned shift = lookup % 4 * 2;
unsigned bit_val = table[off] >> shift;
bit_val &= 3;
result.set_bit(idx, (vvp_bit4_t)bit_val);
}
vvp_send_vec4(ptr.ptr()->out, result);
}
vvp_fun_boolean_::vvp_fun_boolean_(unsigned wid)
{
net_ = 0;
@@ -259,8 +210,9 @@ void vvp_fun_bufz::recv_real(vvp_net_ptr_t ptr, double bit)
vvp_fun_muxr::vvp_fun_muxr()
: a_(0.0), b_(0.0)
{
net_ = 0;
count_functors_logic += 1;
select_ = 2;
select_ = SEL_BOTH;
}
vvp_fun_muxr::~vvp_fun_muxr()
@@ -270,7 +222,7 @@ vvp_fun_muxr::~vvp_fun_muxr()
void vvp_fun_muxr::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
{
/* The real valued mux can only take in the select as a
vector4_t. the muxed data is rea. */
vector4_t. The muxed data is real. */
if (ptr.port() != 2)
return;
@@ -278,30 +230,21 @@ void vvp_fun_muxr::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
switch (bit.value(0)) {
case BIT4_0:
select_ = 0;
if (select_ == SEL_PORT0) return;
select_ = SEL_PORT0;
break;
case BIT4_1:
select_ = 1;
if (select_ == SEL_PORT1) return;
select_ = SEL_PORT1;
break;
default:
select_ = 2;
if (select_ == SEL_BOTH) return;
select_ = SEL_BOTH;
}
switch (select_) {
case 0:
vvp_send_real(ptr.ptr()->out, a_);
break;
case 1:
vvp_send_real(ptr.ptr()->out, b_);
break;
default:
if (a_ == b_) {
vvp_send_real(ptr.ptr()->out, a_);
} else {
// Should send NaN?
vvp_send_real(ptr.ptr()->out, 0.0);
}
break;
if (net_ == 0) {
net_ = ptr.ptr();
schedule_generic(this, 0, false);
}
}
@@ -309,34 +252,57 @@ void vvp_fun_muxr::recv_real(vvp_net_ptr_t ptr, double bit)
{
switch (ptr.port()) {
case 0:
if (a_ == bit)
break;
if (a_ == bit) return;
a_ = bit;
if (select_ == 0)
vvp_send_real(ptr.ptr()->out, a_);
if (select_ == SEL_PORT1) return; // The other port is selected.
break;
case 1:
if (b_ == bit)
break;
if (b_ == bit) return;
b_ = bit;
if (select_ == 1)
vvp_send_real(ptr.ptr()->out, b_);
if (select_ == SEL_PORT0) return; // The other port is selected.
break;
default:
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
assert(0);
}
if (net_ == 0) {
net_ = ptr.ptr();
schedule_generic(this, 0, false);
}
}
void vvp_fun_muxr::run_run()
{
vvp_net_t*ptr = net_;
net_ = 0;
switch (select_) {
case SEL_PORT0:
vvp_send_real(ptr->out, a_);
break;
case SEL_PORT1:
vvp_send_real(ptr->out, b_);
break;
default:
if (a_ == b_) {
vvp_send_real(ptr->out, a_);
} else {
vvp_send_real(ptr->out, 0.0); // Should this be NaN?
}
break;
}
}
vvp_fun_muxz::vvp_fun_muxz(unsigned wid)
: a_(wid), b_(wid)
{
net_ = 0;
count_functors_logic += 1;
select_ = 2;
select_ = SEL_BOTH;
has_run_ = false;
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
a_.set_bit(idx, BIT4_X);
b_.set_bit(idx, BIT4_X);
@@ -351,34 +317,53 @@ void vvp_fun_muxz::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
{
switch (ptr.port()) {
case 0:
if (a_ .eeq(bit) && has_run_) return;
a_ = bit;
if (select_ == SEL_PORT1) return; // The other port is selected.
break;
case 1:
if (b_ .eeq(bit) && has_run_) return;
b_ = bit;
if (select_ == SEL_PORT0) return; // The other port is selected.
break;
case 2:
assert(bit.size() == 1);
switch (bit.value(0)) {
case BIT4_0:
select_ = 0;
if (select_ == SEL_PORT0) return;
select_ = SEL_PORT0;
break;
case BIT4_1:
select_ = 1;
if (select_ == SEL_PORT1) return;
select_ = SEL_PORT1;
break;
default:
select_ = 2;
if (select_ == SEL_BOTH && has_run_) return;
select_ = SEL_BOTH;
}
break;
default:
return;
}
if (net_ == 0) {
net_ = ptr.ptr();
schedule_generic(this, 0, false);
}
}
void vvp_fun_muxz::run_run()
{
has_run_ = true;
vvp_net_t*ptr = net_;
net_ = 0;
switch (select_) {
case 0:
vvp_send_vec4(ptr.ptr()->out, a_);
case SEL_PORT0:
vvp_send_vec4(ptr->out, a_);
break;
case 1:
vvp_send_vec4(ptr.ptr()->out, b_);
case SEL_PORT1:
vvp_send_vec4(ptr->out, b_);
break;
default:
{
@@ -401,7 +386,7 @@ void vvp_fun_muxz::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
for (unsigned idx = min_size ; idx < max_size ; idx += 1)
res.set_bit(idx, BIT4_X);
vvp_send_vec4(ptr.ptr()->out, res);
vvp_send_vec4(ptr->out, res);
}
break;
}
@@ -573,9 +558,6 @@ void compile_functor(char*label, char*type, unsigned width,
} else if (strcmp(type, "MUXR") == 0) {
obj = new vvp_fun_muxr;
} else if (strcmp(type, "MUXX") == 0) {
obj = new table_functor_s(ft_MUXX);
} else if (strcmp(type, "MUXZ") == 0) {
obj = new vvp_fun_muxz(width);
@@ -645,4 +627,3 @@ void compile_functor(char*label, char*type, unsigned width,
define_functor_symbol(label, net_drv);
free(label);
}
+16 -35
View File
@@ -1,7 +1,7 @@
#ifndef __logic_H
#define __logic_H
/*
* Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-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,34 +18,11 @@
* 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: logic.h,v 1.25 2006/11/28 05:57:20 steve Exp $"
#endif
# include "vvp_net.h"
# include "schedule.h"
# include <stddef.h>
/*
* Table driven functor. This kind of node takes 4 inputs and
* generates a single output. The logic is bitwise, and implemented
* with a lookup table.
*/
class table_functor_s: public vvp_net_fun_t {
public:
typedef const unsigned char *truth_t;
explicit table_functor_s(truth_t t);
virtual ~table_functor_s();
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
private:
truth_t table;
vvp_vector4_t input_[4];
};
/*
* vvp_fun_boolean_ is just a common hook for holding operands.
*/
@@ -124,6 +101,8 @@ class vvp_fun_bufz: public vvp_net_fun_t {
private:
};
enum sel_type {SEL_PORT0, SEL_PORT1, SEL_BOTH};
/*
* The muxz functor is an A-B mux device, with the data inputs on
* ports 0 and 1. port 2 is the select input.
@@ -135,7 +114,7 @@ class vvp_fun_bufz: public vvp_net_fun_t {
* input (port-0 or port-1) to enter the device. The narrow vector is
* padded with X values.
*/
class vvp_fun_muxz : public vvp_net_fun_t {
class vvp_fun_muxz : public vvp_net_fun_t, private vvp_gen_event_s {
public:
explicit vvp_fun_muxz(unsigned width);
@@ -143,13 +122,18 @@ class vvp_fun_muxz : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
private:
void run_run();
private:
vvp_vector4_t a_;
vvp_vector4_t b_;
int select_;
vvp_net_t*net_;
sel_type select_;
bool has_run_;
};
class vvp_fun_muxr : public vvp_net_fun_t {
class vvp_fun_muxr : public vvp_net_fun_t, private vvp_gen_event_s {
public:
explicit vvp_fun_muxr();
@@ -158,10 +142,14 @@ class vvp_fun_muxr : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
void recv_real(vvp_net_ptr_t p, double bit);
private:
void run_run();
private:
double a_;
double b_;
int select_;
vvp_net_t*net_;
sel_type select_;
};
class vvp_fun_not: public vvp_net_fun_t, private vvp_gen_event_s {
@@ -202,11 +190,4 @@ class vvp_fun_xor : public vvp_fun_boolean_ {
bool invert_;
};
// table functor types
extern const unsigned char ft_MUXX[];
extern const unsigned char ft_EEQ[];
extern const unsigned char ft_TRIAND[];
extern const unsigned char ft_TRIOR[];
#endif // __logic_H
-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

Some files were not shown because too many files have changed in this diff Show More