Compare commits

...

152 Commits

Author SHA1 Message Date
Stephen Williams 4d4a693248 Improve some assert messages
Replace some assert functions with ivl_assert.
2009-09-16 14:45:55 -07:00
Cary R 1872652019 Don't check the scope for array words.
We do not want to check an array word scope to see if the scope
was already included since a scope does not include array words.
They must be explicitly specified.
(cherry picked from commit 0b6bd343e8)
2009-09-15 20:51:11 -07:00
Cary R d68fea3f58 Warn that events can not be user task or function arguments.
This patch makes events passed as arguments to user tasks or functions
a compile time error with an appropriate error message.
(cherry picked from commit 4d57ede0e5)
2009-09-15 20:45:49 -07:00
Cary R b0e2185ade Fix 64 bit problem in vvp/vpi_signal.c
This is based on a suggested fix from Martin. It fixes the crash
for two tests in the test suite. As a bonus it is more efficient.
(cherry picked from commit 43f41572cb)
2009-09-15 20:40:14 -07:00
Cary R 6aaf2f84a8 Squash some gcc 4.3.3 warnings.
This patch clears all the gcc 4.3.3 warning that can be fixed.
The remaining warning is dictated by older versions of the
1364 standard.
(cherry picked from commit 6d5d06cae4)
2009-09-15 20:38:57 -07:00
Cary R 7ad50f4454 Revert one change from previous patch.
I was mistaken in changing the cast in the comparison.
(cherry picked from commit 5a11a8a9c2)
2009-09-15 20:35:48 -07:00
Cary R 19b0d5b7c9 Fix another 64 bit problem in a part select.
This patch fixes a problem in the .part/v select when the index is
undefined. The default value needs to be INT_MIN, so when the long
is cast to an int the value is in range.
(cherry picked from commit 1b300cb2f6)
2009-09-15 20:35:35 -07:00
Cary R ae87aff745 Fix .part/v to only use a 32 bit value.
To get better functionality in V0.9 and development until we
add a select that is sign aware to .part/v this patch uses
a 32 bit integer (int) for the select value. This allows a
normal Verilog integer to produce the correct results. A
warning for smaller signed index vectors is planned, but it
needs more input.
(cherry picked from commit 27f032760e)
2009-09-15 20:35:24 -07:00
Cary R 9c09394785 Add support for 'bx from a signal to &PV<>
&PV<> was just using vpi_get_value() when a signal was driving
the select. This incorrectly returned 0 for 'bx or 'bz. This
patch adds a check for an undefined value and returns INT_MIN
for this case.
(cherry picked from commit 1b0dd8c8e5)
2009-09-13 08:38:08 -07:00
Cary R 3f8f81568a Add file/line information to named events and better expr. error.
This patch adds file and line number information to named events.
It also modifies the draw_eval_expr_wid() routine to fail with
an appropriate message for named events. This checking needs to
be pushed into the elaboration stage, but this will give a better
message than we had before.
(cherry picked from commit dff6a1ebff)
2009-09-13 08:34:59 -07:00
Martin Whitaker bb5d30ead5 Add user control over implicit sensitivity list warnings.
This patch adds two new warning classes that can be enabled or
disabled via the -W command line option. The first controls
whether a warning is generated if a part select within an
always @* statement causes the entire vector to be added to
the implicit sensitivity list. The second controls whether a
warning is generated if a word select within an always @*
statement causes the entire array to be added to the implicit
sensitivity list. The first class is not automatically enabled
by -Wall, the second class is.
(cherry picked from commit fc49420cb5)
2009-09-13 08:27:54 -07:00
Nick Gasson 4e77abca44 Allow labelled begin blocks to contain processes in VHDL target
This is a simple fix for a crash that occured when a process
was inside a labelled begin inside a generate statement.
(cherry picked from commit face1a1d15)
2009-09-03 18:16:47 -07:00
Nick Gasson 902ae19bbf Handle generate scopes with signals in VHDL target
This uniques the name of each copy of a signal and adds
it to the containing VHDL entity.
(cherry picked from commit 388c9c6747)
2009-09-03 18:16:35 -07:00
Nick Gasson 5587e42e2e Translate simple generate loops to VHDL
This handles generate loops and genvars with no local variables
(cherry picked from commit bc7ec04cab)
2009-09-03 18:16:18 -07:00
Cary R f8f363a0b6 Remove old configure files in vvp directory.
(cherry picked from commit 5f08f40cad)
2009-09-03 18:15:23 -07:00
Cary R f34485d415 Support negative index for %assign/av opcodes.
If the array index is negative these opcodes need to just return.
(cherry picked from commit 9d765820bf)
2009-09-03 18:12:40 -07:00
Cary R df177e9e14 Major rewrite of indexed part selects.
This patch is a major rewrite of the indexed part selects (+: and -:).

It made the following enhancements:

1. Make indexed part selects work correctly with both big and little
   endian vectors.

2. Add a warning flag that warns about constant out of bounds/or 'bx
   indexed selects.

3. Moved the -: parameter code to its own routine.

4. Added support for straddling before part selects in a CA.

5. Added more assert(! number_is_unknown) statements.

6. Add warning for &PV<> select with a signed index signal that is
  less than the width of an int. This will be fixed later.

7. Add support for loading a 'bx/'bz constant into a numeric register.

8. Add a number of signed value fixes to the compiler/code generator.

9. Major fix of draw_select_expr() in the code generator.
(cherry picked from commit 2b17366ad5)
2009-09-03 18:07:51 -07:00
Cary R 5d4c8d616a Propagate sign in synthesize for math operators.
The sign of the expression needs to be propagated for the
math operators when they are synthesized.
(cherry picked from commit a49463e728)
2009-09-03 18:02:40 -07:00
Cary R 72c02a8285 Pass file/line information for part selects.
Propagate the file and line information for a part select
expression and LPM (continuous assign).
(cherry picked from commit 06997c63ed)
2009-09-03 18:02:24 -07:00
Cary R 043c86ba02 Enhance %shiftr/i0 and $shiftl/i0 to work with negative shifts.
The %shiftr/i0 and %shiftl/i0 opcodes are used for some part
selects and if we have a negative shift we want the value to be
padded with 'bx. This patch enhances the two %shift/i0 opcodes
to work with negative shifts and for negative shifts pad with
'bx instead of 'b0.

It also fixes %ix/get/s to use a uint64_t instead of a unsigned
long to avoid problems with sign extension on 32 bit machines.
(cherry picked from commit ecb00017cb)
2009-09-03 18:02:02 -07:00
Cary R b9d0783ad9 Assert number is not unknown for many cases in tgt-vvp.
This patch adds a number of asserts that a number is not unknown
in places where this should never happen.
(cherry picked from commit d108221fef)
2009-09-03 18:01:43 -07:00
Cary R 047ee137ed Add vvp support for out of bound variable part selects.
This patch adds support for variable part selects with out of bound
and 'bx index values.
(cherry picked from commit 1306a6db81)
2009-09-03 18:01:27 -07:00
Cary R ef814a9ef4 Add a -Wselect-range warning class.
This patch adds support for a -Wselect-range warning class to the
driver and ivl programs. This is part of -Wall. The actual checks
will be added in a later patch.

Cherry-picked from e576e1eb2c
2009-09-03 18:00:31 -07:00
Cary R fa0ecb3761 Convert IVL_LPM_CONCAT to use ivl_lpm_size() instead of ivl_lpm_selects()
It was documented that a IVL_LPM_CONCAT would use _size() instead
of _selects(). This patch adds the functionality to _size() and
converts all the Icarus provided code generators to use _size().
_select() will be kept for compatibility in V0.9.
(cherry picked from commit 4cd790a2d2)
2009-09-03 17:52:35 -07:00
Cary R f2a81cf660 Fix subtle bug in scope checking.
This check looks to be defined to check the child scope not the
top level scope.
(cherry picked from commit 872962ef18)
2009-09-03 17:49:18 -07:00
Cary R e1b4d531a1 Update config.guess and config.sub to latest version.
This patch updates the config.guess and config.sub files to the
latest ones from automake 1.11.
(cherry picked from commit 9669ccd011)
2009-09-03 17:48:17 -07:00
Cary R a418995988 Update MinGW requirements, etc.
The old readline library was causing problem. I updated the mingw.txt
file to use the gnuwin32 version of readline (5.0-1) which works. I
also mentioned that I plan to rewrite the directions using a newer
version of MinGW.
(cherry picked from commit a51f2dca50)
2009-09-03 17:46:53 -07:00
Cary R 8c36e20fd4 Add support for an undefined index for the %load/a* opcodes.
These opcodes need to return 'bx or 0.0 for the real opcode when
the array index is undefined.

The patch also documents the auto incrementing of the bit
index register done by the %load/avx.p opcode.
(cherry picked from commit 8623f804f2)
2009-09-03 17:40:01 -07:00
Cary R 2c982a6edb Add missing limits.h include in vpi_signal.cc
(cherry picked from commit 83c7a24cff)
2009-09-03 17:37:52 -07:00
Cary R a298bfb22a For a part select driving another part select the extra bits must be 'bz.
When a part select is driving another part select any bits outside the
original select must be 'bz instead of 'bx. If we initialize the temporary
buffer to 'bz this should work as required. It there are multiple drivers
then a resolver comes into play and this should not matter.
(cherry picked from commit e31b6bd20c)
2009-09-03 17:35:16 -07:00
Cary R cce61d7134 Ignore a zero MCD for $fflush, $fdisplay*, $fwrite* and $fstrobe*.
(cherry picked from commit ed4e2eb046)
2009-09-03 17:30:12 -07:00
Martin Whitaker aad5443a36 Fix for pr2842185 and for genvar scopes.
When checking for name collisions, the compiler looks for genvar
declarations in the enclosing module rather than in the current
scope, which leads to false positives. The compiler also places
all genvar declarations in the enclosing module scope, even when
the declarations are inside a generate block which has its own
scope. This patch fixes both these faults. It also fixes some
typos and outdated information in comments.
(cherry picked from commit da010db739)
2009-09-03 17:24:45 -07:00
Martin Whitaker f5f104f8a6 Fix for pr2837451.
pr2827132 changed the val_ field in vvp_fun_part_sa to only store
the bit values for the selected part, not the entire source vector,
but omitted to modify the recv_vec4_pv method to handle this change.
This patch rectifies that omission.
(cherry picked from commit 7c6176357f)
2009-08-18 17:33:30 -07:00
Cary R b7ff68c3f4 Fix a few more minor memory leaks.
This patch fixes a few more memory leaks that can happen under
error conditions.
(cherry picked from commit 35f3d7f60e)
2009-08-18 15:00:12 -07:00
Cary R 69986a5bc7 Do not schedule a new event if the previous event has the same value.
If the previous event has exactly the same value as this event then
we do not add this event to the event queue.
(cherry picked from commit 2e820ca6f0)
2009-08-18 14:56:14 -07:00
Cary R c0f4b0374a Warn that we do not support non-blocking assignment to real array words.
A while ago we changed how variable arrays were accessed. This change
did not get propagated to the non-blocking assignment for real array
words. This patch adds a warning that this is not currently supported.
We can add this to development, but not V0.9 (interface change).
(cherry picked from commit 88b18d4212)
2009-08-18 14:52:35 -07:00
Cary R 817b1ef3d4 UDPs need to evaluate their arguments before generation
When generating a .udp call the arguments need to be evaluated
before the .udp is. This allows things like .resolv to be built
correctly.
(cherry picked from commit cb5c4299fb)
2009-08-18 14:48:30 -07:00
Cary R f9774758a3 UDPs can only take two delay values.
Check in the compiler that a UDP is only given two delay values.
(cherry picked from commit 7916e148f8)
2009-08-18 14:45:31 -07:00
Cary R eb2fed7015 Fix some memory leaks/issues found with cppcheck.
I ran cppcheck on the code and it found a few obscure memory leaks and
a few other issues. This patch fixes most of them.
(cherry picked from commit 2e166b7279)
2009-08-18 14:36:32 -07:00
Stephen Williams 5af47cda12 Fix man page formatting for portability. 2009-08-10 06:34:18 -07:00
Cary R 0aad444bbf Add full $ferror() support, bug fixes, etc.
This patch adds $ferror() support. This is enhanced over what the standard
says needs to be supported. All file I/O routines set/clear the errno flag,
This allows $ferror() to check when an invalid fd/MCD is passed to a
system task. The $ferror() fd is only checked if errno is not set since
all the other routines will set EBADF when they are called. This allows us
to test the output from $fopen() which sets the fd to zero (an invalid fd)
when it has a problem.

The following bugs (changes) are also fixed:

Fix $fdisplay*, $fwrite*, $fstrobe*, $fflush, $fclose to not accept 0 as
a valid MCD.

For the $fdisplay*, $fwrite* and $fstrobe tasks an invalid fd/MCD is now
a warning instead of an error like the other file I/O routines.

Modify $fputc() to be a function and return a value like $ungetc().

Modify $ungetc() to return a value like the standard dictates (-1 on
error else 0) and pass the value as a full int to get EOF as an error.

Remove some extra checks that could not happen in $fseek() and to
be safe convert the numeric codes to the system symbolic values.

Skip $fstrobe callback when the fd/MCD is closed. The standard says
we need to cancel the callback, but we currently do not have the
ability to do that so just skipping this will work for now.

Free the argument handle when $fscanf() is called with an invalid fd
(memory leak).
(cherry picked from commit ce89a68735)
2009-08-02 11:07:23 -07:00
Cary R e63c75d1a3 Add a warning when we reach 1024 files.
It's not too likely we will ever reach this, but we should be nice
and print a message instead of just failing. We could set errno,
but for now the warning will have to be enough.
(cherry picked from commit b0ac550791)
2009-08-02 11:04:24 -07:00
Cary R a5b0872016 Fix memory leak, unneeded argument.
Very minor issues dosify was not closing files so memory leaks could
show up and vpi/sys_readmem.c was passing the file after it was
closed to the lexor cleanup code. The lexor cleanup code does not
need an argument.
(cherry picked from commit 52fbb3f734)
2009-08-02 11:01:31 -07:00
Cary R f6b9db1c78 Add full genvar support and name space checking.
This patch adds genvars to the elaboration process. It adds checks
that a genvar is defined for a generate loop and that a genvar does
not conflict with any other items in its name space.
(cherry picked from commit 72a98e85cb)
2009-07-29 08:56:01 -07:00
Martin Whitaker 597097eaef Fix for pr2821633.
Currently, edge event functors declared in automatically allocated
scopes that are used to detect edges on signals declared in static
scopes are unable to correctly determine edge information for the
first signal delta they receive because they do not know the old
state of the signal. This patch causes the state of static signals
received by these event functors to be recorded as static state in
the functors, so the old state of the signals can be initialised
to the correct value when a new automatic context is created.
(cherry picked from commit d7fe9c613c)
2009-07-29 08:52:50 -07:00
Martin Whitaker 47512e351f Suppress unnecessary update of part select functor output.
Currently a part select functor will send updates to nodes connected
to its output whenever any part of its input vector changes. This
patch ensures updates are only sent when the selected part of the
input vector changes.
(cherry picked from commit 1453c5b0bb)
2009-07-29 08:50:28 -07:00
Cary R 506c09f5f8 Fix power operator width in self-determined context.
In a self determined context the width of the power operator
is defined to be the left argument width.
(cherry picked from commit e98000426e)
2009-07-29 08:47:25 -07:00
Cary R 693fb93962 Fix CA replication of zero issues.
This patch fixes a CA to evaluate and ignore a replication of zero.
It also fixes a minor glitch in the data type calculation code. This
was causing a problem if a zero width replication was the first
element in a concatenation/replication since the data type was hard
coded to the first element of the concatenation/replication. It now
uses the first defined element in the concatenation/replication to
determine the data type.
(cherry picked from commit b629d913d2)
2009-07-29 08:44:15 -07:00
Cary R 8ca5926db9 Fix procedural concatenation/repetition problems
This patch evaluates the whole concatenation expression and
makes the concatenation padding sign aware. This is needed
when $signed({...}) is passed as an argument.

A repetition is just N copies of the base expression not N
evaluations of the base expression. This is only a problem
when functions have side effects. It's also faster to copy.
The evaluation must also be done when the replication count
is zero (see 1364-2005).
(cherry picked from commit e362a86b16)
2009-07-29 08:44:05 -07:00
Cary R 7acafd128f The scanf functions must return EOF if source starts at the end of input.
The $fscanf() and $sscanf() functions are defined to return EOF when
the end of input is reached before any matches or match failures have
occurred.
(cherry picked from commit c5ee1fdbf5)
2009-07-29 08:40:47 -07:00
Cary R d0a12f5b14 When skipping C-style comments in a skipped `ifdef include the '\n'
When a C-style comment /* */ is being skipped because it is in a
skipped `ifdef, `ifndef, etc. directive then we need to output a
'\n' at any comment end of line.
(cherry picked from commit e932c41587)
2009-07-29 08:37:59 -07:00
Cary R 8964a175f8 Find the width of net arrays correctly.
Add code to the generic get_array_word_size() function to correctly
find the width of net arrays and use this routine in the _vthr_
code as needed.
(cherry picked from commit 212bd4134a)
2009-07-29 08:34:49 -07:00
Cary R 97d70f9069 base if for ivl pbase is for ivlpp 2009-07-29 08:31:43 -07:00
Cary R 0dc0fbf78d Add check for prec > unit in `timescale directive. 2009-07-29 08:28:14 -07:00
Cary R 786b3a0ca9 Real constants are always signed.
Set the signed_flag_ for real constants.
2009-07-29 08:21:36 -07:00
Cary R 24a60ce6af Add compiler warnings for more constant out of bounds array accesses.
This patch adds compiler warning messages for all/most constant out
of bounds array access.
2009-07-06 15:08:56 -07:00
Cary R 4c640f67cb More VCD enhancements.
Make the code smarter so it can keep fewer items in the lists.
Scopes and explicitly given variables are all that is kept.
Includes a few other refinements.
2009-07-06 15:06:15 -07:00
Cary R cfe68fe6b4 Add basic support for events and cleanup VCD dumper.
This patch adds support for dumping named events to the VCD
dumper only. The LXT and LXT2 will be added once this has
been tested more. It also reworks the $dumpvars routine
to be more consistent concerning warning messages for duplicate
signal dump requests and fixes some bugs.

For events you will get extra events at T0 and at $dumpon. I
plan to fix this, but that is much more involved.

For duplicate signal warnings. Implicit duplicates loaded
automatically from a scope will not display a warning. Only
an explicit signal request will print a warning if it was
already included. All other will be silently ignored. This
should limit the warning to only what the user cares about.

For example:

  $dumpvars(0, var, scope_that_includes_var);

Will work without a warning message.

  $dumpvars(0, scope_that_includes_var, var);

Will generate a warning since the var was already included
by the scope request.

Other enhancements include the start of including type
information in the output. For now integer is added, the
other type information will require changes to the code
generator and hence will only be done in development.
2009-07-06 15:06:02 -07:00
Cary R 78149e9d15 Use correct sign for signal and constant addition.
This was incorrectly using the expression sign not checking if
the two sub-expressions are both signed. This likely used to
work, but in the context of $signed which sets the expression
to signed so we can have a signed expression without both
sub-expressions being signed.
2009-07-06 15:01:23 -07:00
Cary R bbe037bf9f Print a warning for an implicit sensitivity list that has selects.
An implicit sensitivity list that has selects (bit, part, indexed
part or array) will include more than the user expects so print a
warning to let them know what will happen. Other simulators have
the same behavior, but I believe this is incorrect and needs to
be fixed to only include the appropriate parts. The warnings can
go when we fix this functionality, but we need them now to warn
the user that they may not be getting what they expect. One other
simulator warns for array selects.

This patch also adds the array index to the sensitivity list.
2009-06-23 09:53:31 -07:00
Cary R d3bf6be7b2 Fix real variable array and net array bugs.
This patch fixes a number of bugs related to real variable and net
arrays. Specifically the following:

1. When iterating over (scanning) a net array start at base index 0
   not index 1.

2. Don't fail when iterating over (scanning) a real variable array.

3. Run the array_word_change() routine when a real variable array
   word is changed. This allows array ports and value change
   callbacks to work correctly.

4. Update the array_word_change() routine to work with real variable
   arrays.

5. Update the array port code to support real variable arrays.

6. find_name() needs to also iterate over net array words just like
   memory array words.

7. Initialize all real array words to 0.0 when the array is created.
2009-06-23 09:50:13 -07:00
Cary R 6146a98278 Make the dumpers match better (VCD, LXT, LXT2).
This patch removes some of the unneeded differences in the
various dumper routines. This is the start of a complete
refactoring, but the first task is to make them as common
as possible and this is the start of that.
2009-06-23 09:43:22 -07:00
Cary R 63c7285113 For real expressions evaluate non-real sub-exprs as bits and convert.
When processing procedural real expressions we need to evaluate
non-real sub-expressions as bit based expressions and then
convert the result to a real value. This is particularly import
for integer division.
2009-06-23 09:37:41 -07:00
Cary R 79e0203280 Use a default buffer size of 512 vs 256 for displaying.
This patch changes the initial buffer size when displaying results
to 512 from 256. This initial buffer is used as the default for the
floating point results and failed when %f is given a large, but
valid value. To make this even more safe we add the precision to
the size to make sure we do not overflow the buffer.
2009-06-23 09:31:18 -07:00
Cary R ad419dfbe4 Parse the config declarations and report they will be ignored.
This patch adds code to parse config declarations and reports
that they are not currently supported and will be ignored.
2009-06-23 09:25:21 -07:00
Cary R 75d71fe312 Some compiler cleanup and minor memory leak fixes.
This patch cleans up some unneeded code. Releases some allocated
memory before the compiler quits and fixes a couple minor memory
leaks in the compiler and vvp code generator.
2009-06-23 09:14:03 -07:00
Cary R 5a30355faf Ignore specify pulsestyle_* and *showcancelled directives.
This patch adds code to silently ignore the specify directives:
  pulsestyle_onevent
  pulsestyle_ondetect
  showcancelled
  noshowcancelled.
2009-06-08 11:12:04 -07:00
Cary R 623e897e55 Some delay expressions need to probe their width (ternary)
The ternary operator requires that the expression width be defined.
This requires that the delay expression has test_width() run on it.
2009-06-08 11:09:10 -07:00
Cary R 0bb6360ac7 Allocate the fd table dynamically in 32 entry chunks.
The fd table used to be statically allocated with only 32 entries.
Three of these were preallocated for stdin, stdout and stderr
leaving only 29 for the user.  This patch makes the allocation of
this table dynamic with a hard limit at 1024 total fds. The table
is increased in 32 bit chunks.
2009-06-08 11:06:43 -07:00
Cary R 4b850e1e74 Fix bugs in &= and |= for vvp_vector4_t
Someone got a bit too creative in reducing the original equations
I wrote to handle this. This patch reverts the previous code and
uses my original equations. This passes for both wide and narrow
vectors. The equations are slightly more complicated, but the old
z2x conversion had some overhead. I would expect the time to be
about the same, but you now get the correct results.
2009-06-08 09:45:25 -07:00
Cary R 8ce807a263 Parse all the 1364-1995 and 1364-2001 timing checks.
This patch adds code to parse and ignore the following timing checks:

$nochange  1364-1995
$skew      1364-1995
$fullskew  1364-2001
$removal   1364-2001
$timeskew  1364-2001

The other checks were already supported. These have not been tested,
but they use the same basic terms as the other checks. We can fully
test these when we actually implement them.
2009-06-08 09:26:54 -07:00
Cary R cc9524bd89 Fix some keywords, add -g2001-noconfig and fix up uwire/wone.
This patch adds -g2001-noconfig command line flag. The compiler
already supported this with `begin_keywords. Document this in
the manual page and fix a few other issues.

Fix endgenerate to be a 2001 keyword and add a few missing
keywords at the appropriate standard level e.g.(unsigned).

Add uwire and deprecate wone. wone used to just convert without
a warning to a wire. uwire will display a warning that it is
being converted to a wire without a check. wone is converted to
a uwire with a warning and then prints the uwire message. The
uwire message will be replaced with a real check fairly soon.
2009-06-08 09:20:27 -07:00
nog 13e07d6b7c Avoid stepping on free'd memory during recursive macro expansion
During macro expansion (with arguments), there is one global buffer
(exp_buf) that keeps getting reallocated to fit all the macro's text
that's currently being expanded.  The problem with this scheme is that if
a macro with arguments needs to be expanded from the macro text of another
macro with arguments, it may happen that the second expansion forces
the above exp_buf buffer to be reallocated.  Which is fine until the
previous macro processing resumes where (struct include_stack_t *)->str
now points to uninitialised memory.  Basically, the code that can trigger
such behaviour is as follows:

`define FOO(a)	(a+3)
`define BAR(b)	(`FOO(b)+2)

`BAR(x)

Ofcourse, you need to get lucky to get the exp_buf to be realloced at the
right point, but it's possible.

I don't see the advantage in keeping all the expanding macro's text
together, so my solution is to simply allocate a new buffer and pass it
as (struct include_stack_t *)->str to the flex parsing function and free
it at the end.
2009-06-08 08:51:31 -07:00
Cary R bbf11b830b Add support for unconnected_drive.
Icarus has recognized this directive, but it did not do anything
with the information. This patch adds the functionality for most
common cases. It adds this by changing the input net type from
wire/tri to tri1 or tri0 depending on the pull. The issue is that
if the input net is not a wire or tri this is not safe and should
really be done as an external pull gate connected to the input.
We will need to handle this is it ever comes up. For now a sorry
message is printed.
2009-06-08 08:42:12 -07:00
Cary R d345fb7654 Add more default net types
Previously Icarus only supported a default net type of wire or none.
This patch adds the rest of the supported net types (all except
uwire and trireg) to the `default_nettype directive. It also fixes
make_implicit_net_() to use the default_nettype instead of always
using implicit (the same as wire).
2009-06-08 08:25:21 -07:00
Cary R 3186e3dc54 Rework the `timescale directive and cleanup `line a bit.
This patch reworks the `timescale directive to do a better
job of parsing the line, it refactors some of the code and
should produce better error messages. It also tightens up
parsing the numeric constant, etc. to better match the
Verilog standard.

The parsing of `line has been enhanced to only allow 0, 1 or
2 for the level and a single line comment at the end of the
line is ignored.
2009-06-07 21:45:31 -07:00
Cary R d4d50fd97d Use strchr() instead of index().
strchr() is more portable and index() is not available under
MinGW so replace index() with strchr().
2009-06-07 21:30:42 -07:00
Cary R 3337c9d51a Make ivl warn that it does not support `ifndef or `elsif
We added support for these two directives some time ago,
but ivl was never updated to warn that it did not support
them and you needed to use ivlpp.
2009-05-24 10:36:33 -07:00
Cary R dfda202f14 Add better error checking to the two line directives.
Icarus supports both a #line and `line directive. This patch
reworks the parsing of these to provide better error detection
and full checking.
2009-05-24 10:34:06 -07:00
Cary R 5ca440dc1c Add support for `resetall and other directive changes.
This patch adds support for the `resetall directive.

It also changes `celldefine, `endcelldefine and `resetall
to no longer grab text following them. These directives do
not take an argument so they should not be grabbing any
text and silently discarding it.

The `timescale processing was reworked to handle being
reset and hooks were added to easily change the default
time units and precision when we add that feature request.
2009-05-24 10:28:42 -07:00
Cary R 96908e2fc5 Add compiler support for `celldefine, vpiCellInstance
This patch adds support to the compiler and stub backend for
`celldefine. This matches the compiler portion of the full
support that was added to 0.10.devel. This does not change
vvp or the vvp interface since changing the interface is not
allowed in a stable branch.
2009-05-24 10:21:37 -07:00
Cary R 9f07e3c16e Print a better error message for a '~' token in front of ('&' | '|' | '^')
Some users may expect this to work so this patch catches these
specific cases and tells the user to use the singe unary operators
'~&', etc. instead.
2009-05-24 10:18:51 -07:00
Cary R 3ae3e34732 Cleanup if an invalid option is given.
Cleanup the temporary files and memory if iverilog is given
an invalid option.
2009-05-24 10:16:13 -07:00
Cary R 372efd8c30 Fix memory leak when parsing command files.
These are not leaks in the true sense of the word, but it is
memory that is not being freed before the program finishes
so valgrind will complain about this.
2009-05-24 10:15:45 -07:00
Larry Doolittle ac7f55f22a Remove fresh const lint
It looks pretty stupid and non-c++-y, but it does remove two compiler warnings
vvp/stop.cc: In function 'void stop_handler(int)':
vvp/stop.cc:492: warning: deprecated conversion from string constant to 'char*'
vvp/stop.cc:493: warning: deprecated conversion from string constant to 'char*'
2009-05-24 10:14:01 -07:00
Cary R b74736c784 Display and error for hierarchical references in a parameter r-value expr.
Display and error message when the user uses a hierarchical reference
in a parameter r-value expression.
2009-05-19 08:38:46 -07:00
Cary R 7988ef04d8 Add support for displaying a real parameter using %d.
This patch modifies the real parameter get_value routine to use
the standard vpip_real_get_value() routine. This routine has
support for an integer and a decimal string value.
2009-05-19 08:33:02 -07:00
Cary R 61214108fe Add support for initializing outputs declared as output reg.
The standard allows an output declared as "output reg" to be
given an initialization assignment in the output declaration.
this patch adds that functionality. Specifically:

  output reg out = 1'b0;

works as expected.
2009-05-19 08:28:39 -07:00
Cary R 356a19c918 Add escaping to the stringification of macros.
Icarus support returning a string version of a macro ``<MACRO>.
The problem was that it did not escape '\' or '"' so if the
macro to be escaped had either of these it would create an
invalid string. This patch fixes this by translating these two
codes to their octal equivalent when the macro is converted.
2009-05-19 08:25:41 -07:00
Cary R f1c5b58845 Fix the %assign/v0/x1 operators for width equal negative offset case.
This patch fixes the three %assign/v0/x1 operators to correctly
notice that the select has fallen off the start of the vector
for the case that the negative offset equaled the width.
2009-05-19 08:22:12 -07:00
Cary R fad37da1dc Fix %t to work with real system functions.
Fix %t to get the real value when the argument comes from a real
valued system function.
2009-05-06 14:25:03 -07:00
Cary R 80f74d0d24 Add a warning message for some array words when dumping.
When dumping an array word the name is implicitly converted to
an escaped identifier. If this implicit name conflicts with an
explicitly created escaped identifier this patch will print a
warning message warning that the array word will conflict with
an escaped identifier.
2009-05-06 14:22:26 -07:00
Cary R d25f689f55 Vec8 delays should schedule like vec4 delays.
This patch adds code to calculate the vec8 delays using the
same method that is used to calculate the vec4 delays.
2009-05-06 14:19:37 -07:00
Cary R 42618741d9 Calculate the width of an array word correctly.
When finding the width of an array word we need to skip any word
selects for the array dimensions.
2009-05-06 14:16:21 -07:00
Cary R 9bcfc8ab6d Check for name space collisions.
This patch adds code to check for most of the name space
collisions. genvars are not checked correctly since they
are not completely implemented.
2009-04-27 18:07:03 -07:00
Cary R de75e71152 Dump the streams when entering interactive mode.
This patch adds code to automatically dump the output stream
including any dump file when entering interactive mode. When
the user typed ^C or $stop was executed.
2009-04-21 15:11:25 -07:00
Cary R 5f8f7bc6fc Add support for dumping non-constant array selects as a constant select.
Dumping array words is an enhancement that we have added to Icarus.
The problem was that if you wanted to dump the whole array you would
like to use a for loop as follows:

for (lp = 0; lp < max ; lp = lp + 1) $dumpvars(0, array[lp]);

This used to work, but some of the VPI rework broke it because it
counted on the word select to be constant. This patch restores the
functionality by converting the variable word select into a constant
word select in the calltf routine. This is done without warning and
only for the $dumpvars() routine.

Adding this functionality necessitated adding support for vpiIndex
to the &A<> routines.
2009-04-21 15:09:01 -07:00
Cary R f7fb754ee8 It is an error to select part of a scalar value.
In 1364-2005 it is an explicit error to take the select of a scalar
or real value. We added the checks for real a while ago. This patch
adds the functionality for scalar values. In the future we may want
to push the scalar property to the run time.
2009-04-21 15:02:14 -07:00
Cary R e59a6b8df7 Warn the user if they use both a default and `timescale based delay.
This patch add code to print a warning message if it finds both a
default and `timescale based delays. The -Wall or more specifically
the -Wtimescale flag can be used to find the module with the missing
`timescale directive.
2009-04-21 14:56:25 -07:00
Cary R f149a30045 Handle $stop and $finish at the interactive prompt.
This patch adds interactive support for $stop and $finish.
$stop displays a message that the simulator is already stopped.
$finish acts exactly like (calls) the interactive "finish"
command. Having $stop do nothing and $finish not finish until
you exit interactive mode is not very intuitive.
2009-04-21 14:54:44 -07:00
Cary R ddaba5b017 Print a better error message for the optional system tasks/funcs
This patch adds better error messages (compiletf) for the optional
system tasks and functions (Annex C 1364-2005). Doing this also
makes calling them fail more gracefully (it is no longer a RE).
2009-04-21 14:42:12 -07:00
Cary R dff535923f Generate better error messages for concat. with indefinite width.
This patch generates a more user friendly error message for a
concatenation with an indefinite width operand.
2009-04-21 14:38:52 -07:00
Cary R d66471c449 Add $readmempath to set a search path for $readmem{b,h}.
This patch add a new system function $readmempath. It accepts
a ":" separated list of directories that $readmem{b,h} will
use when trying to open a given file. If the file given to
$readmem{b,h} starts with a '/' (an absolute path) the search
list will not be used. A new call to $readmempath will replace
the previous search list with the given list. The search list
elements are check to see if they exist and are directories.
If not a warning will be displayed and they will not be added
to the list.
2009-04-21 14:35:29 -07:00
Cary R b16e3ab59e Allow macro expansions to take arguments with multiple arguments.
This patch allows a macro expansion to have an argument which
itself has multiple arguments (handle nested ",").
(cherry picked from commit 047828ded0)
2009-04-08 19:16:26 -07:00
Cary R d7b76e9390 Add support for recursive modules inside generate blocks
This patch adds support for recursive module loops if the
loop contains a generate block. The assumption is that the
user is doing the right thing in the generate block to make
the loop terminate. For this case there is also a check
that limits the number of loops (default 10). This prevents
the system from crashing when the user did not correctly
terminate the looping structure. The limit can be changed
by the user if needed.
(cherry picked from commit 5e723bfd61)
2009-04-08 19:12:39 -07:00
Cary R 6f692e7984 Use the port that has already been fetched.
This patch reuses the port that has already been fetched vs
fetching it again.
(cherry picked from commit a7741d2bd5)
2009-04-08 19:11:22 -07:00
Cary R dfe7279488 Check for both the library and include file when adding history.
When adding history (add_history) use both the existence of the
library and the header file to determine if history can be
supported. Add a new USE_HISTORY that is the and of these two.
(cherry picked from commit 4b2e5e5914)
2009-04-08 19:09:52 -07:00
Cary R b9ea0036de For div/mod only sign extend if both arguments are signed.
Only sign extend the operands for division or modulus if
both of them are signed. Previously only the individual
operand signedness was being considered.
(cherry picked from commit d074a37a2d)
2009-04-08 19:07:24 -07:00
Cary R fc24624fa2 Add support for empty task port lists with a warning.
The standard does not allow this, but it appears that other
simulators do. This patch adds the functionality, but prints
a warning message for the invalid task definition.
(cherry picked from commit 46350da5f0)
2009-04-08 19:05:03 -07:00
Cary R cca3d5907c Skip leading space for some codes in scanf routines.
Most conversion codes in the scanf routines are supposed to
skip leading space. This patch adds that functionality.
(cherry picked from commit e987162cb9)
2009-04-05 14:01:53 -07:00
Cary R ec809c9137 Fix constant CA delays to support two/three values.
This patch fixes the code generator to correctly create three value
constant delays. It also fixes a bug in the compiler related to the
precalculation of the high-Z delay when only two delays are given.
Previously if was using a pointer not a value comparison to find
the minimum value.

Variable delays should work when one or three values are given.
For the two value case we need to do a comparison at run time and
that will require changing the compiler/run time interface so that
can only go into the V0.10 branch. This patch can be applied to
both development and V0.9. I have added a sorry message and an
assert for this case. I will add the variable two delay case at a
later time. We also do not support mixing constant and variable
delays on a single statement. That is a much bigger change and
can wait until someone asks for it.
(cherry picked from commit b1cb80b32e)
2009-04-05 13:58:22 -07:00
Cary R 682e54841c Add support for getting the size of a real array word.
This patch adds code to get the size of a real array word.
We currently define the size if a real to be 1.
(cherry picked from commit 337c9e7577)
2009-04-03 06:56:54 -07:00
Cary R 7d2734c9cc If a PGAssign is driven by a select then make a driver.
When a PGAssign is driven by (r-value) a bit, part or indexed
select and the strength is not the default (supply). Then
we need to create a driver (BUFZ) to convey the strength
information.
(cherry picked from commit 85e2bf3e55)
2009-04-03 06:54:20 -07:00
Cary R 74df582c73 Show verireal constants with a decimal point.
When displaying a verireal constant value force the display
of the decimal point and trailing zeros. This prevents 2.0,
etc. from being display as "2". which can be confused with
decimal two.
(cherry picked from commit 74ea0ecb4a)
2009-04-03 06:51:32 -07:00
Cary R 10b8055a38 Report an error when trying to take the concatenation of a real value.
This patch adds checks in various places to prevent the user from
taking a concatenation of a real value.
(cherry picked from commit 464310f522)
2009-04-03 06:48:59 -07:00
Cary R 95848eb2f8 Enhance the real selection is invalid error messages.
This patch enhances the error messages emitted when trying to
select part of a real value. It now includes the signal name
so it is easier to debug.
(cherry picked from commit 3517f11c2c)
2009-04-03 06:45:28 -07:00
Cary R efc3bbd29e Report an error when trying to take the select of a real value.
This patch adds checks in various places to prevent the user from
taking a select of a real value (bit, part and indexed selects).
(cherry picked from commit 5852f1eb7a)
2009-04-03 06:45:04 -07:00
Cary R c56f21a20c A right shift is only signed for an ARS.
The signed_flag should only be set when the expression is signed
and an ARS is used a normal RS should never be signed.
(cherry picked from commit caab6cab9d)
2009-04-03 06:41:50 -07:00
Cary R 17210d5423 Add limited support for getting and putting to real array words
This patch adds basic support for getting and putting values to
real array words. This will be finished during the VPI rework.
(cherry picked from commit 1dbc517164)
2009-04-03 06:36:31 -07:00
Cary R b1af2f8535 Arrays can have bit selects of individual words.
The l-value code was not handling the case of a bit select for
an individual array word.
(cherry picked from commit ad39445eed)
2009-03-31 08:05:16 -07:00
Cary R aa28430832 When determining if a signal is an array use array_dimensions_
The previous code looked for more than one array word to determine
if the given signal was an array or not. The problem with this is
that a single word memory was considered a signal. This is fixed
here by looking for an array_dimension to be greater than zero.
(cherry picked from commit 3d449f60a2)
2009-03-31 07:54:27 -07:00
Cary R ceea5d568c Fix problems in rshift code.
This patch fixes the following problems in the right shift code.

The >>> result is only signed if the l-arg is also signed.

The r-arg is always unsigned.

Only sign extend the l-arg when the >>> operator is used.
This relates to an optimization for certain constant shifts.

Removed some obsoleted/outdated code.
(cherry picked from commit d7f272d14c)
2009-03-31 07:40:28 -07:00
Larry Doolittle 710ad582ed Make VHDL code generator skip over virtual pins
Fixes pr2701438
(cherry picked from commit a05ac4b5f4)
2009-03-31 07:34:19 -07:00
Stephen Williams 183137b60c BUFZ devices are strength-aware
When vvp_vector8_t objects come in, pass them out as vec8. The
BUFZ device is used in situations where this acts much like a
simple wire.
2009-03-28 10:08:39 -07:00
Cary R 9c7c719cac Use AC_HELP_STRING instead of AS_HELP_STRING.
The later causes a warning under MinGW. The former appears
to work everywhere.
2009-03-27 06:37:21 -07:00
Cary R 2f3061c158 We are deprecating the $log function in favor of $log10.
When the VAMS math functions were originally built we did a
straight copy of the log() function to $log(). This can
conflict with other Verilog-D definitions of $log. We
need to deprecate this function and remove it before the
next major release.
2009-03-27 06:32:46 -07:00
Cary R af08ff64c7 Add message the the $dumpports* task are not available
These are in the standard and we did not have error messages
for them. This patch make calling these tasks a compiletf
fatal error.
2009-03-27 06:29:44 -07:00
Cary R 036c176e8b Add the $fread() system function.
This patch adds the $fread() system function. Icarus does not
currently allow missing arguments in functions so the following
standard specified functionality is not supported:

  res = $fread(mem, fd,,count);

It also fixes a memory leak in fopen related to the get_filename
refactoring I recently did.
2009-03-26 11:51:22 -07:00
Cary R 327e8d0ec0 Use a single = in configure.in test
The ability to use == is an extension so use the more common =.
2009-03-26 11:45:11 -07:00
Larry Doolittle cfb45e56e2 Address pr2710081, version_tag.h guards
Tested with both bash and dash on Debian, has the desired effect.
No promises for cygwin.
2009-03-26 11:42:42 -07:00
Cary R 809044cbf8 Add guards in CREATE_VERSION script.
This patch adds the same guards that the other two scripts
create for the version_tag.h file.
2009-03-26 11:38:32 -07:00
Larry Doolittle 2a53255445 Add support for virtual reg arrays to tgt-stub
This patch adds support for virtualized register arrays to the
tgt-stub back end.

Based Cary's patch, but with a slightly different style.
Both work fine.
2009-03-26 11:03:42 -07:00
Stephen Williams 4205752bb0 Clean up release builder scripts.
The version.h file is generated by the Makefile, we should
prefill the version_tag.h file.
2009-03-20 14:29:18 -07:00
Cary R d237e35076 Make vvp use inttypes for the 64 bit printing info.
To get the correct print format for a 64 bit value it is much
better to use <inttypes.h> (when available) than building our
own value. This allows MinGW to use the non-standard I64.
2009-03-20 13:58:32 -07:00
Stephen Williams 90f37fe3cb Slightly more portable version of configure test. 2009-03-19 18:31:21 -07:00
Stephen Williams 4be2f61b53 Get ready for the 0.9 first release. 2009-03-19 10:17:12 -07:00
Purdea Andrei f8aa9073ac fixing: %0b format prints nothing for a 0 input
the following example returns ||. This patch fixes it to return |0|.
module t();
wire [3:0] b;
initial
    $monitor("|%0b|", b);
assign b = 0;
endmodule
(cherry picked from commit c9d2400dd0)
2009-03-19 09:11:49 -07:00
Cary R 9ea20d6677 Cleanup lxt and lxt2 EOS data.
This patch cleans up the memory allocated in the lxt and lxt2
$dumpvars routines.
(cherry picked from commit be158dd45f)
2009-03-19 09:05:05 -07:00
Cary R 9fec1f7e45 Handle zero repetition in a synthesized concatenation.
It is valid to have a repetition of zero inside a concatenation
that has other elements with a defined width. This patch adds
this functionality to the synthesize method. It also prints
an error if you try to synthesize a zero width constant.
(cherry picked from commit fa8a3d6c2e)
2009-03-17 16:04:49 -07:00
Stephen Williams c47ea0721c fix the arithmetic of multi-word division.
The Multiword division was not handling some degenerate high
guesses for the intermediate division result guess. The end result
was an assertion. Recover from this case.

(Does the addinb back of bp need to be optimized better?)
(cherry picked from commit 6715426833)
2009-03-17 16:04:28 -07:00
Stephen Williams ef12137931 Pass unsigned-ness of arithmetic operators through operands.
The arithmetic operands are signed only if both operands are signed.
If the expression is unsigned, then the expression as a whole needs
to be processed as unsigned in order to get padding right.
(cherry picked from commit c4a62dee0d)
2009-03-17 16:04:09 -07:00
Larry Doolittle 0e8a12eebf Don't make useless arrays of nexa
When a pin array is virtual, dll_target::signal() doesn't need
to make a corresponding set of stub nexa.

This patch includes new detection of oversized arrays, configurable
with the ARRAY_SIZE_LIMIT flag.  This limit only applies to devirtualized
arrays; virtual arrays are only limited by your architecture's
unsigned int type.

The concept and earlier versions of this patch have been successfully
stress-tested by multiple people.  This one causes no testsuite
regressions on my machine.

Closes: pr2023076
(cherry picked from commit 3a18bda8ee)
2009-03-15 13:54:08 -07:00
Cary R 9473e823ed You must assert a logical not NULL.
This fixes a small problem where an assert was being called
with NULL instead of 0.
(cherry picked from commit ac4cb1bbe9)
2009-03-15 13:53:55 -07:00
Larry Doolittle c75f9db315 Add user interface to pin virtualization
Flag is DISABLE_VIRTUAL_PINS.  Try to give a helpful hint for
how to work around any problems our regression testing might
have missed.
(cherry picked from commit 67381431ed)
2009-03-15 13:53:41 -07:00
Larry Doolittle 1d31a91b4f Remove valgrind errors triggered by virtual pins
NetBus wasn't initializing pin direction.
I hope Link::PASSIVE is correct for busses!
No test suite regressions.
(cherry picked from commit f344515e38)
2009-03-15 13:53:28 -07:00
Larry Doolittle b795d8c1d8 Virtualize Pins until needed
Reduces resource usage when compiling large memories.
Normal usage patterns still create large nexus arrays
in t-dll.cc:dll_target::signal().

This patch is extensively tested; it shouldn't break anything.

The existing debug "optimizer" flag is (ab)used to control
message printing when large (>1000 element) arrays are
devirtualized or nexus-ized.

The new global variable disable_virtual_pins is available
to force allocation of Pin arrays when they are declared,
but no user interface is provided.

See extensive discussion on iverilog-devel, March 4-5 2009,
title "pr2023076: large memories".
(cherry picked from commit 5bc41e1a17)
2009-03-15 13:52:57 -07:00
Larry Doolittle 5ec7731e04 Detect overflows converting to long
The code is ugly, but the results are good.
No regressions in existing testsuite, needs a new entry.
2009-03-13 15:17:51 -07:00
Larry Doolittle bb29e1d588 Drop useless CVS stuff in .txt files
Remove useless, redundant, misleading, and misspelled $Id$ and $Log$
cruft from all .txt files.
(cherry picked from commit 86bf6c447b)
2009-03-13 09:42:17 -07:00
Larry Doolittle 74fd1865cb Minor tweaks ahead of memory virtualization
Limit memory sizes to whatever fits in unsigned; crash if
the conversion from unsigned long to unsigned overflows,
instead of just wrapping.  I don't know what happens on
a 32-bit machine if you ask for an 8 Gig memory, but with
a 64-bit machine and this patch, it crashes with an assert.

Set direction on PartSelect Links before connecting them.

May or may not be considered orthogonal to upcoming
memory virtualization patches.
2009-03-09 14:46:13 -07:00
Larry Doolittle b40b6fb50d Spelling fixes
Mostly comments, but includes user-visible debug messages.
(cherry picked from commit b0c4a87133)
2009-03-09 14:44:07 -07:00
Stephen Williams 19b68f6332 Fix broken definition of is_linked().
(cherry picked from commit fff2598709)
2009-03-09 14:43:18 -07:00
Cary R c96e4da9e4 More constant function not supported warnings.
This patch adds more places that need to warn about constant
functions not being available.
2009-03-05 17:09:43 -08:00
137 changed files with 6344 additions and 5436 deletions

View File

@ -1,7 +1,7 @@
#ifndef __Attrib_H #ifndef __Attrib_H
#define __Attrib_H #define __Attrib_H
/* /*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -30,7 +30,7 @@ class Attrib {
public: public:
Attrib(); Attrib();
~Attrib(); virtual ~Attrib();
const verinum&attribute(perm_string key) const; const verinum&attribute(perm_string key) const;
void attribute(perm_string key, const verinum&value); void attribute(perm_string key, const verinum&value);

View File

@ -1,7 +1,7 @@
#ifndef __LineInfo_H #ifndef __LineInfo_H
#define __LineInfo_H #define __LineInfo_H
/* /*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -36,7 +36,7 @@ using namespace std;
class LineInfo { class LineInfo {
public: public:
LineInfo(); LineInfo();
~LineInfo(); virtual ~LineInfo();
// Get a fully formatted file/lineno // Get a fully formatted file/lineno
string get_fileline() const; string get_fileline() const;

View File

@ -223,15 +223,16 @@ endif
version_tag.h version: version_tag.h version:
@if $(GIT_PRESENT) && test -d $(srcdir)/.git; then \ @if $(GIT_PRESENT) && test -d $(srcdir)/.git; then \
echo "Using git-describe for VERSION_TAG"; \ echo "Using git-describe for VERSION_TAG"; \
tmp=`$(GIT) --git-dir $(srcdir)/.git describe \ tag=`$(GIT) --git-dir $(srcdir)/.git describe`; \
| sed -e 's;\(.*\);#define VERSION_TAG "\1";'`; \ tmp=`printf "#ifndef VERSION_TAG\n#define VERSION_TAG \"$$tag\"\n#endif\n"`; \
echo "$$tmp" | diff - version_tag.h > /dev/null 2>&1 || echo "$$tmp" > version_tag.h || exit 1; \ echo "$$tmp" | diff - version_tag.h > /dev/null 2>&1 || echo "$$tmp" > version_tag.h || exit 1; \
elif test -r $(srcdir)/version_tag.h; then \ elif test -r $(srcdir)/version_tag.h; then \
echo "Using $(srcdir)/version_tag.h for VERSION_TAG"; \ echo "Using $(srcdir)/version_tag.h for VERSION_TAG"; \
diff $(srcdir)/version_tag.h version_tag.h > /dev/null 2>&1 || cp $(srcdir)/version_tag.h version_tag.h; \ diff $(srcdir)/version_tag.h version_tag.h > /dev/null 2>&1 || cp $(srcdir)/version_tag.h version_tag.h; \
else \ else \
echo "Using empty VERSION_TAG"; \ echo "Using empty VERSION_TAG"; \
echo '#define VERSION_TAG ""' > version_tag.h; \ tmp=`printf "#ifndef VERSION_TAG\n#define VERSION_TAG \"\"\n#endif\n"`; \
echo "$$tmp" | diff - version_tag.h > /dev/null 2>&1 || echo "$$tmp" > version_tag.h || exit 1; \
fi fi
ifeq (@MINGW32@,yes) ifeq (@MINGW32@,yes)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -29,7 +29,10 @@ Module::Module(perm_string n)
: PScope(n) : PScope(n)
{ {
library_flag = false; library_flag = false;
is_cell = false;
uc_drive = UCD_NONE;
default_nettype = NetNet::NONE; default_nettype = NetNet::NONE;
timescale_warn_done = false;
} }
Module::~Module() Module::~Module()

View File

@ -1,7 +1,7 @@
#ifndef __Module_H #ifndef __Module_H
#define __Module_H #define __Module_H
/* /*
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -74,6 +74,11 @@ class Module : public PScope, public LineInfo {
other effect. */ other effect. */
bool library_flag; bool library_flag;
bool is_cell;
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
UCDriveType uc_drive;
NetNet::Type default_nettype; NetNet::Type default_nettype;
/* specparams are simpler then other params, in that they have /* specparams are simpler then other params, in that they have
@ -105,6 +110,8 @@ class Module : public PScope, public LineInfo {
/* These are the timescale for this module. The default is /* These are the timescale for this module. The default is
set by the `timescale directive. */ set by the `timescale directive. */
int time_unit, time_precision; int time_unit, time_precision;
bool time_from_timescale;
bool timescale_warn_done;
/* Task definitions within this module */ /* Task definitions within this module */
map<perm_string,PTask*> tasks; map<perm_string,PTask*> tasks;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -26,6 +26,11 @@
# include "verinum.h" # include "verinum.h"
# include "netmisc.h" # include "netmisc.h"
bool dly_used_no_timescale = false;
bool dly_used_timescale = false;
bool display_ts_dly_warning = true;
PDelays::PDelays() PDelays::PDelays()
{ {
delete_flag_ = true; delete_flag_ = true;
@ -60,12 +65,28 @@ void PDelays::set_delays(const svector<PExpr*>*del, bool df)
delete_flag_ = df; delete_flag_ = df;
} }
static NetExpr*calculate_val(Design*des, NetScope*scope, const PExpr*expr) static NetExpr*calculate_val(Design*des, NetScope*scope, PExpr*expr)
{ {
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE;
bool tmp_flag = false;
expr->test_width(des, scope, 0, 0, tmp_type, tmp_flag);
NetExpr*dex = expr->elaborate_expr(des, scope, -1, false); NetExpr*dex = expr->elaborate_expr(des, scope, -1, false);
eval_expr(dex); eval_expr(dex);
/* Print a warning if we find default and `timescale based
* delays in the design, since this is likely an error. */
if (scope->time_from_timescale()) dly_used_timescale = true;
else dly_used_no_timescale = true;
if (display_ts_dly_warning &&
dly_used_no_timescale && dly_used_timescale) {
cerr << "warning: Found both default and "
"`timescale based delays. Use" << endl;
cerr << " -Wtimescale to find the "
"module(s) with no `timescale." << endl;
display_ts_dly_warning = false;
}
/* If the delay expression is a real constant or vector /* If the delay expression is a real constant or vector
constant, then evaluate it, scale it to the local time constant, then evaluate it, scale it to the local time
units, and return an adjusted value. */ units, and return an adjusted value. */
@ -119,6 +140,20 @@ static NetExpr* make_delay_nets(Design*des, NetScope*scope, NetExpr*expr)
return expr; return expr;
} }
static NetExpr* calc_decay_time(NetExpr *rise, NetExpr *fall)
{
NetEConst *c_rise = dynamic_cast<NetEConst*>(rise);
NetEConst *c_fall = dynamic_cast<NetEConst*>(fall);
if (c_rise && c_fall) {
if (c_rise->value() < c_fall->value()) return rise;
else return fall;
}
cerr << fall->get_fileline() << ": sorry: can not calculate the "
<< "decay time from " << *rise << " and " << *fall << endl;
return 0;
}
void PDelays::eval_delays(Design*des, NetScope*scope, void PDelays::eval_delays(Design*des, NetScope*scope,
NetExpr*&rise_time, NetExpr*&rise_time,
NetExpr*&fall_time, NetExpr*&fall_time,
@ -140,14 +175,14 @@ void PDelays::eval_delays(Design*des, NetScope*scope,
if (delay_[2]) { if (delay_[2]) {
decay_time = calculate_val(des, scope, delay_[2]); decay_time = calculate_val(des, scope, delay_[2]);
if (as_nets_flag) if (as_nets_flag)
decay_time = make_delay_nets(des, scope, decay_time); decay_time = make_delay_nets(des, scope,
decay_time);
} else { } else {
if (rise_time < fall_time) // If this is zero then we need to do the min()
decay_time = rise_time; // at run time.
else decay_time = calc_decay_time(rise_time, fall_time);
decay_time = fall_time;
} }
} else { } else {
assert(delay_[2] == 0); assert(delay_[2] == 0);

View File

@ -339,6 +339,12 @@ class PEIdent : public PExpr {
NetScope*found, NetScope*found,
const NetExpr*par_msb, const NetExpr*par_msb,
const NetExpr*par_lsb) const; const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_param_idx_do_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found,
const NetExpr*par_msb,
const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_net(Design*des, NetExpr*elaborate_expr_net(Design*des,
NetScope*scope, NetScope*scope,
NetNet*net, NetNet*net,

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 Stephen Williams (steve@icarus.com) * Copyright (c) 2006,2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -55,6 +55,7 @@ void PGenerate::probe_for_direct_nesting_(void)
if (localparams.size() > 0) return; if (localparams.size() > 0) return;
if (events.size() > 0) return; if (events.size() > 0) return;
if (wires.size() > 0) return; if (wires.size() > 0) return;
if (genvars.size() > 0) return;
if (behaviors.size() > 0) return; if (behaviors.size() > 0) return;
if (analog_behaviors.size() > 0) return; if (analog_behaviors.size() > 0) return;

View File

@ -1,7 +1,7 @@
#ifndef __PGenerate_H #ifndef __PGenerate_H
#define __PGenerate_H #define __PGenerate_H
/* /*
* Copyright (c) 2006-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2006-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -87,6 +87,9 @@ class PGenerate : public LineInfo, public LexicalScope {
map<perm_string,PTask*> tasks; map<perm_string,PTask*> tasks;
map<perm_string,PFunction*>funcs; map<perm_string,PFunction*>funcs;
// genvars declared within this scheme.
map<perm_string,LineInfo*> genvars;
// Generate schemes can contain further generate schemes. // Generate schemes can contain further generate schemes.
list<PGenerate*> generate_schemes; list<PGenerate*> generate_schemes;
PGenerate*parent; PGenerate*parent;
@ -109,8 +112,8 @@ class PGenerate : public LineInfo, public LexicalScope {
bool generate_scope_case_(Design*des, NetScope*container); bool generate_scope_case_(Design*des, NetScope*container);
bool generate_scope_nblock_(Design*des, NetScope*container); bool generate_scope_nblock_(Design*des, NetScope*container);
// Call probe during elaborate_scope to calulate the // Call probe during elaborate_scope to calculate the
// directed_nested_ flag. It is OK to store the direct_nested_ // direct_nested_ flag. It is OK to store the direct_nested_
// information here because "direct nested" is a property of // information here because "direct nested" is a property of
// the lexical generate code. // the lexical generate code.
void probe_for_direct_nesting_(void); void probe_for_direct_nesting_(void);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -29,8 +29,8 @@ PWire::PWire(perm_string n,
: name_(n), type_(t), port_type_(pt), data_type_(dt), : name_(n), type_(t), port_type_(pt), data_type_(dt),
signed_(false), isint_(false), signed_(false), isint_(false),
port_msb_(0), port_lsb_(0), port_set_(false), port_msb_(0), port_lsb_(0), port_set_(false),
net_msb_(0), net_lsb_(0), net_set_(false), error_cnt_(0), net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false),
lidx_(0), ridx_(0), discipline_(0) error_cnt_(0), lidx_(0), ridx_(0), discipline_(0)
{ {
if (t == NetNet::INTEGER) { if (t == NetNet::INTEGER) {
type_ = NetNet::REG; type_ = NetNet::REG;
@ -135,7 +135,12 @@ bool PWire::get_isint() const
return isint_; return isint_;
} }
void PWire::set_range(PExpr*m, PExpr*l, PWSRType type) bool PWire::get_scalar() const
{
return is_scalar_;
}
void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar)
{ {
switch (type) { switch (type) {
case SR_PORT: case SR_PORT:
@ -147,6 +152,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
port_msb_ = m; port_msb_ = m;
port_lsb_ = l; port_lsb_ = l;
port_set_ = true; port_set_ = true;
is_scalar_ = is_scalar;
} }
return; return;
@ -159,6 +165,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
net_msb_ = m; net_msb_ = m;
net_lsb_ = l; net_lsb_ = l;
net_set_ = true; net_set_ = true;
is_scalar_ = is_scalar;
} }
return; return;
@ -181,6 +188,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
net_msb_ = m; net_msb_ = m;
net_lsb_ = l; net_lsb_ = l;
net_set_ = true; net_set_ = true;
is_scalar_ = is_scalar;
} }
return; return;
} }

View File

@ -1,7 +1,7 @@
#ifndef __PWire_H #ifndef __PWire_H
#define __PWire_H #define __PWire_H
/* /*
* Copyright (c) 1998-2007 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -70,11 +70,12 @@ class PWire : public LineInfo {
void set_signed(bool flag); void set_signed(bool flag);
bool get_signed() const; bool get_signed() const;
bool get_isint() const; bool get_isint() const;
bool get_scalar() const;
bool set_data_type(ivl_variable_type_t dt); bool set_data_type(ivl_variable_type_t dt);
ivl_variable_type_t get_data_type() const; ivl_variable_type_t get_data_type() const;
void set_range(PExpr*msb, PExpr*lsb, PWSRType type); void set_range(PExpr*msb, PExpr*lsb, PWSRType type, bool is_scalar);
void set_memory_idx(PExpr*ldx, PExpr*rdx); void set_memory_idx(PExpr*ldx, PExpr*rdx);
@ -104,6 +105,7 @@ class PWire : public LineInfo {
PExpr*net_msb_; PExpr*net_msb_;
PExpr*net_lsb_; PExpr*net_lsb_;
bool net_set_; bool net_set_;
bool is_scalar_;
unsigned error_cnt_; unsigned error_cnt_;
// If this wire is actually a memory, these indices will give // If this wire is actually a memory, these indices will give

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002-2004 Stephen Williams (steve@icarus.com) * Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -25,6 +25,11 @@
# include <string.h> # include <string.h>
# include <assert.h> # include <assert.h>
#ifdef CHECK_WITH_VALGRIND
static char **string_pool = NULL;
static unsigned string_pool_count = 0;
#endif
StringHeap::StringHeap() StringHeap::StringHeap()
{ {
cell_base_ = 0; cell_base_ = 0;
@ -46,6 +51,12 @@ const char* StringHeap::add(const char*text)
unsigned rem = HEAPCELL - cell_ptr_; unsigned rem = HEAPCELL - cell_ptr_;
if (rem < (len+1)) { if (rem < (len+1)) {
cell_base_ = (char*)malloc(HEAPCELL); cell_base_ = (char*)malloc(HEAPCELL);
#ifdef CHECK_WITH_VALGRIND
string_pool_count += 1;
string_pool = (char **) realloc(string_pool,
string_pool_count*sizeof(char **));
string_pool[string_pool_count-1] = cell_base_;
#endif
cell_ptr_ = 0; cell_ptr_ = 0;
cell_count_ += 1; cell_count_ += 1;
assert(cell_base_ != 0); assert(cell_base_ != 0);
@ -80,6 +91,22 @@ StringHeapLex::~StringHeapLex()
{ {
} }
void StringHeapLex::cleanup()
{
#ifdef CHECK_WITH_VALGRIND
for (unsigned idx = 0 ; idx < string_pool_count ; idx += 1) {
free(string_pool[idx]);
}
free(string_pool);
string_pool = NULL;
string_pool_count = 0;
for (unsigned idx = 0 ; idx < HASH_SIZE ; idx += 1) {
hash_table_[idx] = 0;
}
#endif
}
unsigned StringHeapLex::add_hit_count() const unsigned StringHeapLex::add_hit_count() const
{ {
return hit_count_; return hit_count_;
@ -175,4 +202,3 @@ bool operator < (perm_string a, perm_string b)
return false; return false;
} }

View File

@ -1,7 +1,7 @@
#ifndef __StringHeap_H #ifndef __StringHeap_H
#define __StringHeap_H #define __StringHeap_H
/* /*
* Copyright (c) 2002-2004 Stephen Williams (steve@icarus.com) * Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -104,6 +104,7 @@ class StringHeapLex : private StringHeap {
unsigned add_count() const; unsigned add_count() const;
unsigned add_hit_count() const; unsigned add_hit_count() const;
void cleanup();
private: private:
enum { HASH_SIZE = 4096 }; enum { HASH_SIZE = 4096 };

View File

@ -2,7 +2,6 @@
CADENCE PLI1 MODULES CADENCE PLI1 MODULES
Copyright 2003 Stephen Williams Copyright 2003 Stephen Williams
$Id: cadpli.txt,v 1.2 2003/02/17 00:01:25 steve Exp $
With the cadpli module, Icarus Verilog is able to load PLI1 With the cadpli module, Icarus Verilog is able to load PLI1
applications that were compiled and linked to be dynamic loaded by applications that were compiled and linked to be dynamic loaded by
@ -34,15 +33,3 @@ the +loadpli1= argument to Verilog-XL.
The integration from this point is seamless. The PLI application The integration from this point is seamless. The PLI application
hardly knows that it is being invoked by Icarus Verilog instead of hardly knows that it is being invoked by Icarus Verilog instead of
Verilog-XL, so operates as it would otherwise. Verilog-XL, so operates as it would otherwise.
$Log: cadpli.txt,v $
Revision 1.2 2003/02/17 00:01:25 steve
Use a variant of ivl_dlfcn to do dynamic loading
from within the cadpli module.
Change the +cadpli flag to -cadpli, to keep the
plusargs namespace clear.
Revision 1.1 2003/02/16 02:44:47 steve
Add the cadpli HOWTO.

View File

@ -1,7 +1,7 @@
#ifndef __compiler_H #ifndef __compiler_H
#define __compiler_H #define __compiler_H
/* /*
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -36,6 +36,12 @@
*/ */
extern unsigned integer_width; extern unsigned integer_width;
/*
* This is the maximum number of recursive module loops allowed within
* a generate block.
*/
extern unsigned recursive_mod_limit;
/* The TIME_WIDTH is the width of time variables. */ /* The TIME_WIDTH is the width of time variables. */
#ifndef TIME_WIDTH #ifndef TIME_WIDTH
# define TIME_WIDTH 64 # define TIME_WIDTH 64
@ -76,9 +82,17 @@ extern bool warn_timescale;
/* Warn about legal but questionable module port bindings. */ /* Warn about legal but questionable module port bindings. */
extern bool warn_portbinding; extern bool warn_portbinding;
/* Warn about constant out of bound selects. */
extern bool warn_ob_select;
/* Warn about structures that may have infinite loops. */ /* Warn about structures that may have infinite loops. */
extern bool warn_inf_loop; extern bool warn_inf_loop;
/* Warn about always @* statements where a part or word select causes
sensitivity to an entire vector or array. */
extern bool warn_sens_entire_vec;
extern bool warn_sens_entire_arr;
/* This is true if verbose output is requested. */ /* This is true if verbose output is requested. */
extern bool verbose_flag; extern bool verbose_flag;
@ -89,6 +103,12 @@ extern bool debug_elab_pexpr;
extern bool debug_synth2; extern bool debug_synth2;
extern bool debug_optimizer; extern bool debug_optimizer;
/* Possibly temporary flag to control virtualization of pin arrays */
extern bool disable_virtual_pins;
/* Limit to size of devirtualized arrays */
extern unsigned long array_size_limit;
/* Path to a directory useful for finding subcomponents. */ /* Path to a directory useful for finding subcomponents. */
extern const char*basedir; extern const char*basedir;
@ -101,9 +121,10 @@ extern int build_library_index(const char*path, bool key_case_sensitive);
specific language features. */ specific language features. */
enum generation_t { enum generation_t {
GN_VER1995 = 1, GN_VER1995 = 1,
GN_VER2001 = 2, GN_VER2001_NOCONFIG = 2,
GN_VER2005 = 3, GN_VER2001 = 3,
GN_DEFAULT = 3 GN_VER2005 = 4,
GN_DEFAULT = 4
}; };
extern generation_t generation_flag; extern generation_t generation_flag;
@ -189,5 +210,6 @@ struct sfunc_return_type {
extern const struct sfunc_return_type* lookup_sys_func(const char*name); extern const struct sfunc_return_type* lookup_sys_func(const char*name);
extern int load_sys_func_table(const char*path); extern int load_sys_func_table(const char*path);
extern void cleanup_sys_func_table();
#endif #endif

965
config.guess vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
#ifndef __config_H /* -*- c++ -*- */ #ifndef __config_H /* -*- c++ -*- */
#define __config_H #define __config_H
/* /*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -50,4 +50,10 @@
# include <inttypes.h> # include <inttypes.h>
#endif #endif
/*
* Define this if you want to compile vvp with memory freeing and
* special valgrind hooks for the memory pools.
*/
# undef CHECK_WITH_VALGRIND
#endif /* __config_H */ #endif /* __config_H */

415
config.sub vendored
View File

@ -1,9 +1,10 @@
#! /bin/sh #! /bin/sh
# Configuration validation subroutine script. # Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002 Free Software Foundation, Inc. # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
# Free Software Foundation, Inc.
timestamp='2002-07-03' timestamp='2009-04-17'
# This file is (in principle) common to ALL GNU software. # This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software # The presence of a machine in this file suggests that SOME GNU software
@ -21,14 +22,15 @@ timestamp='2002-07-03'
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
# Boston, MA 02111-1307, USA. # 02110-1301, USA.
#
# As a special exception to the GNU General Public License, if you # As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a # distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under # configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program. # the same distribution terms that you use for the rest of that program.
# Please send patches to <config-patches@gnu.org>. Submit a context # Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry. # diff and a properly formatted ChangeLog entry.
# #
@ -70,8 +72,8 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\ version="\
GNU config.sub ($timestamp) GNU config.sub ($timestamp)
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
Free Software Foundation, Inc. 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -83,11 +85,11 @@ Try \`$me --help' for more information."
while test $# -gt 0 ; do while test $# -gt 0 ; do
case $1 in case $1 in
--time-stamp | --time* | -t ) --time-stamp | --time* | -t )
echo "$timestamp" ; exit 0 ;; echo "$timestamp" ; exit ;;
--version | -v ) --version | -v )
echo "$version" ; exit 0 ;; echo "$version" ; exit ;;
--help | --h* | -h ) --help | --h* | -h )
echo "$usage"; exit 0 ;; echo "$usage"; exit ;;
-- ) # Stop option processing -- ) # Stop option processing
shift; break ;; shift; break ;;
- ) # Use stdin as input. - ) # Use stdin as input.
@ -99,7 +101,7 @@ while test $# -gt 0 ; do
*local*) *local*)
# First pass through any local machine types. # First pass through any local machine types.
echo $1 echo $1
exit 0;; exit ;;
* ) * )
break ;; break ;;
@ -118,7 +120,10 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations. # Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in case $maybe_os in
nto-qnx* | linux-gnu* | freebsd*-gnu* | storm-chaos* | os2-emx* | windows32-* | rtmk-nova*) nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;; ;;
@ -144,7 +149,7 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple | -axis) -apple | -axis | -knuth | -cray)
os= os=
basic_machine=$1 basic_machine=$1
;; ;;
@ -169,6 +174,10 @@ case $os in
-hiux*) -hiux*)
os=-hiuxwe2 os=-hiuxwe2
;; ;;
-sco6)
os=-sco5v6
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco5) -sco5)
os=-sco3.2v5 os=-sco3.2v5
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@ -185,6 +194,10 @@ case $os in
# Don't forget version if it is 3.2v4 or newer. # Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-sco5v6*)
# Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco*) -sco*)
os=-sco3.2v2 os=-sco3.2v2
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@ -228,40 +241,57 @@ case $basic_machine in
| a29k \ | a29k \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | am33_2.0 \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
| bfin \
| c4x | clipper \ | c4x | clipper \
| d10v | d30v | dlx | dsp16xx \ | d10v | d30v | dlx | dsp16xx \
| fr30 | frv \ | fido | fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \ | i370 | i860 | i960 | ia64 \
| ip2k \ | ip2k | iq2000 \
| m32r | m68000 | m68k | m88k | mcore \ | lm32 \
| m32c | m32r | m32rle | m68000 | m68k | m88k \
| maxq | mb | microblaze | mcore | mep | metag \
| mips | mipsbe | mipseb | mipsel | mipsle \ | mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \ | mips16 \
| mips64 | mips64el \ | mips64 | mips64el \
| mips64octeon | mips64octeonel \
| mips64orion | mips64orionel \ | mips64orion | mips64orionel \
| mips64r5900 | mips64r5900el \
| mips64vr | mips64vrel \
| mips64vr4100 | mips64vr4100el \ | mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \ | mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \ | mips64vr5000 | mips64vr5000el \
| mips64vr5900 | mips64vr5900el \
| mipsisa32 | mipsisa32el \ | mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa64 | mipsisa64el \ | mipsisa64 | mipsisa64el \
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \ | mipstx39 | mipstx39el \
| mn10200 | mn10300 \ | mn10200 | mn10300 \
| moxie \
| mt \
| msp430 \
| nios | nios2 \
| ns16k | ns32k \ | ns16k | ns32k \
| openrisc | or32 \ | or32 \
| pdp10 | pdp11 | pj | pjl \ | pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \ | pyramid \
| sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | score \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \ | sh64 | sh64le \
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| strongarm \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
| tahoe | thumb | tic80 | tron \ | spu | strongarm \
| tahoe | thumb | tic4x | tic80 | tron \
| v850 | v850e \ | v850 | v850e \
| we32k \ | we32k \
| x86 | xscale | xstormy16 | xtensa \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
| z8k) | z8k | z80)
basic_machine=$basic_machine-unknown basic_machine=$basic_machine-unknown
;; ;;
m6811 | m68hc11 | m6812 | m68hc12) m6811 | m68hc11 | m6812 | m68hc12)
@ -271,6 +301,9 @@ case $basic_machine in
;; ;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;; ;;
ms1)
basic_machine=mt-unknown
;;
# We use `pc' rather than `unknown' # We use `pc' rather than `unknown'
# because (1) that's what they normally are, and # because (1) that's what they normally are, and
@ -290,48 +323,67 @@ case $basic_machine in
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* \ | avr-* | avr32-* \
| bs2000-* \ | bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c54x-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
| clipper-* | cydra-* \ | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \ | d10v-* | d30v-* | dlx-* \
| elxsi-* \ | elxsi-* \
| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \ | h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| i*86-* | i860-* | i960-* | ia64-* \ | i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* \ | ip2k-* | iq2000-* \
| m32r-* \ | lm32-* \
| m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | mcore-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \ | mips16-* \
| mips64-* | mips64el-* \ | mips64-* | mips64el-* \
| mips64octeon-* | mips64octeonel-* \
| mips64orion-* | mips64orionel-* \ | mips64orion-* | mips64orionel-* \
| mips64r5900-* | mips64r5900el-* \
| mips64vr-* | mips64vrel-* \
| mips64vr4100-* | mips64vr4100el-* \ | mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \ | mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \ | mips64vr5000-* | mips64vr5000el-* \
| mips64vr5900-* | mips64vr5900el-* \
| mipsisa32-* | mipsisa32el-* \ | mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa64-* | mipsisa64el-* \ | mipsisa64-* | mipsisa64el-* \
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \
| mipstx39 | mipstx39el \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
| mt-* \
| msp430-* \
| nios-* | nios2-* \
| none-* | np1-* | ns16k-* | ns32k-* \ | none-* | np1-* | ns16k-* | ns32k-* \
| orion-* \ | orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \ | pyramid-* \
| romp-* | rs6000-* \ | romp-* | rs6000-* \
| sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | sparclite-* \
| tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
| tron-* \
| v850-* | v850e-* | vax-* \ | v850-* | v850e-* | vax-* \
| we32k-* \ | we32k-* \
| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
| xtensa-* \ | xstormy16-* | xtensa*-* \
| ymp-* \ | ymp-* \
| z8k-*) | z8k-* | z80-*)
;;
# Recognize the basic CPU types without company name, with glob match.
xtensa*)
basic_machine=$basic_machine-unknown
;; ;;
# Recognize the various machine names and aliases which stand # Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS. # for a CPU type and a company and sometimes even an OS.
@ -349,6 +401,9 @@ case $basic_machine in
basic_machine=a29k-amd basic_machine=a29k-amd
os=-udi os=-udi
;; ;;
abacus)
basic_machine=abacus-unknown
;;
adobe68k) adobe68k)
basic_machine=m68010-adobe basic_machine=m68010-adobe
os=-scout os=-scout
@ -363,6 +418,12 @@ case $basic_machine in
basic_machine=a29k-none basic_machine=a29k-none
os=-bsd os=-bsd
;; ;;
amd64)
basic_machine=x86_64-pc
;;
amd64-*)
basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
amdahl) amdahl)
basic_machine=580-amdahl basic_machine=580-amdahl
os=-sysv os=-sysv
@ -386,6 +447,10 @@ case $basic_machine in
basic_machine=m68k-apollo basic_machine=m68k-apollo
os=-bsd os=-bsd
;; ;;
aros)
basic_machine=i386-pc
os=-aros
;;
aux) aux)
basic_machine=m68k-apple basic_machine=m68k-apple
os=-aux os=-aux
@ -394,10 +459,22 @@ case $basic_machine in
basic_machine=ns32k-sequent basic_machine=ns32k-sequent
os=-dynix os=-dynix
;; ;;
blackfin)
basic_machine=bfin-unknown
os=-linux
;;
blackfin-*)
basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
c90) c90)
basic_machine=c90-cray basic_machine=c90-cray
os=-unicos os=-unicos
;; ;;
cegcc)
basic_machine=arm-unknown
os=-cegcc
;;
convex-c1) convex-c1)
basic_machine=c1-convex basic_machine=c1-convex
os=-bsd os=-bsd
@ -422,12 +499,27 @@ case $basic_machine in
basic_machine=j90-cray basic_machine=j90-cray
os=-unicos os=-unicos
;; ;;
craynv)
basic_machine=craynv-cray
os=-unicosmp
;;
cr16)
basic_machine=cr16-unknown
os=-elf
;;
crds | unos) crds | unos)
basic_machine=m68k-crds basic_machine=m68k-crds
;; ;;
crisv32 | crisv32-* | etraxfs*)
basic_machine=crisv32-axis
;;
cris | cris-* | etrax*) cris | cris-* | etrax*)
basic_machine=cris-axis basic_machine=cris-axis
;; ;;
crx)
basic_machine=crx-unknown
os=-elf
;;
da30 | da30-*) da30 | da30-*)
basic_machine=m68k-da30 basic_machine=m68k-da30
;; ;;
@ -450,6 +542,14 @@ case $basic_machine in
basic_machine=m88k-motorola basic_machine=m88k-motorola
os=-sysv3 os=-sysv3
;; ;;
dicos)
basic_machine=i686-pc
os=-dicos
;;
djgpp)
basic_machine=i586-pc
os=-msdosdjgpp
;;
dpx20 | dpx20-*) dpx20 | dpx20-*)
basic_machine=rs6000-bull basic_machine=rs6000-bull
os=-bosx os=-bosx
@ -600,6 +700,14 @@ case $basic_machine in
basic_machine=m68k-isi basic_machine=m68k-isi
os=-sysv os=-sysv
;; ;;
m68knommu)
basic_machine=m68k-unknown
os=-linux
;;
m68knommu-*)
basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
m88k-omron*) m88k-omron*)
basic_machine=m88k-omron basic_machine=m88k-omron
;; ;;
@ -615,6 +723,10 @@ case $basic_machine in
basic_machine=i386-pc basic_machine=i386-pc
os=-mingw32 os=-mingw32
;; ;;
mingw32ce)
basic_machine=arm-unknown
os=-mingw32ce
;;
miniframe) miniframe)
basic_machine=m68000-convergent basic_machine=m68000-convergent
;; ;;
@ -628,10 +740,6 @@ case $basic_machine in
mips3*) mips3*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
;; ;;
mmix*)
basic_machine=mmix-knuth
os=-mmixware
;;
monitor) monitor)
basic_machine=m68k-rom68k basic_machine=m68k-rom68k
os=-coff os=-coff
@ -644,6 +752,9 @@ case $basic_machine in
basic_machine=i386-pc basic_machine=i386-pc
os=-msdos os=-msdos
;; ;;
ms1-*)
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
mvs) mvs)
basic_machine=i370-ibm basic_machine=i370-ibm
os=-mvs os=-mvs
@ -719,9 +830,12 @@ case $basic_machine in
basic_machine=hppa1.1-oki basic_machine=hppa1.1-oki
os=-proelf os=-proelf
;; ;;
or32 | or32-*) openrisc | openrisc-*)
basic_machine=or32-unknown basic_machine=or32-unknown
os=-coff ;;
os400)
basic_machine=powerpc-ibm
os=-os400
;; ;;
OSE68000 | ose68000) OSE68000 | ose68000)
basic_machine=m68000-ericsson basic_machine=m68000-ericsson
@ -739,55 +853,75 @@ case $basic_machine in
basic_machine=i860-intel basic_machine=i860-intel
os=-osf os=-osf
;; ;;
parisc)
basic_machine=hppa-unknown
os=-linux
;;
parisc-*)
basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
pbd) pbd)
basic_machine=sparc-tti basic_machine=sparc-tti
;; ;;
pbb) pbb)
basic_machine=m68k-tti basic_machine=m68k-tti
;; ;;
pc532 | pc532-*) pc532 | pc532-*)
basic_machine=ns32k-pc532 basic_machine=ns32k-pc532
;; ;;
pc98)
basic_machine=i386-pc
;;
pc98-*)
basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentium | p5 | k5 | k6 | nexgen | viac3) pentium | p5 | k5 | k6 | nexgen | viac3)
basic_machine=i586-pc basic_machine=i586-pc
;; ;;
pentiumpro | p6 | 6x86 | athlon) pentiumpro | p6 | 6x86 | athlon | athlon_*)
basic_machine=i686-pc basic_machine=i686-pc
;; ;;
pentiumii | pentium2) pentiumii | pentium2 | pentiumiii | pentium3)
basic_machine=i686-pc basic_machine=i686-pc
;; ;;
pentium4)
basic_machine=i786-pc
;;
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pentiumpro-* | p6-* | 6x86-* | athlon-*) pentiumpro-* | p6-* | 6x86-* | athlon-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pentiumii-* | pentium2-*) pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pentium4-*)
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pn) pn)
basic_machine=pn-gould basic_machine=pn-gould
;; ;;
power) basic_machine=power-ibm power) basic_machine=power-ibm
;; ;;
ppc) basic_machine=powerpc-unknown ppc) basic_machine=powerpc-unknown
;; ;;
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppcle | powerpclittle | ppc-le | powerpc-little) ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown basic_machine=powerpcle-unknown
;; ;;
ppcle-* | powerpclittle-*) ppcle-* | powerpclittle-*)
basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppc64) basic_machine=powerpc64-unknown ppc64) basic_machine=powerpc64-unknown
;; ;;
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppc64le | powerpc64little | ppc64-le | powerpc64-little) ppc64le | powerpc64little | ppc64-le | powerpc64-little)
basic_machine=powerpc64le-unknown basic_machine=powerpc64le-unknown
;; ;;
ppc64le-* | powerpc64little-*) ppc64le-* | powerpc64little-*)
basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
@ -798,6 +932,10 @@ case $basic_machine in
basic_machine=i586-unknown basic_machine=i586-unknown
os=-pw32 os=-pw32
;; ;;
rdos)
basic_machine=i386-pc
os=-rdos
;;
rom68k) rom68k)
basic_machine=m68k-rom68k basic_machine=m68k-rom68k
os=-coff os=-coff
@ -818,6 +956,20 @@ case $basic_machine in
basic_machine=a29k-amd basic_machine=a29k-amd
os=-udi os=-udi
;; ;;
sb1)
basic_machine=mipsisa64sb1-unknown
;;
sb1el)
basic_machine=mipsisa64sb1el-unknown
;;
sde)
basic_machine=mipsisa32-sde
os=-elf
;;
sei)
basic_machine=mips-sei
os=-seiux
;;
sequent) sequent)
basic_machine=i386-sequent basic_machine=i386-sequent
;; ;;
@ -825,6 +977,12 @@ case $basic_machine in
basic_machine=sh-hitachi basic_machine=sh-hitachi
os=-hms os=-hms
;; ;;
sh5el)
basic_machine=sh5le-unknown
;;
sh64)
basic_machine=sh64-unknown
;;
sparclite-wrs | simso-wrs) sparclite-wrs | simso-wrs)
basic_machine=sparclite-wrs basic_machine=sparclite-wrs
os=-vxworks os=-vxworks
@ -883,7 +1041,7 @@ case $basic_machine in
sun386 | sun386i | roadrunner) sun386 | sun386i | roadrunner)
basic_machine=i386-sun basic_machine=i386-sun
;; ;;
sv1) sv1)
basic_machine=sv1-cray basic_machine=sv1-cray
os=-unicos os=-unicos
;; ;;
@ -891,10 +1049,6 @@ case $basic_machine in
basic_machine=i386-sequent basic_machine=i386-sequent
os=-dynix os=-dynix
;; ;;
t3d)
basic_machine=alpha-cray
os=-unicos
;;
t3e) t3e)
basic_machine=alphaev5-cray basic_machine=alphaev5-cray
os=-unicos os=-unicos
@ -907,6 +1061,18 @@ case $basic_machine in
basic_machine=tic54x-unknown basic_machine=tic54x-unknown
os=-coff os=-coff
;; ;;
tic55x | c55x*)
basic_machine=tic55x-unknown
os=-coff
;;
tic6x | c6x*)
basic_machine=tic6x-unknown
os=-coff
;;
tile*)
basic_machine=tile-unknown
os=-linux-gnu
;;
tx39) tx39)
basic_machine=mipstx39-unknown basic_machine=mipstx39-unknown
;; ;;
@ -920,6 +1086,10 @@ case $basic_machine in
tower | tower-32) tower | tower-32)
basic_machine=m68k-ncr basic_machine=m68k-ncr
;; ;;
tpf)
basic_machine=s390x-ibm
os=-tpf
;;
udi29k) udi29k)
basic_machine=a29k-amd basic_machine=a29k-amd
os=-udi os=-udi
@ -941,8 +1111,8 @@ case $basic_machine in
os=-vms os=-vms
;; ;;
vpp*|vx|vx-*) vpp*|vx|vx-*)
basic_machine=f301-fujitsu basic_machine=f301-fujitsu
;; ;;
vxworks960) vxworks960)
basic_machine=i960-wrs basic_machine=i960-wrs
os=-vxworks os=-vxworks
@ -963,11 +1133,11 @@ case $basic_machine in
basic_machine=hppa1.1-winbond basic_machine=hppa1.1-winbond
os=-proelf os=-proelf
;; ;;
windows32) xbox)
basic_machine=i386-pc basic_machine=i686-pc
os=-windows32-msvcrt os=-mingw32
;; ;;
xps | xps100) xps | xps100)
basic_machine=xps100-honeywell basic_machine=xps100-honeywell
;; ;;
ymp) ymp)
@ -978,6 +1148,10 @@ case $basic_machine in
basic_machine=z8k-unknown basic_machine=z8k-unknown
os=-sim os=-sim
;; ;;
z80-*-coff)
basic_machine=z80-unknown
os=-sim
;;
none) none)
basic_machine=none-none basic_machine=none-none
os=-none os=-none
@ -997,6 +1171,9 @@ case $basic_machine in
romp) romp)
basic_machine=romp-ibm basic_machine=romp-ibm
;; ;;
mmix)
basic_machine=mmix-knuth
;;
rs6000) rs6000)
basic_machine=rs6000-ibm basic_machine=rs6000-ibm
;; ;;
@ -1013,16 +1190,13 @@ case $basic_machine in
we32k) we32k)
basic_machine=we32k-att basic_machine=we32k-att
;; ;;
sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele) sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown basic_machine=sh-unknown
;; ;;
sh64) sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
basic_machine=sh64-unknown
;;
sparc | sparcv9 | sparcv9b)
basic_machine=sparc-sun basic_machine=sparc-sun
;; ;;
cydra) cydra)
basic_machine=cydra-cydrome basic_machine=cydra-cydrome
;; ;;
orion) orion)
@ -1037,10 +1211,6 @@ case $basic_machine in
pmac | pmac-mpw) pmac | pmac-mpw)
basic_machine=powerpc-apple basic_machine=powerpc-apple
;; ;;
c4x*)
basic_machine=c4x-none
os=-coff
;;
*-unknown) *-unknown)
# Make sure to match an already-canonicalized machine name. # Make sure to match an already-canonicalized machine name.
;; ;;
@ -1092,22 +1262,28 @@ case $os in
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
| -kopensolaris* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* \ | -aos* | -aros* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -openbsd* | -solidbsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \ | -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux* | -uxpv* | -beos* | -mpeix* | -udk* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
| -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* | -powermax*) | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
# Remember, each alternative MUST END IN *, to match a version number. # Remember, each alternative MUST END IN *, to match a version number.
;; ;;
-qnx*) -qnx*)
@ -1119,16 +1295,24 @@ case $os in
;; ;;
esac esac
;; ;;
-nto-qnx*)
;;
-nto*) -nto*)
os=-nto-qnx os=`echo $os | sed -e 's|nto|nto-qnx|'`
;; ;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
;; ;;
-mac*) -mac*)
os=`echo $os | sed -e 's|mac|macos|'` os=`echo $os | sed -e 's|mac|macos|'`
;; ;;
-linux-dietlibc)
os=-linux-dietlibc
;;
-linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
-sunos5*) -sunos5*)
os=`echo $os | sed -e 's|sunos5|solaris2|'` os=`echo $os | sed -e 's|sunos5|solaris2|'`
;; ;;
@ -1138,6 +1322,9 @@ case $os in
-opened*) -opened*)
os=-openedition os=-openedition
;; ;;
-os400*)
os=-os400
;;
-wince*) -wince*)
os=-wince os=-wince
;; ;;
@ -1159,6 +1346,9 @@ case $os in
-atheos*) -atheos*)
os=-atheos os=-atheos
;; ;;
-syllable*)
os=-syllable
;;
-386bsd) -386bsd)
os=-bsd os=-bsd
;; ;;
@ -1169,7 +1359,7 @@ case $os in
os=-rtmk-nova os=-rtmk-nova
;; ;;
-ns2 ) -ns2 )
os=-nextstep2 os=-nextstep2
;; ;;
-nsk*) -nsk*)
os=-nsk os=-nsk
@ -1181,6 +1371,9 @@ case $os in
-sinix*) -sinix*)
os=-sysv4 os=-sysv4
;; ;;
-tpf*)
os=-tpf
;;
-triton*) -triton*)
os=-sysv3 os=-sysv3
;; ;;
@ -1208,8 +1401,20 @@ case $os in
-xenix) -xenix)
os=-xenix os=-xenix
;; ;;
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
os=-mint os=-mint
;;
-aros*)
os=-aros
;;
-kaos*)
os=-kaos
;;
-zvmoe)
os=-zvmoe
;;
-dicos*)
os=-dicos
;; ;;
-none) -none)
;; ;;
@ -1233,6 +1438,12 @@ else
# system, and we'll never get to this point. # system, and we'll never get to this point.
case $basic_machine in case $basic_machine in
score-*)
os=-elf
;;
spu-*)
os=-elf
;;
*-acorn) *-acorn)
os=-riscix1.2 os=-riscix1.2
;; ;;
@ -1242,11 +1453,14 @@ case $basic_machine in
arm*-semi) arm*-semi)
os=-aout os=-aout
;; ;;
c4x-* | tic4x-*)
os=-coff
;;
# This must come before the *-dec entry. # This must come before the *-dec entry.
pdp10-*) pdp10-*)
os=-tops20 os=-tops20
;; ;;
pdp11-*) pdp11-*)
os=-none os=-none
;; ;;
*-dec | vax-*) *-dec | vax-*)
@ -1267,6 +1481,9 @@ case $basic_machine in
m68*-cisco) m68*-cisco)
os=-aout os=-aout
;; ;;
mep-*)
os=-elf
;;
mips*-cisco) mips*-cisco)
os=-elf os=-elf
;; ;;
@ -1285,9 +1502,15 @@ case $basic_machine in
*-be) *-be)
os=-beos os=-beos
;; ;;
*-haiku)
os=-haiku
;;
*-ibm) *-ibm)
os=-aix os=-aix
;; ;;
*-knuth)
os=-mmixware
;;
*-wec) *-wec)
os=-proelf os=-proelf
;; ;;
@ -1339,19 +1562,19 @@ case $basic_machine in
*-next) *-next)
os=-nextstep3 os=-nextstep3
;; ;;
*-gould) *-gould)
os=-sysv os=-sysv
;; ;;
*-highlevel) *-highlevel)
os=-bsd os=-bsd
;; ;;
*-encore) *-encore)
os=-bsd os=-bsd
;; ;;
*-sgi) *-sgi)
os=-irix os=-irix
;; ;;
*-siemens) *-siemens)
os=-sysv4 os=-sysv4
;; ;;
*-masscomp) *-masscomp)
@ -1420,9 +1643,15 @@ case $basic_machine in
-mvs* | -opened*) -mvs* | -opened*)
vendor=ibm vendor=ibm
;; ;;
-os400*)
vendor=ibm
;;
-ptx*) -ptx*)
vendor=sequent vendor=sequent
;; ;;
-tpf*)
vendor=ibm
;;
-vxsim* | -vxworks* | -windiss*) -vxsim* | -vxworks* | -windiss*)
vendor=wrs vendor=wrs
;; ;;
@ -1447,7 +1676,7 @@ case $basic_machine in
esac esac
echo $basic_machine$os echo $basic_machine$os
exit 0 exit
# Local variables: # Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp) # eval: (add-hook 'write-file-hooks 'time-stamp)

View File

@ -80,11 +80,11 @@ fi
AC_SUBST(HAVE_LIBBZ2) AC_SUBST(HAVE_LIBBZ2)
# valgrind checks # valgrind checks
AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind], AC_ARG_WITH([valgrind], [AC_HELP_STRING([--with-valgrind],
[Add valgrind hooks])], [Add valgrind hooks])],
[], [check_valgrind=yes]) [], [check_valgrind=yes])
AS_IF([test "x$check_valgrind" == xyes], AS_IF([test "x$check_valgrind" = xyes],
[AC_MSG_NOTICE([Not using valgrind hooks])], [AC_MSG_NOTICE([Not using valgrind hooks])],
[AC_CHECK_HEADER([valgrind/memcheck.h], [AC_CHECK_HEADER([valgrind/memcheck.h],
[AC_DEFINE([CHECK_WITH_VALGRIND], [1], [AC_DEFINE([CHECK_WITH_VALGRIND], [1],
@ -181,21 +181,21 @@ AX_C_UNDERSCORES_TRAILING
####################### #######################
AC_MSG_CHECKING(for sanity of prefix) AC_MSG_CHECKING(for sanity of prefix)
if test X`echo "$prefix" | wc -w` != X1 if test `echo "$prefix" | wc -w` != 1
then then
AC_MSG_ERROR(cannot configure white space in prefix: $prefix) AC_MSG_ERROR(cannot configure white space in prefix: $prefix)
fi fi
AC_MSG_RESULT(ok) AC_MSG_RESULT(ok)
AC_MSG_CHECKING(for sanity of exec_prefix) AC_MSG_CHECKING(for sanity of exec_prefix)
if test X`echo "$exec_prefix" | wc -w` != X1 if test `echo "$exec_prefix" | wc -w` != 1
then then
AC_MSG_ERROR(cannot configure white space in exec_prefix: $exec_prefix) AC_MSG_ERROR(cannot configure white space in exec_prefix: $exec_prefix)
fi fi
AC_MSG_RESULT(ok) AC_MSG_RESULT(ok)
AC_MSG_CHECKING(for sanity of libdir) AC_MSG_CHECKING(for sanity of libdir)
if test X`echo "$libdir" | wc -w` != X1 if test `echo "$libdir" | wc -w` != 1
then then
AC_MSG_ERROR(cannot configure white space in libdir: $libdir) AC_MSG_ERROR(cannot configure white space in libdir: $libdir)
fi fi

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -208,8 +208,12 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
o << " scope=" << scope_path(scope()); o << " scope=" << scope_path(scope());
o << " #(" << rise_time() << "," << fall_time() << "," o << " #(" << rise_time() << "," << fall_time() << ","
<< decay_time() << ") vector_width=" << vector_width() << decay_time() << ") vector_width=" << vector_width()
<< " pin_count=" << pin_count() << " pin_count=" << pin_count();
<< " init="; if (pins_are_virtual()) {
o << " pins_are_virtual" << endl;
return;
}
o << " init=";
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1) for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
o << pin(idx-1).get_init(); o << pin(idx-1).get_init();
@ -1073,29 +1077,11 @@ void NetRepeat::dump(ostream&o, unsigned ind) const
void NetScope::dump(ostream&o) const void NetScope::dump(ostream&o) const
{ {
/* This is a constructed hierarchical name. */ /* This is a constructed hierarchical name. */
o << scope_path(this); o << scope_path(this) << " ";
switch (type_) { print_type(o);
case BEGIN_END:
o << " sequential block";
break;
case FORK_JOIN:
o << " parallel block";
break;
case FUNC:
o << " function";
break;
case MODULE:
o << " module <" << (module_name_? module_name_.str() : "") << ">";
break;
case TASK:
o << " task";
break;
case GENBLOCK:
o << " generate block";
break;
}
if (is_auto()) o << " (automatic)"; if (is_auto()) o << " (automatic)";
if (is_cell()) o << " (cell)";
o << endl; o << endl;
for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1) for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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 * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT
#ident "$Id: dosify.c,v 1.5 2003/07/15 16:17:47 steve Exp $"
#endif
/* /*
* This is a simple program to make a dosified copy of the * This is a simple program to make a dosified copy of the
@ -51,6 +48,7 @@ int main(int argc, char*argv[])
ofile = fopen(argv[2], "wb"); ofile = fopen(argv[2], "wb");
if (ofile == 0) { if (ofile == 0) {
fprintf(stderr, "Unable to open %s for output.\n", argv[2]); fprintf(stderr, "Unable to open %s for output.\n", argv[2]);
fclose(ifile);
return 2; return 2;
} }
@ -64,25 +62,7 @@ int main(int argc, char*argv[])
pr = ch; pr = ch;
} }
fclose(ifile);
fclose(ofile);
return 0; return 0;
} }
/*
* $Log: dosify.c,v $
* Revision 1.5 2003/07/15 16:17:47 steve
* Fix spelling of ifdef.
*
* Revision 1.4 2003/07/15 03:49:22 steve
* Spelling fixes.
*
* Revision 1.3 2002/08/12 01:34:58 steve
* conditional ident string using autoconfig.
*
* Revision 1.2 2002/08/11 23:47:04 steve
* Add missing Log and Ident strings.
*
* Revision 1.1 2001/08/03 17:06:47 steve
* Add install of examples for Windows.
*
*/

View File

@ -4,7 +4,7 @@
%{ %{
/* /*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -21,9 +21,6 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT
#ident "$Id: cflexor.lex,v 1.11 2007/03/22 16:08:18 steve Exp $"
#endif
# include "cfparse.h" # include "cfparse.h"
# include "cfparse_misc.h" # include "cfparse_misc.h"
@ -236,3 +233,17 @@ void cfreset(FILE*fd, const char*path)
current_file = strdup(path); current_file = strdup(path);
cflloc.first_line = 1; cflloc.first_line = 1;
} }
/*
* Modern version of flex (>=2.5.9) can clean up the scanner data.
*/
void destroy_lexor()
{
# ifdef FLEX_SCANNER
# if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5
# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9
yylex_destroy();
# endif
# endif
# endif
}

View File

@ -1,6 +1,6 @@
%{ %{
/* /*
* Copyright (c) 20001 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -17,10 +17,6 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT
#ident "$Id: cfparse.y,v 1.12 2007/04/19 02:52:53 steve Exp $"
#endif
# include "globals.h" # include "globals.h"
# include "cfparse_misc.h" # include "cfparse_misc.h"

View File

@ -1,7 +1,7 @@
#ifndef __cfparse_misc_H #ifndef __cfparse_misc_H
#define __cfparse_misc_H #define __cfparse_misc_H
/* /*
* Copyright (c) 2001 Picture Elements, Inc. * Copyright (c) 2001-2009 Picture Elements, Inc.
* Stephen Williams (steve@picturel.com) * Stephen Williams (steve@picturel.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
@ -38,6 +38,7 @@ int cflex(void);
int cferror(const char *); int cferror(const char *);
int cfparse(void); int cfparse(void);
void switch_to_command_file(const char *); void switch_to_command_file(const char *);
void destroy_lexor();
char *current_file; char *current_file;
#endif #endif

View File

@ -4,10 +4,10 @@ iverilog - Icarus Verilog compiler
.SH SYNOPSIS .SH SYNOPSIS
.B iverilog .B iverilog
[-ESVv] [-Bpath] [-ccmdfile|-fcmdfile] [-Dmacro[=defn]] [-pflag=value] [\-ESVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] [\-pflag=value]
[-dname] [-g1995|-g2001|-g2005|-g<feature>] [\-dname] [\-g1995|\-g2001|\-g2005|\-g<feature>]
[-Iincludedir] [-mmodule] [-Mfile] [-Nfile] [-ooutputfilename] [\-Iincludedir] [\-mmodule] [\-Mfile] [\-Nfile] [\-ooutputfilename]
[-stopmodule] [-ttype] [-Tmin/typ/max] [-Wclass] [-ypath] sourcefile [\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] [\-ypath] sourcefile
.SH DESCRIPTION .SH DESCRIPTION
.PP .PP
@ -18,7 +18,6 @@ simulation, and \fIfpga\fP for synthesis. Other target
types are added as code generators are implemented. types are added as code generators are implemented.
.SH OPTIONS .SH OPTIONS
.l
\fIiverilog\fP accepts the following options: \fIiverilog\fP accepts the following options:
.TP 8 .TP 8
.B -B\fIbase\fP .B -B\fIbase\fP
@ -55,7 +54,7 @@ is the Verilog input, but with file inclusions and macro references
expanded and removed. This is useful, for example, to preprocess expanded and removed. This is useful, for example, to preprocess
Verilog source for use by other compilers. Verilog source for use by other compilers.
.TP 8 .TP 8
.B -g1995\fI|\fP-g2001\fI|\fP-g2005 .B -g1995\fI|\fP-g2001\fI|\fP-g2001-noconfig\fI|\fP-g2005
Select the Verilog language \fIgeneration\fP to support in the Select the Verilog language \fIgeneration\fP to support in the
compiler. This selects between \fIIEEE1364-1995\fP, compiler. This selects between \fIIEEE1364-1995\fP,
\fIIEEE1364-2001\fP(2), or \fIIEEE1364-2005\fP. Normally, \fIIEEE1364-2001\fP(2), or \fIIEEE1364-2005\fP. Normally,
@ -110,9 +109,9 @@ expression changes value, the entire expression is re-evaluated. By
default, parts of the expression that do not depend on the changed default, parts of the expression that do not depend on the changed
input value(s) are not re-evaluated. If an expression contains a call input value(s) are not re-evaluated. If an expression contains a call
to a function that doesn't depend solely on its input values or that to a function that doesn't depend solely on its input values or that
has side effects, the resulting behaviour will differ from that has side effects, the resulting behavior will differ from that
required by the standard. Using \fI-gstrict-ca-eval\fP will force required by the standard. Using \fI-gstrict-ca-eval\fP will force
standard compliant behaviour (with some loss in performance). standard compliant behavior (with some loss in performance).
.TP 8 .TP 8
.B -I\fIincludedir\fP .B -I\fIincludedir\fP
Append directory \fIincludedir\fP to list of directories searched Append directory \fIincludedir\fP to list of directories searched
@ -198,6 +197,11 @@ all the requested classes.
Append the directory to the library module search path. When the Append the directory to the library module search path. When the
compiler finds an undefined module, it looks in these directories for compiler finds an undefined module, it looks in these directories for
files with the right name. files with the right name.
.TP 8
.B -Y\fIsuffix\fP
Add suffix to the list of accepted file name suffixes used when
searching a library for cells. The list defaults to the single
entry \fI.v\fP.
.SH MODULE LIBRARIES .SH MODULE LIBRARIES
@ -250,7 +254,8 @@ after a \fB-Wall\fP argument to suppress isolated warning types.
.TP 8 .TP 8
.B all .B all
This enables all supported warning categories. This enables the implicit, portbind, select-range, timescale, and
sensitivity-entire-array warning categories.
.TP 8 .TP 8
.B implicit .B implicit
@ -264,6 +269,12 @@ This enables warnings for ports of module instantiations that are not
connected but probably should be. Dangling input ports, for example, connected but probably should be. Dangling input ports, for example,
will generate a warning. will generate a warning.
.TP 8
.B select-range
This enables warnings for constant out of bound selects. This includes
partial or fully out of bound selects as well as a select using 'bx as
an index.
.TP 8 .TP 8
.B timescale .B timescale
This enables warnings for inconsistent use of the timescale This enables warnings for inconsistent use of the timescale
@ -287,6 +298,22 @@ verified. It is expected that many of the warnings will be false
positives, since the code treats the value of all variables and signals positives, since the code treats the value of all variables and signals
as indeterminate. as indeterminate.
.TP 8
.B sensitivity-entire-vector
This enables warnings for when a part select within an "always @*"
statement results in the entire vector being added to the implicit
sensitivity list. Although this behaviour is prescribed by the IEEE
standard, it is not what might be expected and can have performance
implications if the vector is large.
.TP 8
.B sensitivity-entire-array
This enables warnings for when a word select within an "always @*"
statement results in the entire array being added to the implicit
sensitivity list. Although this behaviour is prescribed by the IEEE
standard, it is not what might be expected and can have performance
implications if the array is large.
.SH "SYSTEM FUNCTION TABLE FILES" .SH "SYSTEM FUNCTION TABLE FILES"
If the source file name as a \fB.sft\fP suffix, then it is taken to be 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 a system function table file. A System function table file is used to
@ -359,7 +386,7 @@ on to the next library directory.
.TP 8 .TP 8
.B +libdir+\fIdir\fP .B +libdir+\fIdir\fP
This is another way to specify library directories. See the -y flag. This is another way to specify library directories. See the \-y flag.
.TP 8 .TP 8
.B +libdir-nocase+\fIdir\fP .B +libdir-nocase+\fIdir\fP
@ -424,11 +451,11 @@ To compile hello.v to an executable file called a.out:
To compile hello.v to an executable file called hello: To compile hello.v to an executable file called hello:
iverilog -o hello hello.v iverilog \-o hello hello.v
To compile and run explicitly using the vvp runtime: To compile and run explicitly using the vvp runtime:
iverilog -ohello.vvp -tvvp hello.v iverilog \-ohello.vvp \-tvvp hello.v
.SH "AUTHOR" .SH "AUTHOR"
.nf .nf
@ -443,7 +470,7 @@ Tips on using, debugging, and developing the compiler can be found at
.SH COPYRIGHT .SH COPYRIGHT
.nf .nf
Copyright \(co 2002-2008 Stephen Williams Copyright \(co 2002-2009 Stephen Williams
This document can be freely redistributed according to the terms of the This document can be freely redistributed according to the terms of the
GNU General Public License version 2.0 GNU General Public License version 2.0

View File

@ -281,7 +281,7 @@ static int t_version_only(void)
} }
fflush(0); fflush(0);
snprintf(tmp, sizeof tmp, "%s%civl -V -C%s -C%s", pbase, sep, snprintf(tmp, sizeof tmp, "%s%civl -V -C%s -C%s", base, sep,
iconfig_path, iconfig_common_path); iconfig_path, iconfig_common_path);
rc = system(tmp); rc = system(tmp);
if (rc != 0) { if (rc != 0) {
@ -469,13 +469,18 @@ static void process_warning_switch(const char*name)
if (strcmp(name,"all") == 0) { if (strcmp(name,"all") == 0) {
process_warning_switch("implicit"); process_warning_switch("implicit");
process_warning_switch("portbind"); process_warning_switch("portbind");
process_warning_switch("select-range");
process_warning_switch("timescale"); process_warning_switch("timescale");
process_warning_switch("sensitivity-entire-array");
} else if (strcmp(name,"implicit") == 0) { } else if (strcmp(name,"implicit") == 0) {
if (! strchr(warning_flags, 'i')) if (! strchr(warning_flags, 'i'))
strcat(warning_flags, "i"); strcat(warning_flags, "i");
} else if (strcmp(name,"portbind") == 0) { } else if (strcmp(name,"portbind") == 0) {
if (! strchr(warning_flags, 'p')) if (! strchr(warning_flags, 'p'))
strcat(warning_flags, "p"); strcat(warning_flags, "p");
} else if (strcmp(name,"select-range") == 0) {
if (! strchr(warning_flags, 's'))
strcat(warning_flags, "s");
} else if (strcmp(name,"timescale") == 0) { } else if (strcmp(name,"timescale") == 0) {
if (! strchr(warning_flags, 't')) if (! strchr(warning_flags, 't'))
strcat(warning_flags, "t"); strcat(warning_flags, "t");
@ -484,6 +489,12 @@ static void process_warning_switch(const char*name)
} else if (strcmp(name,"infloop") == 0) { } else if (strcmp(name,"infloop") == 0) {
if (! strchr(warning_flags, 'l')) if (! strchr(warning_flags, 'l'))
strcat(warning_flags, "l"); strcat(warning_flags, "l");
} else if (strcmp(name,"sensitivity-entire-vector") == 0) {
if (! strchr(warning_flags, 'v'))
strcat(warning_flags, "v");
} else if (strcmp(name,"sensitivity-entire-array") == 0) {
if (! strchr(warning_flags, 'a'))
strcat(warning_flags, "a");
} else if (strcmp(name,"no-implicit") == 0) { } else if (strcmp(name,"no-implicit") == 0) {
char*cp = strchr(warning_flags, 'i'); char*cp = strchr(warning_flags, 'i');
if (cp) while (*cp) { if (cp) while (*cp) {
@ -496,12 +507,30 @@ static void process_warning_switch(const char*name)
cp[0] = cp[1]; cp[0] = cp[1];
cp += 1; cp += 1;
} }
} else if (strcmp(name,"no-select-range") == 0) {
char*cp = strchr(warning_flags, 's');
if (cp) while (*cp) {
cp[0] = cp[1];
cp += 1;
}
} else if (strcmp(name,"no-timescale") == 0) { } else if (strcmp(name,"no-timescale") == 0) {
char*cp = strchr(warning_flags, 't'); char*cp = strchr(warning_flags, 't');
if (cp) while (*cp) { if (cp) while (*cp) {
cp[0] = cp[1]; cp[0] = cp[1];
cp += 1; cp += 1;
} }
} else if (strcmp(name,"no-sensitivity-entire-vector") == 0) {
char*cp = strchr(warning_flags, 'v');
if (cp) while (*cp) {
cp[0] = cp[1];
cp += 1;
}
} else if (strcmp(name,"no-sensitivity-entire-array") == 0) {
char*cp = strchr(warning_flags, 'a');
if (cp) while (*cp) {
cp[0] = cp[1];
cp += 1;
}
} }
} }
@ -557,6 +586,9 @@ int process_generation(const char*name)
else if (strcmp(name,"2001") == 0) else if (strcmp(name,"2001") == 0)
generation = "2001"; generation = "2001";
else if (strcmp(name,"2001-noconfig") == 0)
generation = "2001-noconfig";
else if (strcmp(name,"2005") == 0) else if (strcmp(name,"2005") == 0)
generation = "2005"; generation = "2005";
@ -866,6 +898,20 @@ int main(int argc, char **argv)
break; break;
case '?': case '?':
default: default:
fclose(source_file);
remove(source_path);
free(source_path);
fclose(defines_file);
remove(defines_path);
free(defines_path);
fclose(iconfig_file);
remove(iconfig_path);
free(iconfig_path);
remove(compiled_defines_path);
free(compiled_defines_path);
while( (command_filename = get_cmd_file()) ) {
free(command_filename);
}
return 1; return 1;
} }
} }
@ -937,7 +983,9 @@ int main(int argc, char **argv)
return 1; return 1;
} }
free(command_filename); free(command_filename);
fclose(fp);
} }
destroy_lexor();
if (depfile) { if (depfile) {
fprintf(defines_file, "M:%s\n", depfile); fprintf(defines_file, "M:%s\n", depfile);

View File

@ -419,10 +419,8 @@ NetExpr* PEBinary::elaborate_expr_base_bits_(Design*des,
// If either of the arguments is unsigned, then process both // If either of the arguments is unsigned, then process both
// of them as unsigned. This only impacts the padding that is // of them as unsigned. This only impacts the padding that is
// done to get the operands to the expr_wid. // done to get the operands to the expr_wid.
if (! lp->has_sign()) if (! lp->has_sign()) rp->cast_signed(false);
rp->cast_signed(false); if (! rp->has_sign()) lp->cast_signed(false);
if (! rp->has_sign())
lp->cast_signed(false);
if (expr_wid > 0) { if (expr_wid > 0) {
if (type_is_vectorable(lp->expr_type())) if (type_is_vectorable(lp->expr_type()))
@ -453,6 +451,12 @@ NetExpr* PEBinary::elaborate_expr_base_div_(Design*des,
} }
} }
// If either of the arguments is unsigned, then process both
// of them as unsigned. This only impacts the padding that is
// done to get the operands to the expr_wid.
if (! lp->has_sign()) rp->cast_signed(false);
if (! rp->has_sign()) lp->cast_signed(false);
/* The original elaboration of the left and right expressions /* The original elaboration of the left and right expressions
already tried to elaborate to the expr_wid. If the already tried to elaborate to the expr_wid. If the
expressions are not that width by now, then they need to be expressions are not that width by now, then they need to be
@ -643,13 +647,13 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
} }
if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) { if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
long shift = rpc->value().as_long(); unsigned long shift = rpc->value().as_ulong();
// Special case: The shift is the size of the entire // Special case: The shift is the size of the entire
// left operand, and the shift is unsigned. Elaborate as // left operand, and the shift is unsigned. Elaborate as
// a constant-0. // a constant-0.
if ((op_=='r' || (lp->has_sign()==false)) if ((op_=='r' || (lp->has_sign()==false)) &&
&& shift >= (long)lp->expr_width()) { shift >= lp->expr_width()) {
if (debug_elaborate) if (debug_elaborate)
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
@ -666,7 +670,11 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
// Special case: the shift is the size of the entire // Special case: the shift is the size of the entire
// left operand, and the shift is signed. Elaborate as a // left operand, and the shift is signed. Elaborate as a
// replication of the top bit of the left expression. // replication of the top bit of the left expression.
if (shift >= (long)lp->expr_width()) { //
// The above test assures us that op_ == 'R' && the left
// argument is signed when the shift is greater than the
// expression width.
if (shift >= lp->expr_width()) {
if (debug_elaborate) if (debug_elaborate)
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
@ -685,34 +693,10 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
return tmp; return tmp;
} }
// Special case: shift is negative (so do a left shift)
// and is greater then the output width. Replace the
// expression with a constant-0.
if (shift < 0 && (0-shift) >= use_wid) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Value signed-right-shifted " << shift
<< " beyond width of " << use_wid
<< "." << endl;
tmp = make_const_0(use_wid);
tmp->set_line(*this);
return tmp;
}
ivl_assert(*this, shift >= 0);
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Value signed-right-shifted " << shift
<< " beyond width of " << lp->expr_width()
<< ". shift=" << shift
<< ", expr_wid=" << expr_wid
<< ", expr=" << *lp << endl;
// If this is lossless, then pad the left expression // If this is lossless, then pad the left expression
// enough to cover the right shift. // enough to cover the right shift.
if (expr_wid == -2 && use_wid+shift > (long)lp->expr_width()) { if (expr_wid == -2 && use_wid+shift > lp->expr_width()) {
lp->cast_signed(lp->has_sign() && op_=='R');
lp = pad_to_width(lp, use_wid + shift, *this); lp = pad_to_width(lp, use_wid + shift, *this);
} }
@ -1504,6 +1488,12 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
def->port(idx)->data_type(), def->port(idx)->data_type(),
def->port(idx)->vector_width(), def->port(idx)->vector_width(),
tmp); tmp);
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (parms[idx])) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' can not be a user "
"function argument." << endl;
des->errors += 1;
}
if (debug_elaborate) if (debug_elaborate)
cerr << get_fileline() << ": debug:" cerr << get_fileline() << ": debug:"
<< " function " << path_ << " function " << path_
@ -1633,7 +1623,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
} }
if (tmp->expr_type() == IVL_VT_REAL) { if (tmp->expr_type() == IVL_VT_REAL) {
cerr << tmp->get_fileline() << ": error: concatenation " cerr << tmp->get_fileline() << ": error: Concatenation "
<< "repeat expression can not be REAL." << endl; << "repeat expression can not be REAL." << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
@ -1643,7 +1633,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
if (rep == 0) { if (rep == 0) {
cerr << get_fileline() << ": error: " cerr << get_fileline() << ": error: "
"concatenation repeat expression cannot be evaluated." "Concatenation repeat expression cannot be evaluated."
<< endl; << endl;
cerr << get_fileline() << ": : The expression is: " cerr << get_fileline() << ": : The expression is: "
<< *tmp << endl; << *tmp << endl;
@ -1702,18 +1692,20 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
ex->set_line(*parms_[idx]); ex->set_line(*parms_[idx]);
if (! ex->has_width()) {
cerr << ex->get_fileline() << ": error: "
<< "concatenation operand has indefinite width: "
<< *ex << endl;
des->errors += 1;
}
if (ex->expr_type() == IVL_VT_REAL) { if (ex->expr_type() == IVL_VT_REAL) {
cerr << ex->get_fileline() << ": error: " cerr << ex->get_fileline() << ": error: "
<< "concatenation operand can not be REAL: " << "Concatenation operand can not be real: "
<< *ex << endl; << *parms_[idx] << endl;
des->errors += 1; des->errors += 1;
continue;
}
if (! ex->has_width()) {
cerr << ex->get_fileline() << ": error: "
<< "Concatenation operand \"" << *parms_[idx]
<< "\" has indefinite width." << endl;
des->errors += 1;
continue;
} }
wid_sum += ex->expr_width(); wid_sum += ex->expr_width();
@ -1727,6 +1719,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
<< "have zero width in this context." << endl; << "have zero width in this context." << endl;
des->errors += 1; des->errors += 1;
concat_depth -= 1; concat_depth -= 1;
delete tmp;
return 0; return 0;
} }
@ -1790,7 +1783,9 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
two bit select expressions, and both must be two bit select expressions, and both must be
constant. Evaluate them and pass the results back to constant. Evaluate them and pass the results back to
the caller. */ the caller. */
need_constant_expr = true;
NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, lsb_wid); NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, lsb_wid);
need_constant_expr = false;
NetEConst*lsb_c = dynamic_cast<NetEConst*>(lsb_ex); NetEConst*lsb_c = dynamic_cast<NetEConst*>(lsb_ex);
if (lsb_c == 0) { if (lsb_c == 0) {
cerr << index_tail.lsb->get_fileline() << ": error: " cerr << index_tail.lsb->get_fileline() << ": error: "
@ -1808,7 +1803,9 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
lsb = lsb_c->value().as_long(); lsb = lsb_c->value().as_long();
} }
need_constant_expr = true;
NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, msb_wid); NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, msb_wid);
need_constant_expr = false;
NetEConst*msb_c = dynamic_cast<NetEConst*>(msb_ex); NetEConst*msb_c = dynamic_cast<NetEConst*>(msb_ex);
if (msb_c == 0) { if (msb_c == 0) {
cerr << index_tail.msb->get_fileline() << ": error: " cerr << index_tail.msb->get_fileline() << ": error: "
@ -1845,7 +1842,9 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope,
/* Calculate the width expression (in the lsb_ position) /* Calculate the width expression (in the lsb_ position)
first. If the expression is not constant, error but guess 1 first. If the expression is not constant, error but guess 1
so we can keep going and find more errors. */ so we can keep going and find more errors. */
need_constant_expr = true;
NetExpr*wid_ex = elab_and_eval(des, scope, index_tail.lsb, -1); NetExpr*wid_ex = elab_and_eval(des, scope, index_tail.lsb, -1);
need_constant_expr = false;
NetEConst*wid_c = dynamic_cast<NetEConst*>(wid_ex); NetEConst*wid_c = dynamic_cast<NetEConst*>(wid_ex);
if (wid_c == 0) { if (wid_c == 0) {
@ -1943,7 +1942,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope,
if (!name_tail.index.empty()) { if (!name_tail.index.empty()) {
probe_index_expr_width(des, scope, name_tail); probe_index_expr_width(des, scope, name_tail);
const index_component_t&index_tail = name_tail.index.back(); const index_component_t&index_tail = name_tail.index.back();
use_sel = index_tail.sel; // Skip full array word net selects.
if (!net || (name_tail.index.size() > net->array_dimensions())) {
use_sel = index_tail.sel;
}
} }
unsigned use_width = UINT_MAX; unsigned use_width = UINT_MAX;
@ -2214,12 +2216,12 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
} }
static verinum param_part_select_bits(const verinum&par_val, long wid, static verinum param_part_select_bits(const verinum&par_val, long wid,
long lsv, long par_lsv) long lsv)
{ {
verinum result (verinum::Vx, wid, true); verinum result (verinum::Vx, wid, true);
for (long idx = 0 ; idx < wid ; idx += 1) { for (long idx = 0 ; idx < wid ; idx += 1) {
long off = idx + lsv - par_lsv; long off = idx + lsv;
if (off < 0) if (off < 0)
result.set(idx, verinum::Vx); result.set(idx, verinum::Vx);
else if (off < (long)par_val.len()) else if (off < (long)par_val.len())
@ -2234,7 +2236,7 @@ static verinum param_part_select_bits(const verinum&par_val, long wid,
// If the input is a string, and the part select is working on // If the input is a string, and the part select is working on
// byte boundaries, then make the result into a string. // byte boundaries, then make the result into a string.
if (par_val.is_string() && (labs(lsv-par_lsv)%8 == 0) && (wid%8 == 0)) if (par_val.is_string() && (labs(lsv)%8 == 0) && (wid%8 == 0))
return result.as_string(); return result.as_string();
return result; return result;
@ -2259,7 +2261,7 @@ NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
if (! parts_defined_flag) { if (! parts_defined_flag) {
if (debug_elaborate) if (debug_elaborate)
cerr << get_fileline() << ": debug: Part select of paramter " cerr << get_fileline() << ": debug: Part select of parameter "
<< "has x/z bits, so resorting to 'bx result." << endl; << "has x/z bits, so resorting to 'bx result." << endl;
long wid = 1 + labs(par_msv-par_lsv); long wid = 1 + labs(par_msv-par_lsv);
@ -2290,28 +2292,56 @@ NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par); const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
ivl_assert(*this, par_ex); ivl_assert(*this, par_ex);
verinum result = param_part_select_bits(par_ex->value(), wid, lsv, par_lsv); verinum result = param_part_select_bits(par_ex->value(), wid, lsv-par_lsv);
NetEConst*result_ex = new NetEConst(result); NetEConst*result_ex = new NetEConst(result);
result_ex->set_line(*this); result_ex->set_line(*this);
return result_ex; return result_ex;
} }
static void warn_param_ob(long par_msv, long par_lsv, bool defined,
long par_base, unsigned long wid, long pwid,
const LineInfo *info, perm_string name, bool up)
{
long par_max;
if (defined) {
if (par_msv < par_lsv) par_max = par_lsv-par_msv;
else par_max = par_msv-par_lsv;
} else {
if (pwid < 0) par_max = integer_width;
else par_max = pwid;
}
/* Is this a select before the start of the parameter? */
if (par_base < 0) {
cerr << info->get_fileline() << ": warning: " << name << "["
<< par_base;
if (up) cerr << "+:";
else cerr << "-:";
cerr << wid << "] is selecting before vector." << endl;
}
/* Is this a select after the end of the parameter? */
if (par_base + (long)wid - 1 > par_max) {
cerr << info->get_fileline() << ": warning: " << name << "["
<< par_base << "+:" << wid << "] is selecting after vector."
<< endl;
}
}
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
const NetExpr*par, const NetExpr*par,
NetScope*found_in, NetScope*found_in,
const NetExpr*par_msb, const NetExpr*par_msb,
const NetExpr*par_lsb) const const NetExpr*par_lsb) const
{ {
long par_msv, par_lsv; long par_msv, par_lsv;
bool flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv); if(! calculate_param_range_(des, scope, par_msb, par_msv,
if (!flag) par_lsb, par_lsv)) return 0;
return 0;
NetExpr*base = calculate_up_do_base_(des, scope); NetExpr*base = calculate_up_do_base_(des, scope);
if (base == 0) if (base == 0) return 0;
return 0;
unsigned long wid = 0; unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid); calculate_up_do_width_(des, scope, wid);
@ -2327,22 +2357,139 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
// Handle the special case that the base is constant. In this // Handle the special case that the base is constant. In this
// case, just precalculate the entire constant result. // case, just precalculate the entire constant result.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) { if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
if (! base_c->value().is_defined()) {
NetEConst *ex;
ex = new NetEConst(verinum(verinum::Vx, wid, true));
ex->set_line(*this);
if (warn_ob_select) {
perm_string name = peek_tail_name(path_);
cerr << get_fileline() << ": warning: " << name
<< "['bx+:" << wid
<< "] is always outside vector." << endl;
}
return ex;
}
long lsv = base_c->value().as_long(); long lsv = base_c->value().as_long();
long par_base = par_lsv;
// Watch out for reversed bit numbering. We're making // Watch out for reversed bit numbering. We're making
// the part select from LSB to MSB. // the part select from LSB to MSB.
if (par_msv < par_lsv) if (par_msv < par_lsv) {
lsv = lsv - wid + 1; par_base = lsv;
lsv = par_lsv - wid + 1;
}
if (warn_ob_select) {
bool defined = true;
// Check to see if the parameter has a defined range.
if (par_msb == 0) {
assert(par_lsb == 0);
defined = false;
}
// Get the parameter values width.
long pwid = -1;
if (par_ex->has_width()) pwid = par_ex->expr_width()-1;
perm_string name = peek_tail_name(path_);
warn_param_ob(par_msv, par_lsv, defined, lsv-par_base, wid,
pwid, this, name, true);
}
verinum result = param_part_select_bits(par_ex->value(), wid, verinum result = param_part_select_bits(par_ex->value(), wid,
lsv, par_lsv); lsv-par_base);
NetEConst*result_ex = new NetEConst(result); NetEConst*result_ex = new NetEConst(result);
result_ex->set_line(*this); result_ex->set_line(*this);
return result_ex; return result_ex;
} }
if ((par_msv < par_lsv) && (wid>1)) if (par_msv >= par_lsv) {
base = make_add_expr(base, 1-(long)wid); if (par_lsv != 0) base = make_add_expr(base, -par_lsv);
} else {
base = make_sub_expr(par_lsv-wid+1, base);
}
NetExpr*tmp = par->dup_expr();
tmp = new NetESelect(tmp, base, wid);
tmp->set_line(*this);
return tmp;
}
NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb) const
{
long par_msv, par_lsv;
if(! calculate_param_range_(des, scope, par_msb, par_msv,
par_lsb, par_lsv)) return 0;
NetExpr*base = calculate_up_do_base_(des, scope);
if (base == 0) return 0;
unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid);
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
ivl_assert(*this, par_ex);
if (debug_elaborate)
cerr << get_fileline() << ": debug: Calculate part select "
<< "[" << *base << "-:" << wid << "] from range "
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
// Handle the special case that the base is constant. In this
// case, just precalculate the entire constant result.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
if (! base_c->value().is_defined()) {
NetEConst *ex;
ex = new NetEConst(verinum(verinum::Vx, wid, true));
ex->set_line(*this);
if (warn_ob_select) {
perm_string name = peek_tail_name(path_);
cerr << get_fileline() << ": warning: " << name
<< "['bx-:" << wid
<< "] is always outside vector." << endl;
}
return ex;
}
long lsv = base_c->value().as_long();
long par_base = par_lsv + wid - 1;
// Watch out for reversed bit numbering. We're making
// the part select from LSB to MSB.
if (par_msv < par_lsv) {
par_base = lsv;
lsv = par_lsv;
}
if (warn_ob_select) {
bool defined = true;
// Check to see if the parameter has a defined range.
if (par_msb == 0) {
assert(par_lsb == 0);
defined = false;
}
// Get the parameter values width.
long pwid = -1;
if (par_ex->has_width()) pwid = par_ex->expr_width()-1;
perm_string name = peek_tail_name(path_);
warn_param_ob(par_msv, par_lsv, defined, lsv-par_base, wid,
pwid, this, name, false);
}
verinum result = param_part_select_bits(par_ex->value(), wid,
lsv-par_base);
NetEConst*result_ex = new NetEConst(result);
result_ex->set_line(*this);
return result_ex;
}
if (par_msv >= par_lsv) {
if (long offset = par_lsv+wid-1) {
base = make_add_expr(base, -offset);
}
} else {
base = make_sub_expr(par_lsv, base);
}
NetExpr*tmp = par->dup_expr(); NetExpr*tmp = par->dup_expr();
tmp = new NetESelect(tmp, base, wid); tmp = new NetESelect(tmp, base, wid);
@ -2368,6 +2515,15 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
if (!name_tail.index.empty()) if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel; use_sel = name_tail.index.back().sel;
if (par->expr_type() == IVL_VT_REAL &&
use_sel != index_component_t::SEL_NONE) {
perm_string name = peek_tail_name(path_);
cerr << get_fileline() << ": error: "
<< "can not select part of real parameter: " << name << endl;
des->errors += 1;
return 0;
}
// NOTE TO SELF: This is the way I want to see this code // NOTE TO SELF: This is the way I want to see this code
// structured. This closely follows the structure of the // structured. This closely follows the structure of the
// elaborate_expr_net_ code, which splits all the various // elaborate_expr_net_ code, which splits all the various
@ -2380,47 +2536,16 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
return elaborate_expr_param_idx_up_(des, scope, par, found_in, return elaborate_expr_param_idx_up_(des, scope, par, found_in,
par_msb, par_lsb); par_msb, par_lsb);
if (use_sel == index_component_t::SEL_IDX_DO)
return elaborate_expr_param_idx_do_(des, scope, par, found_in,
par_msb, par_lsb);
// NOTE TO SELF (continued): The code below should be // NOTE TO SELF (continued): The code below should be
// rewritten in the above format, as I get to it. // rewritten in the above format, as I get to it.
NetExpr*tmp = par->dup_expr(); NetExpr*tmp = par->dup_expr();
if (use_sel == index_component_t::SEL_IDX_DO) { if (use_sel == index_component_t::SEL_BIT) {
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb);
ivl_assert(*this, index_tail.lsb);
/* Get and evaluate the width of the index
select. This must be constant. */
NetExpr*wid_ex = elab_and_eval(des, scope, index_tail.lsb, -1);
NetEConst*wid_ec = dynamic_cast<NetEConst*> (wid_ex);
if (wid_ec == 0) {
cerr << index_tail.lsb->get_fileline() << ": error: "
<< "Second expression of indexed part select "
<< "most be constant." << endl;
des->errors += 1;
return 0;
}
unsigned wid = wid_ec->value().as_ulong();
NetExpr*idx_ex = elab_and_eval(des, scope, index_tail.msb, -1);
if (idx_ex == 0) {
return 0;
}
if (use_sel == index_component_t::SEL_IDX_DO && wid > 1) {
idx_ex = make_add_expr(idx_ex, 1-(long)wid);
}
/* Wrap the param expression with a part select. */
tmp = new NetESelect(tmp, idx_ex, wid);
} else if (use_sel == index_component_t::SEL_BIT) {
ivl_assert(*this, !name_tail.index.empty()); ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back(); const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb); ivl_assert(*this, index_tail.msb);
@ -2603,6 +2728,9 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
// Special case: The index is out of range, so the value // Special case: The index is out of range, so the value
// of this expression is a 'bx vector the width of a word. // of this expression is a 'bx vector the width of a word.
if (!net->array_index_is_valid(addr)) { if (!net->array_index_is_valid(addr)) {
cerr << get_fileline() << ": warning: returning 'bx for out "
"of bounds array access " << net->name()
<< "[" << addr << "]." << endl;
NetEConst*resx = make_const_x(net->vector_width()); NetEConst*resx = make_const_x(net->vector_width());
resx->set_line(*this); resx->set_line(*this);
delete word_index; delete word_index;
@ -2638,6 +2766,18 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
if (name_tail.index.size() > 1) if (name_tail.index.size() > 1)
word_sel = name_tail.index.back().sel; word_sel = name_tail.index.back().sel;
if (net->get_scalar() &&
word_sel != index_component_t::SEL_NONE) {
cerr << get_fileline() << ": error: can not select part of ";
if (res->expr_type() == IVL_VT_REAL) cerr << "real";
else cerr << "scalar";
cerr << " array word: " << net->name()
<<"[" << *word_index << "]" << endl;
des->errors += 1;
delete res;
return 0;
}
if (word_sel == index_component_t::SEL_PART) if (word_sel == index_component_t::SEL_PART)
return elaborate_expr_net_part_(des, scope, res, found_in); return elaborate_expr_net_part_(des, scope, res, found_in);
@ -2651,6 +2791,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
return elaborate_expr_net_bit_(des, scope, res, found_in); return elaborate_expr_net_bit_(des, scope, res, found_in);
ivl_assert(*this, word_sel == index_component_t::SEL_NONE); ivl_assert(*this, word_sel == index_component_t::SEL_NONE);
return res; return res;
} }
@ -2745,15 +2886,47 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
if (net->sig()->sb_to_idx(lsv) == 0 && if (net->sig()->sb_to_idx(lsv) == 0 &&
wid == net->vector_width()) { wid == net->vector_width()) {
delete base; delete base;
net->cast_signed(false);
return net; return net;
} }
long offset = 0;
if (net->msi() < net->lsi()) {
offset = -wid + 1;
}
// Otherwise, make a part select that covers the right // Otherwise, make a part select that covers the right
// range. // range.
ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv))); ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
offset));
if (warn_ob_select) {
long rel_base = net->sig()->sb_to_idx(lsv) + offset;
if (rel_base < 0) {
cerr << get_fileline() << ": warning: "
<< net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << lsv << "+:" << wid
<< "] is selecting before vector." << endl;
}
if (rel_base + wid > net->vector_width()) {
cerr << get_fileline() << ": warning: "
<< net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << lsv << "+:" << wid
<< "] is selecting after vector." << endl;
}
}
} else { } else {
// Return 'bx for an undefined base. // Return 'bx for an undefined base.
ex = new NetEConst(verinum(verinum::Vx, 1, false)); ex = new NetEConst(verinum(verinum::Vx, wid, true));
ex->set_line(*this);
delete base;
if (warn_ob_select) {
cerr << get_fileline() << ": warning: " << net->name();
if (net->word_index()) cerr << "[]";
cerr << "['bx+:" << wid
<< "] is always outside vector." << endl;
}
return ex;
} }
NetESelect*ss = new NetESelect(net, ex, wid); NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this); ss->set_line(*this);
@ -2764,11 +2937,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
if (net->msi() > net->lsi()) { if (net->msi() > net->lsi()) {
if (long offset = net->lsi()) if (long offset = net->lsi())
base = make_add_expr(base, 0-offset); base = make_add_expr(base, -offset);
} else { } else {
long vwid = net->lsi() - net->msi() + 1; base = make_sub_expr(net->lsi()-wid+1, base);
long offset = net->msi();
base = make_sub_expr(vwid-offset-wid, base);
} }
NetESelect*ss = new NetESelect(net, base, wid); NetESelect*ss = new NetESelect(net, base, wid);
@ -2807,15 +2978,47 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) && if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
wid == net->vector_width()) { wid == net->vector_width()) {
delete base; delete base;
net->cast_signed(false);
return net; return net;
} }
long offset = 0;
if (net->msi() > net->lsi()) {
offset = -wid + 1;
}
// Otherwise, make a part select that covers the right // Otherwise, make a part select that covers the right
// range. // range.
ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)-wid+1)); ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
offset));
if (warn_ob_select) {
long rel_base = net->sig()->sb_to_idx(lsv) + offset;
if (rel_base < 0) {
cerr << get_fileline() << ": warning: "
<< net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << lsv << "+:" << wid
<< "] is selecting before vector." << endl;
}
if (rel_base + wid > net->vector_width()) {
cerr << get_fileline() << ": warning: "
<< net->name();
if (net->word_index()) cerr << "[]";
cerr << "[" << lsv << "-:" << wid
<< "] is selecting after vector." << endl;
}
}
} else { } else {
// Return 'bx for an undefined base. // Return 'bx for an undefined base.
ex = new NetEConst(verinum(verinum::Vx, 1, false)); ex = new NetEConst(verinum(verinum::Vx, wid, true));
ex->set_line(*this);
delete base;
if (warn_ob_select) {
cerr << get_fileline() << ": warning: " << net->name();
if (net->word_index()) cerr << "[]";
cerr << "['bx-:" << wid
<< "] is always outside vector." << endl;
}
return ex;
} }
NetESelect*ss = new NetESelect(net, ex, wid); NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this); ss->set_line(*this);
@ -2824,16 +3027,19 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
return ss; return ss;
} }
long offset = net->lsi(); if (net->msi() > net->lsi()) {
NetExpr*base_adjusted = wid > 1 if (long offset = net->lsi()+wid-1)
? make_add_expr(base,1-(long)wid-offset) base = make_add_expr(base, -offset);
: (offset == 0? base : make_add_expr(base, 0-offset)); } else {
NetESelect*ss = new NetESelect(net, base_adjusted, wid); base = make_sub_expr(net->lsi(), base);
}
NetESelect*ss = new NetESelect(net, base, wid);
ss->set_line(*this); ss->set_line(*this);
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: Elaborate part " cerr << get_fileline() << ": debug: Elaborate part "
<< "select base="<< *base_adjusted << ", wid="<< wid << endl; << "select base="<< *base << ", wid="<< wid << endl;
} }
return ss; return ss;
@ -2932,6 +3138,16 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
if (! path_.back().index.empty()) if (! path_.back().index.empty())
use_sel = path_.back().index.back().sel; use_sel = path_.back().index.back().sel;
if (net->get_scalar() &&
use_sel != index_component_t::SEL_NONE) {
cerr << get_fileline() << ": error: can not select part of ";
if (node->expr_type() == IVL_VT_REAL) cerr << "real: ";
else cerr << "scalar: ";
cerr << net->name() << endl;
des->errors += 1;
return 0;
}
// If this is a part select of a signal, then make a new // If this is a part select of a signal, then make a new
// temporary signal that is connected to just the // temporary signal that is connected to just the
// selected bits. The lsb_ and msb_ expressions are from // selected bits. The lsb_ and msb_ expressions are from

View File

@ -118,17 +118,20 @@ NetAssign_* PEConcat::elaborate_lval(Design*des,
NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope, is_force); NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope, is_force);
if (tmp->expr_type() == IVL_VT_REAL) {
cerr << parms_[idx]->get_fileline() << ": error: "
<< "concatenation operand can not be real: "
<< *parms_[idx] << endl;
des->errors += 1;
continue;
}
/* If the l-value doesn't elaborate, the error was /* If the l-value doesn't elaborate, the error was
already detected and printed. We just skip it and let already detected and printed. We just skip it and let
the compiler catch more errors. */ the compiler catch more errors. */
if (tmp == 0) if (tmp == 0) continue;
continue;
assert(tmp);
/* Link the new l-value to the previous one. */ /* Link the new l-value to the previous one. */
NetAssign_*last = tmp; NetAssign_*last = tmp;
while (last->more) while (last->more)
last = last->more; last = last->more;
@ -195,6 +198,17 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
if (reg->array_dimensions() > 0) if (reg->array_dimensions() > 0)
return elaborate_lval_net_word_(des, scope, reg); return elaborate_lval_net_word_(des, scope, reg);
// This must be after the array word elaboration above!
if (reg->get_scalar() &&
use_sel != index_component_t::SEL_NONE) {
cerr << get_fileline() << ": error: can not select part of ";
if (reg->data_type() == IVL_VT_REAL) cerr << "real: ";
else cerr << "scalar: ";
cerr << reg->name() << endl;
des->errors += 1;
return 0;
}
if (use_sel == index_component_t::SEL_PART) { if (use_sel == index_component_t::SEL_PART) {
NetAssign_*lv = new NetAssign_(reg); NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_part_(des, scope, lv); elaborate_lval_net_part_(des, scope, lv);
@ -243,13 +257,11 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
ivl_assert(*this, index_head.msb != 0); ivl_assert(*this, index_head.msb != 0);
ivl_assert(*this, index_head.lsb == 0); ivl_assert(*this, index_head.lsb == 0);
// These are not used, but they need to have a default value.
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE; ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
// This not used, but it needs to have a default value.
bool unsized_flag_tmp = false; bool unsized_flag_tmp = false;
index_head.msb->test_width(des, scope, index_head.msb->test_width(des, scope, integer_width, integer_width,
reg->vector_width(), reg->vector_width(), expr_type_tmp, unsized_flag_tmp);
expr_type_tmp,
unsized_flag_tmp);
NetExpr*word = elab_and_eval(des, scope, index_head.msb, -1); NetExpr*word = elab_and_eval(des, scope, index_head.msb, -1);
@ -289,6 +301,20 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
if (name_tail.index.size() > 1) if (name_tail.index.size() > 1)
use_sel = name_tail.index.back().sel; use_sel = name_tail.index.back().sel;
if (reg->get_scalar() &&
use_sel != index_component_t::SEL_NONE) {
cerr << get_fileline() << ": error: can not select part of ";
if (reg->data_type() == IVL_VT_REAL) cerr << "real";
else cerr << "scalar";
cerr << " array word: " << reg->name()
<< "[" << *word << "]" << endl;
des->errors += 1;
return 0;
}
if (use_sel == index_component_t::SEL_BIT)
elaborate_lval_net_bit_(des, scope, lv);
if (use_sel == index_component_t::SEL_PART) if (use_sel == index_component_t::SEL_PART)
elaborate_lval_net_part_(des, scope, lv); elaborate_lval_net_part_(des, scope, lv);
@ -310,16 +336,14 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
NetNet*reg = lv->sig(); NetNet*reg = lv->sig();
// These are not used, but they need to have a default value.
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE; ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
// This not used, but it needs to have a default value.
bool unsized_flag_tmp = false; bool unsized_flag_tmp = false;
index_tail.msb->test_width(des, scope, index_tail.msb->test_width(des, scope, integer_width, integer_width,
lv->lwidth(), lv->lwidth(), expr_type_tmp, unsized_flag_tmp);
expr_type_tmp,
unsized_flag_tmp);
// Bit selects have a single select expression. Evaluate the // Bit selects have a single select expression. Evaluate the
// constant value and treat it as a part select with a bit // constant value and treat it as a part select with a bit
// width of 1. // width of 1.
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1); NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1);
@ -444,24 +468,86 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
unsigned long wid; unsigned long wid;
calculate_up_do_width_(des, scope, wid); calculate_up_do_width_(des, scope, wid);
// These are not used, but they need to have a default value.
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE; ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
// This not used, but it needs to have a default value.
bool unsized_flag_tmp = false; bool unsized_flag_tmp = false;
index_tail.msb->test_width(des, scope, index_tail.msb->test_width(des, scope, integer_width, integer_width,
wid, wid, expr_type_tmp, unsized_flag_tmp);
expr_type_tmp,
unsized_flag_tmp);
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1); NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
/* Correct the mux for the range of the vector. */ // Handle the special case that the base is constant. For this
if (reg->msb() < reg->lsb()) // case we can reduce the expression.
base = make_sub_expr(reg->lsb(), base); if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
else if (reg->lsb() != 0) // For the undefined case just let the constant pass and
base = make_add_expr(base, - reg->lsb()); // we will handle it in the code generator.
if (base_c->value().is_defined()) {
if (use_sel == index_component_t::SEL_IDX_DO && wid > 1 ) { long lsv = base_c->value().as_long();
base = make_add_expr(base, 1-(long)wid); long offset = 0;
if (((reg->msb() < reg->lsb()) &&
use_sel == index_component_t::SEL_IDX_UP) ||
((reg->msb() > reg->lsb()) &&
use_sel == index_component_t::SEL_IDX_DO)) {
offset = -wid + 1;
}
delete base;
base = new NetEConst(verinum(reg->sb_to_idx(lsv) + offset));
if (warn_ob_select) {
long rel_base = reg->sb_to_idx(lsv) + offset;
if (rel_base < 0) {
cerr << get_fileline() << ": warning: " << reg->name();
if (reg->array_dimensions() > 0) cerr << "[]";
cerr << "[" << lsv;
if (use_sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
} else {
cerr << "-:";
}
cerr << wid << "] is selecting before vector." << endl;
}
if (rel_base + wid > reg->vector_width()) {
cerr << get_fileline() << ": warning: " << reg->name();
if (reg->array_dimensions() > 0) cerr << "[]";
cerr << "[" << lsv;
if (use_sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
} else {
cerr << "-:";
}
cerr << wid << "] is selecting after vector." << endl;
}
}
} else {
if (warn_ob_select) {
cerr << get_fileline() << ": warning: " << reg->name();
if (reg->array_dimensions() > 0) cerr << "[]";
cerr << "['bx";
if (use_sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
} else {
cerr << "-:";
}
cerr << wid << "] is always outside vector." << endl;
}
}
} else {
/* Correct the mux for the range of the vector. */
if (use_sel == index_component_t::SEL_IDX_UP) {
if (reg->msb() > reg->lsb()) {
if (long offset = reg->lsb())
base = make_add_expr(base, -offset);
} else {
base = make_sub_expr(reg->lsb()-wid+1, base);
}
} else {
// This is assumed to be a SEL_IDX_DO.
if (reg->msb() > reg->lsb()) {
if (long offset = reg->lsb()+wid-1)
base = make_add_expr(base, -offset);
} else {
base = make_sub_expr(reg->lsb(), base);
}
}
} }
if (debug_elaborate) if (debug_elaborate)

View File

@ -72,10 +72,16 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
} else { } else {
nets[idx] = parms_[idx]->elaborate_lnet(des, scope); nets[idx] = parms_[idx]->elaborate_lnet(des, scope);
} }
if (nets[idx] == 0)
if (nets[idx] == 0) errors += 1;
else if (nets[idx]->data_type() == IVL_VT_REAL) {
cerr << parms_[idx]->get_fileline() << ": error: "
<< "concatenation operand can no be real: "
<< *parms_[idx] << endl;
errors += 1; errors += 1;
else continue;
width += nets[idx]->vector_width(); } else width += nets[idx]->vector_width();
} }
/* If any of the sub expressions failed to elaborate, then /* If any of the sub expressions failed to elaborate, then
@ -173,7 +179,7 @@ NetNet* PEIdent::make_implicit_net_(Design*des, NetScope*scope) const
assert(nettype != NetNet::NONE); assert(nettype != NetNet::NONE);
NetNet*sig = new NetNet(scope, peek_tail_name(path_), NetNet*sig = new NetNet(scope, peek_tail_name(path_),
NetNet::IMPLICIT, 1); nettype, 1);
sig->set_line(*this); sig->set_line(*this);
/* Implicit nets are always scalar logic. */ /* Implicit nets are always scalar logic. */
sig->data_type(IVL_VT_LOGIC); sig->data_type(IVL_VT_LOGIC);
@ -220,7 +226,9 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
case index_component_t::SEL_IDX_DO: case index_component_t::SEL_IDX_DO:
case index_component_t::SEL_IDX_UP: { case index_component_t::SEL_IDX_UP: {
need_constant_expr = true;
NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1); NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1);
need_constant_expr = false;
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex); NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
if (!tmp) { if (!tmp) {
cerr << get_fileline() << ": error: indexed part select of " cerr << get_fileline() << ": error: indexed part select of "
@ -230,15 +238,33 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
return 0; return 0;
} }
long midx_val = tmp->value().as_long();
midx = sig->sb_to_idx(midx_val);
delete tmp_ex;
/* The width (a constant) is calculated here. */ /* The width (a constant) is calculated here. */
unsigned long wid = 0; unsigned long wid = 0;
bool flag = calculate_up_do_width_(des, scope, wid); bool flag = calculate_up_do_width_(des, scope, wid);
if (! flag) if (! flag) return false;
/* We have an undefined index and that is out of range. */
if (! tmp->value().is_defined()) {
if (warn_ob_select) {
cerr << get_fileline() << ": warning: "
<< sig->name();
if (sig->array_dimensions() > 0) cerr << "[]";
cerr << "['bx";
if (index_tail.sel ==
index_component_t::SEL_IDX_UP) {
cerr << "+:";
} else {
cerr << "-:";
}
cerr << wid << "] is always outside vector."
<< endl;
}
return false; return false;
}
long midx_val = tmp->value().as_long();
midx = sig->sb_to_idx(midx_val);
delete tmp_ex;
if (index_tail.sel == index_component_t::SEL_IDX_UP) if (index_tail.sel == index_component_t::SEL_IDX_UP)
lidx = sig->sb_to_idx(midx_val+wid-1); lidx = sig->sb_to_idx(midx_val+wid-1);
@ -252,9 +278,19 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
} }
/* Warn about an indexed part select that is out of range. */ /* Warn about an indexed part select that is out of range. */
if (midx >= (long)sig->vector_width() || lidx < 0) { if (warn_ob_select && (lidx < 0)) {
cerr << get_fileline() << ": warning: Indexed part " cerr << get_fileline() << ": warning: " << sig->name();
"select " << sig->name(); if (sig->array_dimensions() > 0) cerr << "[]";
cerr << "[" << midx_val;
if (index_tail.sel == index_component_t::SEL_IDX_UP) {
cerr << "+:";
} else {
cerr << "-:";
}
cerr << wid << "] is selecting before vector." << endl;
}
if (warn_ob_select && (midx >= (long)sig->vector_width())) {
cerr << get_fileline() << ": warning: " << sig->name();
if (sig->array_dimensions() > 0) { if (sig->array_dimensions() > 0) {
cerr << "[]"; cerr << "[]";
} }
@ -264,7 +300,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
} else { } else {
cerr << "-:"; cerr << "-:";
} }
cerr << wid << "] is out of range." << endl; cerr << wid << "] is selecting after vector." << endl;
} }
/* This is completely out side the signal so just skip it. */ /* This is completely out side the signal so just skip it. */
@ -415,7 +451,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
// Default part select is the entire word. // Default part select is the entire word.
unsigned midx = sig->vector_width()-1, lidx = 0; unsigned midx = sig->vector_width()-1, lidx = 0;
// The default word select is the first. // The default word select is the first.
unsigned widx = 0; long widx = 0;
const name_component_t&name_tail = path_.back(); const name_component_t&name_tail = path_.back();
@ -437,7 +473,15 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
} }
ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT); ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT);
// These are not used, but they need to have a default value.
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
bool unsized_flag_tmp = false;
index_head.msb->test_width(des, scope,
integer_width, integer_width,
expr_type_tmp, unsized_flag_tmp);
need_constant_expr = true;
NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1); NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1);
need_constant_expr = false;
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex); NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
if (!tmp) { if (!tmp) {
cerr << get_fileline() << ": error: array " << sig->name() cerr << get_fileline() << ": error: array " << sig->name()
@ -456,6 +500,17 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
/* The array has a part/bit select at the end. */ /* The array has a part/bit select at the end. */
if (name_tail.index.size() > sig->array_dimensions()) { if (name_tail.index.size() > sig->array_dimensions()) {
if (sig->get_scalar()) {
cerr << get_fileline() << ": error: "
<< "can not select part of ";
if (sig->data_type() == IVL_VT_REAL) cerr << "real";
else cerr << "scalar";
cerr << " array word: " << sig->name()
<< "[" << widx_val << "]" << endl;
des->errors += 1;
return 0;
}
long midx_tmp, lidx_tmp; long midx_tmp, lidx_tmp;
if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp)) if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
return 0; return 0;
@ -471,6 +526,16 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
lidx = lidx_tmp; lidx = lidx_tmp;
} }
} else if (!name_tail.index.empty()) { } else if (!name_tail.index.empty()) {
if (sig->get_scalar()) {
cerr << get_fileline() << ": error: "
<< "can not select part of ";
if (sig->data_type() == IVL_VT_REAL) cerr << "real: ";
else cerr << "scalar: ";
cerr << sig->name() << endl;
des->errors += 1;
return 0;
}
long midx_tmp, lidx_tmp; long midx_tmp, lidx_tmp;
if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp)) if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
return 0; return 0;
@ -489,7 +554,12 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
unsigned subnet_wid = midx-lidx+1; unsigned subnet_wid = midx-lidx+1;
if (sig->pin_count() > 1) { if (sig->pin_count() > 1) {
assert(widx < sig->pin_count()); if (widx < 0 || widx >= (long) sig->pin_count()) {
cerr << get_fileline() << ": warning: ignoring out of "
"bounds l-value array access "
<< sig->name() << "[" << widx << "]." << endl;
return 0;
}
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet*tmp = new NetNet(scope, scope->local_symbol(),
sig->type(), sig->vector_width()); sig->type(), sig->vector_width());

View File

@ -150,11 +150,19 @@ NetEConcat* PEConcat::elaborate_pexpr(Design*des, NetScope*scope) const
/* Elaborate all the operands and attach them to the concat /* Elaborate all the operands and attach them to the concat
node. Use the elaborate_pexpr method instead of the node. Use the elaborate_pexpr method instead of the
elaborate_expr method. */ elaborate_expr method. */
bool fail = false;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
assert(parms_[idx]); assert(parms_[idx]);
NetExpr*ex = parms_[idx]->elaborate_pexpr(des, scope); NetExpr*ex = parms_[idx]->elaborate_pexpr(des, scope);
if (ex == 0) continue; if (ex == 0) continue;
if (ex->expr_type() == IVL_VT_REAL) {
cerr << ex->get_fileline() << ": error: concatenation "
<< "operand can not be real: " << *ex << endl;
des->errors += 1;
fail = true;
continue;
}
ex->set_line(*parms_[idx]); ex->set_line(*parms_[idx]);
if (dynamic_cast<NetEParam*>(ex)) { if (dynamic_cast<NetEParam*>(ex)) {
@ -167,13 +175,18 @@ NetEConcat* PEConcat::elaborate_pexpr(Design*des, NetScope*scope) const
<< "concatenation has indefinite width: " << "concatenation has indefinite width: "
<< *ex << endl; << *ex << endl;
des->errors += 1; des->errors += 1;
delete tmp; fail = true;
return 0; continue;
} }
tmp->set(idx, ex); tmp->set(idx, ex);
} }
if (fail) {
delete tmp;
return 0;
}
return tmp; return tmp;
} }
@ -194,6 +207,14 @@ NetExpr*PEIdent::elaborate_pexpr(Design*des, NetScope*scope) const
name_component_t name_tail = path_.back(); name_component_t name_tail = path_.back();
oldpath.pop_back(); oldpath.pop_back();
if (path_.size() > 1) {
cerr << get_fileline() << ": error: parameter r-value expression "
"does not support hierarchical references `" << path_
<< "`." << endl;
des->errors += 1;
return 0;
}
NetScope*pscope = scope; NetScope*pscope = scope;
if (path_.size() > 0) { if (path_.size() > 0) {
list<hname_t> tmp = eval_scope_path(des, scope, oldpath); list<hname_t> tmp = eval_scope_path(des, scope, oldpath);
@ -216,8 +237,9 @@ NetExpr*PEIdent::elaborate_pexpr(Design*des, NetScope*scope) const
ivl_assert(*this, pscope); ivl_assert(*this, pscope);
} }
if (ex == 0) { if (ex == 0) {
cerr << get_fileline() << ": error: identifier ``" << name_tail.name << cerr << get_fileline() << ": error: identifier `"
"'' is not a parameter in "<< scope_path(scope)<< "." << endl; << name_tail.name << "` is not a parameter in "
<< scope_path(scope)<< "." << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -174,6 +174,15 @@ static void elaborate_scope_parameters_(Design*des, NetScope*scope,
for (mparm_it_t cur = parameters.begin() for (mparm_it_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) { ; cur != parameters.end() ; cur ++) {
// A parameter can not have the same name as a genvar.
if (scope->find_genvar((*cur).first)) {
cerr << cur->second.get_fileline()
<< ": error: parameter and genvar in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
elaborate_parm_item_((*cur).first, (*cur).second, des, scope); elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
} }
} }
@ -184,6 +193,15 @@ static void elaborate_scope_localparams_(Design*des, NetScope*scope,
for (mparm_it_t cur = localparams.begin() for (mparm_it_t cur = localparams.begin()
; cur != localparams.end() ; cur ++) { ; cur != localparams.end() ; cur ++) {
// A localparam can not have the same name as a genvar.
if (scope->find_genvar((*cur).first)) {
cerr << cur->second.get_fileline()
<< ": error: localparam and genvar in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
elaborate_parm_item_((*cur).first, (*cur).second, des, scope); elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
} }
} }
@ -238,13 +256,38 @@ static void elaborate_scope_tasks(Design*des, NetScope*scope,
; cur != tasks.end() ; cur ++ ) { ; cur != tasks.end() ; cur ++ ) {
hname_t use_name( (*cur).first ); hname_t use_name( (*cur).first );
if (scope->child(use_name)) { // A task can not have the same name as another scope object.
cerr << loc.get_fileline() << ": error: task/scope name " const NetScope *child = scope->child(use_name);
<< use_name << " already used in this context." if (child) {
<< endl; cerr << cur->second->get_fileline() << ": error: task and ";
child->print_type(cerr);
cerr << " in '" << scope->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1; des->errors += 1;
continue; continue;
} }
// A task can not have the same name as a genvar.
if (scope->find_genvar((*cur).first)) {
cerr << cur->second->get_fileline()
<< ": error: task and genvar in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
// A task can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = scope->get_parameter((*cur).first, ex_msb,
ex_lsb);
if (parm) {
cerr << cur->second->get_fileline()
<< ": error: task and parameter in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
NetScope*task_scope = new NetScope(scope, use_name, NetScope*task_scope = new NetScope(scope, use_name,
NetScope::TASK); NetScope::TASK);
task_scope->is_auto((*cur).second->is_auto()); task_scope->is_auto((*cur).second->is_auto());
@ -268,13 +311,39 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope,
; cur != funcs.end() ; cur ++ ) { ; cur != funcs.end() ; cur ++ ) {
hname_t use_name( (*cur).first ); hname_t use_name( (*cur).first );
if (scope->child(use_name)) { // A function can not have the same name as another scope object.
cerr << loc.get_fileline() << ": error: function/scope name " const NetScope *child = scope->child(use_name);
<< use_name << " already used in this context." if (child) {
<< endl; cerr << cur->second->get_fileline()
<< ": error: function and ";
child->print_type(cerr);
cerr << " in '" << scope->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1; des->errors += 1;
continue; continue;
} }
// A function can not have the same name as a genvar.
if (scope->find_genvar((*cur).first)) {
cerr << cur->second->get_fileline()
<< ": error: function and genvar in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
// A function can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = scope->get_parameter((*cur).first, ex_msb,
ex_lsb);
if (parm) {
cerr << cur->second->get_fileline()
<< ": error: function and parameter in '"
<< scope->fullname() << "' have the same name '"
<< (*cur).first << "'." << endl;
des->errors += 1;
}
NetScope*func_scope = new NetScope(scope, use_name, NetScope*func_scope = new NetScope(scope, use_name,
NetScope::FUNC); NetScope::FUNC);
func_scope->is_auto((*cur).second->is_auto()); func_scope->is_auto((*cur).second->is_auto());
@ -328,6 +397,12 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
<< scope_path(scope) << "." << endl; << scope_path(scope) << "." << endl;
} }
// Add the genvars to the scope.
typedef map<perm_string,LineInfo*>::const_iterator genvar_it_t;
for (genvar_it_t cur = genvars.begin(); cur != genvars.end(); cur++ ) {
scope->add_genvar((*cur).first, (*cur).second);
}
// Generate all the parameters that this instance of this // Generate all the parameters that this instance of this
// module introduces to the design. This loop elaborates the // module introduces to the design. This loop elaborates the
// parameters, but doesn't evaluate references to // parameters, but doesn't evaluate references to
@ -446,6 +521,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
elaborate_scope_events_(des, scope, events); elaborate_scope_events_(des, scope, events);
scope->is_cell(is_cell);
return des->errors == 0; return des->errors == 0;
} }
@ -486,8 +563,16 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
{ {
// Check that the loop_index variable was declared in a // Check that the loop_index variable was declared in a
// genvar statement. // genvar statement.
NetScope*scope = container;
// MISSING CODE! while (scope && !scope->find_genvar(loop_index))
scope = scope->parent();
if (!scope) {
cerr << get_fileline() << ": error: genvar is missing for "
"generate \"loop\" variable '" << loop_index << "'."
<< endl;
des->errors += 1;
return false;
}
// We're going to need a genvar... // We're going to need a genvar...
int genvar; int genvar;
@ -496,7 +581,9 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
// use) the genvar itself, so we can evaluate this expression // use) the genvar itself, so we can evaluate this expression
// the same way any other parameter value is evaluated. // the same way any other parameter value is evaluated.
probe_expr_width(des, container, loop_init); probe_expr_width(des, container, loop_init);
need_constant_expr = true;
NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1); NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1);
need_constant_expr = false;
NetEConst*init = dynamic_cast<NetEConst*> (init_ex); NetEConst*init = dynamic_cast<NetEConst*> (init_ex);
if (init == 0) { if (init == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar" cerr << get_fileline() << ": error: Cannot evaluate genvar"
@ -505,19 +592,53 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
return false; return false;
} }
// Since we will be adding the genvar value as a local parameter // Check the generate block name.
// to each instances scope. We need to make sure a parameter does
// not already exist. // A generate "loop" can not have the same name as another scope object.
const NetExpr*tmsb; const NetScope *child = container->child(hname_t(scope_name));
const NetExpr*tlsb; if (child) {
const NetExpr*texpr = container->get_parameter(loop_index, tmsb, tlsb); cerr << get_fileline() << ": error: generate \"loop\" and ";
if (texpr != 0) { child->print_type(cerr);
cerr << get_fileline() << ": error: Cannot have a genvar " cerr << " in '" << container->fullname()
<< "and parameter with the same name: " << loop_index << endl; << "' have the same name '" << scope_name << "'." << endl;
des->errors += 1; des->errors += 1;
return false; return false;
} }
// A generate "loop" can not have the same name as a genvar.
if (container->find_genvar(scope_name)) {
cerr << get_fileline() << ": error: generate \"loop\" and "
"genvar in '" << container->fullname()
<< "' have the same name '" << scope_name << "'." << endl;
des->errors += 1;
}
// A generate "loop" can not have the same name as a named event.
const NetEvent *event = container->find_event(scope_name);
if (event) {
cerr << get_fileline() << ": error: generate \"loop\" and "
"named event in '" << container->fullname()
<< "' have the same name '" << scope_name << "'." << endl;
des->errors += 1;
}
// A generate "loop" can not have the same name as a parameter.
const NetExpr*tmsb;
const NetExpr*tlsb;
const NetExpr*texpr = container->get_parameter(scope_name, tmsb, tlsb);
if (texpr != 0) {
cerr << get_fileline() << ": error: generate \"loop\" and "
"parameter in '" << container->fullname()
<< "' have the same name '" << scope_name << "'." << endl;
des->errors += 1;
}
// These have all been checked so we just need to skip the actual
// generation for these name conflicts. Not skipping these two will
// cause the compiler to have problems (assert, inf. loop, etc.).
if (container->get_parameter(loop_index, tmsb, tlsb)) return false;
if (container->find_event(loop_index)) return false;
genvar = init->value().as_long(); genvar = init->value().as_long();
delete init_ex; delete init_ex;
@ -526,7 +647,9 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
container->genvar_tmp = loop_index; container->genvar_tmp = loop_index;
container->genvar_tmp_val = genvar; container->genvar_tmp_val = genvar;
probe_expr_width(des, container, loop_test); probe_expr_width(des, container, loop_test);
need_constant_expr = true;
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1); NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
need_constant_expr = false;
NetEConst*test = dynamic_cast<NetEConst*>(test_ex); NetEConst*test = dynamic_cast<NetEConst*>(test_ex);
if (test == 0) { if (test == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar" cerr << get_fileline() << ": error: Cannot evaluate genvar"
@ -541,13 +664,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
// container. The format of using [] is part of the // container. The format of using [] is part of the
// Verilog standard. // Verilog standard.
hname_t use_name (scope_name, genvar); hname_t use_name (scope_name, genvar);
if (container->child(use_name)) {
cerr << get_fileline() << ": error: block/scope name "
<< use_name << " already used in this context."
<< endl;
des->errors += 1;
return false;
}
if (debug_scopes) if (debug_scopes)
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
<< "Create generated scope " << use_name << endl; << "Create generated scope " << use_name << endl;
@ -579,7 +696,9 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
// Calculate the step for the loop variable. // Calculate the step for the loop variable.
probe_expr_width(des, container, loop_step); probe_expr_width(des, container, loop_step);
need_constant_expr = true;
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1); NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1);
need_constant_expr = false;
NetEConst*step = dynamic_cast<NetEConst*>(step_ex); NetEConst*step = dynamic_cast<NetEConst*>(step_ex);
if (step == 0) { if (step == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar" cerr << get_fileline() << ": error: Cannot evaluate genvar"
@ -602,7 +721,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
} }
// Clear the genvar_tmp field in the scope to reflect that the // Clear the genvar_tmp field in the scope to reflect that the
// genvar is no longer value for evaluating expressions. // genvar is no longer valid for evaluating expressions.
container->genvar_tmp = perm_string(); container->genvar_tmp = perm_string();
return true; return true;
@ -611,7 +730,9 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else_flag) bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else_flag)
{ {
probe_expr_width(des, container, loop_test); probe_expr_width(des, container, loop_test);
need_constant_expr = true;
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1); NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
need_constant_expr = false;
NetEConst*test = dynamic_cast<NetEConst*> (test_ex); NetEConst*test = dynamic_cast<NetEConst*> (test_ex);
if (test == 0) { if (test == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar" cerr << get_fileline() << ": error: Cannot evaluate genvar"
@ -634,14 +755,45 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
} }
hname_t use_name (scope_name); hname_t use_name (scope_name);
if (container->child(use_name)) { // A generate "if" can not have the same name as another scope object.
cerr << get_fileline() << ": error: block/scope name " const NetScope *child = container->child(use_name);
<< scope_name << " already used in this context." if (child) {
<< endl; cerr << get_fileline() << ": error: generate \"if\" and ";
child->print_type(cerr);
cerr << " in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1; des->errors += 1;
return false; return false;
} }
// A generate "if" can not have the same name as a genvar.
if (container->find_genvar(scope_name)) {
cerr << get_fileline() << ": error: generate \"if\" and "
"genvar in '" << container->fullname()
<< "' have the same name '" << scope_name << "'." << endl;
des->errors += 1;
}
// A generate "if" can not have the same name as a named event.
const NetEvent *event = container->find_event(scope_name);
if (event) {
cerr << get_fileline() << ": error: generate \"if\" and "
"named event in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
// A generate "if" can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = container->get_parameter(scope_name, ex_msb,
ex_lsb);
if (parm) {
cerr << get_fileline() << ": error: generate \"if\" and "
"parameter in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
if (debug_scopes) if (debug_scopes)
cerr << get_fileline() << ": debug: Generate condition " cerr << get_fileline() << ": debug: Generate condition "
<< (else_flag? "(else)" : "(if)") << (else_flag? "(else)" : "(if)")
@ -671,7 +823,9 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
bool PGenerate::generate_scope_case_(Design*des, NetScope*container) bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
{ {
probe_expr_width(des, container, loop_test); probe_expr_width(des, container, loop_test);
need_constant_expr = true;
NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1); NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1);
need_constant_expr = false;
NetEConst*case_value_co = dynamic_cast<NetEConst*>(case_value_ex); NetEConst*case_value_co = dynamic_cast<NetEConst*>(case_value_ex);
if (case_value_co == 0) { if (case_value_co == 0) {
cerr << get_fileline() << ": error: Cannot evaluate genvar case" cerr << get_fileline() << ": error: Cannot evaluate genvar case"
@ -702,9 +856,17 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
bool match_flag = false; bool match_flag = false;
for (unsigned idx = 0 ; idx < item->item_test.size() && !match_flag ; idx +=1 ) { for (unsigned idx = 0 ; idx < item->item_test.size() && !match_flag ; idx +=1 ) {
probe_expr_width(des, container, item->item_test[idx]); probe_expr_width(des, container, item->item_test[idx]);
need_constant_expr = true;
NetExpr*item_value_ex = elab_and_eval(des, container, item->item_test[idx], -1); NetExpr*item_value_ex = elab_and_eval(des, container, item->item_test[idx], -1);
need_constant_expr = false;
NetEConst*item_value_co = dynamic_cast<NetEConst*>(item_value_ex); NetEConst*item_value_co = dynamic_cast<NetEConst*>(item_value_ex);
assert(item_value_co); if (item_value_co == 0) {
cerr << get_fileline() << ": error: Cannot evaluate "
<< " genvar case item expression: "
<< *item->item_test[idx] << endl;
des->errors += 1;
return false;
}
if (debug_scopes) if (debug_scopes)
cerr << get_fileline() << ": debug: Generate case " cerr << get_fileline() << ": debug: Generate case "
@ -739,6 +901,44 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
// The name of the scope to generate, whatever that item is. // The name of the scope to generate, whatever that item is.
hname_t use_name (item->scope_name); hname_t use_name (item->scope_name);
// A generate "case" can not have the same name as another scope object.
const NetScope *child = container->child(use_name);
if (child) {
cerr << get_fileline() << ": error: generate \"case\" and ";
child->print_type(cerr);
cerr << " in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
return false;
}
// A generate "case" can not have the same name as a genvar.
if (container->find_genvar(item->scope_name)) {
cerr << get_fileline() << ": error: generate \"case\" and "
"genvar in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
// A generate "case" can not have the same name as a named event.
const NetEvent *event = container->find_event(item->scope_name);
if (event) {
cerr << get_fileline() << ": error: generate \"case\" and "
"named event in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
// A generate "case" can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = container->get_parameter(item->scope_name, ex_msb,
ex_lsb);
if (parm) {
cerr << get_fileline() << ": error: generate \"case\" and "
"parameter in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
item->probe_for_direct_nesting_(); item->probe_for_direct_nesting_();
if (item->direct_nested_) { if (item->direct_nested_) {
@ -760,13 +960,46 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container) bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container)
{ {
hname_t use_name (scope_name); hname_t use_name (scope_name);
if (container->child(use_name)) { // A generate "block" can not have the same name as another scope
cerr << get_fileline() << ": error: block/scope name " // object.
<< scope_name << " already used in this context." const NetScope *child = container->child(use_name);
<< endl; if (child) {
cerr << get_fileline() << ": error: generate \"block\" and ";
child->print_type(cerr);
cerr << " in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1; des->errors += 1;
return false; return false;
} }
// A generate "block" can not have the same name as a genvar.
if (container->find_genvar(scope_name)) {
cerr << get_fileline() << ": error: generate \"block\" and "
"genvar in '" << container->fullname()
<< "' have the same name '" << scope_name << "'." << endl;
des->errors += 1;
}
// A generate "block" can not have the same name as a named event.
const NetEvent *event = container->find_event(scope_name);
if (event) {
cerr << get_fileline() << ": error: generate \"block\" and "
"named event in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
// A generate "block" can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = container->get_parameter(scope_name, ex_msb,
ex_lsb);
if (parm) {
cerr << get_fileline() << ": error: generate \"block\" and "
"parameter in '" << container->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
if (debug_scopes) if (debug_scopes)
cerr << get_fileline() << ": debug: Generate named block " cerr << get_fileline() << ": debug: Generate named block "
<< ": Generate scope=" << use_name << endl; << ": Generate scope=" << use_name << endl;
@ -791,6 +1024,12 @@ void PGenerate::elaborate_subscope_direct_(Design*des, NetScope*scope)
void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
{ {
// Add the genvars to this scope.
typedef map<perm_string,LineInfo*>::const_iterator genvar_it_t;
for (genvar_it_t cur = genvars.begin(); cur != genvars.end(); cur++ ) {
scope->add_genvar((*cur).first, (*cur).second);
}
// Scan the generated scope for nested generate schemes, // Scan the generated scope for nested generate schemes,
// and *generate* new scopes, which is slightly different // and *generate* new scopes, which is slightly different
// from simple elaboration. // from simple elaboration.
@ -886,36 +1125,77 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
// Missing module instance names have already been rejected. // Missing module instance names have already been rejected.
assert(get_name() != ""); assert(get_name() != "");
// Check for duplicate scopes. Simply look up the scope I'm // A module instance can not have the same name as another scope object.
// about to create, and if I find it then somebody beat me to const NetScope *child = sc->child(hname_t(get_name()));
// it. if (child) {
cerr << get_fileline() << ": error: module <" << mod->mod_name()
if (sc->child(hname_t(get_name()))) { << "> instance and ";
cerr << get_fileline() << ": error: Instance/Scope name " << child->print_type(cerr);
get_name() << " already used in this context." << cerr << " in '" << sc->fullname()
endl; << "' have the same name '" << get_name() << "'." << endl;
des->errors += 1; des->errors += 1;
return; return;
} }
// A module instance can not have the same name as a genvar.
if (sc->find_genvar(get_name())) {
cerr << get_fileline() << ": error: module <" << mod->mod_name()
<< "> instance and genvar in '" << sc->fullname()
<< "' have the same name '" << get_name() << "'." << endl;
des->errors += 1;
}
// A module instance can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = sc->get_parameter(get_name(), ex_msb, ex_lsb);
if (parm) {
cerr << get_fileline() << ": error: module <" << mod->mod_name()
<< "> instance and parameter in '" << sc->fullname()
<< "' have the same name '" << get_name() << "'." << endl;
des->errors += 1;
}
// check for recursive instantiation by scanning the current // check for recursive instantiation by scanning the current
// scope and its parents. Look for a module instantiation of // scope and its parents. Look for a module instantiation of
// the same module, but farther up in the scope. // the same module, but farther up in the scope.
unsigned rl_count = 0;
bool in_genblk = false;
for (NetScope*scn = sc ; scn ; scn = scn->parent()) { for (NetScope*scn = sc ; scn ; scn = scn->parent()) {
if (scn->type() != NetScope::MODULE) // We need to know if we are inside a generate block to allow
// recursive instances.
if (scn->type() == NetScope::GENBLOCK) {
in_genblk = true;
continue; continue;
}
if (strcmp(mod->mod_name(), scn->module_name()) != 0) if (scn->type() != NetScope::MODULE) continue;
if (strcmp(mod->mod_name(), scn->module_name()) != 0) continue;
// We allow nested scopes if they are inside a generate block,
// but only to a certain nesting depth.
if (in_genblk) {
rl_count += 1;
if (rl_count > recursive_mod_limit) {
cerr << get_fileline() << ": error: instance "
<< scope_path(sc) << "." << get_name()
<< " of module " << mod->mod_name()
<< " is nested too deep." << endl;
cerr << get_fileline() << ": : check for "
"proper recursion termination or increase the "
"limit (" << recursive_mod_limit
<< ") with the -pRECURSIVE_MOD_LIMIT flag."
<< endl;
des->errors += 1;
return;
}
continue; continue;
}
cerr << get_fileline() << ": error: You cannot instantiate " cerr << get_fileline() << ": error: You cannot instantiate "
<< "module " << mod->mod_name() << " within itself." << endl; << "module " << mod->mod_name() << " within itself." << endl;
cerr << get_fileline() << ": : The offending instance is " cerr << get_fileline() << ": : The offending instance is "
<< scope_path(sc) << "." << get_name() << " within " << get_name() << " within " << scope_path(scn) << "." << endl;
<< scope_path(scn) << "." << endl;
des->errors += 1; des->errors += 1;
return; return;
} }
@ -952,8 +1232,10 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
{ {
if (msb_) probe_expr_width(des, sc, msb_); if (msb_) probe_expr_width(des, sc, msb_);
if (lsb_) probe_expr_width(des, sc, lsb_); if (lsb_) probe_expr_width(des, sc, lsb_);
need_constant_expr = true;
NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0; NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0;
NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0; NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0;
need_constant_expr = false;
NetEConst*msb = dynamic_cast<NetEConst*> (mse); NetEConst*msb = dynamic_cast<NetEConst*> (mse);
NetEConst*lsb = dynamic_cast<NetEConst*> (lse); NetEConst*lsb = dynamic_cast<NetEConst*> (lse);
@ -1019,6 +1301,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
// Set time units and precision. // Set time units and precision.
my_scope->time_unit(mod->time_unit); my_scope->time_unit(mod->time_unit);
my_scope->time_precision(mod->time_precision); my_scope->time_precision(mod->time_precision);
my_scope->time_from_timescale(mod->time_from_timescale);
des->set_precision(mod->time_precision); des->set_precision(mod->time_precision);
// Look for module parameter replacements. The "replace" map // Look for module parameter replacements. The "replace" map
@ -1109,6 +1392,34 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
*/ */
void PEvent::elaborate_scope(Design*des, NetScope*scope) const void PEvent::elaborate_scope(Design*des, NetScope*scope) const
{ {
// A named event can not have the same name as another scope object.
const NetScope *child = scope->child(hname_t(name_));
if (child) {
cerr << get_fileline() << ": error: named event and ";
child->print_type(cerr);
cerr << " in '" << scope->fullname()
<< "' have the same name '" << name_ << "'." << endl;
des->errors += 1;
}
// A named event can not have the same name as a genvar.
if (scope->find_genvar(name_)) {
cerr << get_fileline() << ": error: named event and "
<< "genvar in '" << scope->fullname()
<< "' have the same name '" << name_ << "'." << endl;
des->errors += 1;
}
// A named event can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = scope->get_parameter(name_, ex_msb, ex_lsb);
if (parm) {
cerr << get_fileline() << ": error: named event and "
<< "parameter in '" << scope->fullname()
<< "' have the same name '" << name_ << "'." << endl;
des->errors += 1;
}
NetEvent*ev = new NetEvent(name_); NetEvent*ev = new NetEvent(name_);
ev->set_line(*this); ev->set_line(*this);
scope->add_event(ev); scope->add_event(ev);
@ -1189,13 +1500,37 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
if (pscope_name() != 0) { if (pscope_name() != 0) {
hname_t use_name(pscope_name()); hname_t use_name(pscope_name());
if (scope->child(use_name)) { // A named block can not have the same name as another scope
cerr << get_fileline() << ": error: block/scope name " // object.
<< use_name << " already used in this context." const NetScope *child = scope->child(use_name);
<< endl; if (child) {
cerr << get_fileline() << ": error: named block and ";
child->print_type(cerr);
cerr << " in '" << scope->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1; des->errors += 1;
return; return;
} }
// A named block can not have the same name as a genvar.
if (scope->find_genvar(pscope_name())) {
cerr << get_fileline() << ": error: named block and "
"genvar in '" << scope->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
// A named block can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = scope->get_parameter(pscope_name(), ex_msb,
ex_lsb);
if (parm) {
cerr << get_fileline() << ": error: named block and "
"parameter in '" << scope->fullname()
<< "' have the same name '" << use_name << "'." << endl;
des->errors += 1;
}
if (debug_scopes) if (debug_scopes)
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
<< "Elaborate block scope " << use_name << "Elaborate block scope " << use_name

View File

@ -126,7 +126,7 @@ static void elaborate_sig_funcs(Design*des, NetScope*scope,
hname_t use_name ( (*cur).first ); hname_t use_name ( (*cur).first );
NetScope*fscope = scope->child(use_name); NetScope*fscope = scope->child(use_name);
if (scope == 0) { if (fscope == 0) {
cerr << (*cur).second->get_fileline() << ": internal error: " cerr << (*cur).second->get_fileline() << ": internal error: "
<< "Child scope for function " << (*cur).first << "Child scope for function " << (*cur).first
<< " missing in " << scope_path(scope) << "." << endl; << " missing in " << scope_path(scope) << "." << endl;
@ -599,9 +599,11 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
} }
ret_sig = new NetNet(scope, fname, NetNet::REG, mnum, lnum); ret_sig = new NetNet(scope, fname, NetNet::REG, mnum, lnum);
ret_sig->set_scalar(false);
} else { } else {
ret_sig = new NetNet(scope, fname, NetNet::REG); ret_sig = new NetNet(scope, fname, NetNet::REG);
ret_sig->set_scalar(true);
} }
ret_sig->set_line(*this); ret_sig->set_line(*this);
ret_sig->set_signed(return_type_.type == PTF_REG_S); ret_sig->set_signed(return_type_.type == PTF_REG_S);
@ -614,6 +616,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
ret_sig->set_line(*this); ret_sig->set_line(*this);
ret_sig->set_signed(true); ret_sig->set_signed(true);
ret_sig->set_isint(true); ret_sig->set_isint(true);
ret_sig->set_scalar(false);
ret_sig->port_type(NetNet::POUTPUT); ret_sig->port_type(NetNet::POUTPUT);
ret_sig->data_type(IVL_VT_LOGIC); ret_sig->data_type(IVL_VT_LOGIC);
break; break;
@ -623,6 +626,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
ret_sig->set_line(*this); ret_sig->set_line(*this);
ret_sig->set_signed(false); ret_sig->set_signed(false);
ret_sig->set_isint(false); ret_sig->set_isint(false);
ret_sig->set_scalar(false);
ret_sig->port_type(NetNet::POUTPUT); ret_sig->port_type(NetNet::POUTPUT);
ret_sig->data_type(IVL_VT_LOGIC); ret_sig->data_type(IVL_VT_LOGIC);
break; break;
@ -633,6 +637,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
ret_sig->set_line(*this); ret_sig->set_line(*this);
ret_sig->set_signed(true); ret_sig->set_signed(true);
ret_sig->set_isint(false); ret_sig->set_isint(false);
ret_sig->set_scalar(true);
ret_sig->port_type(NetNet::POUTPUT); ret_sig->port_type(NetNet::POUTPUT);
ret_sig->data_type(IVL_VT_REAL); ret_sig->data_type(IVL_VT_REAL);
break; break;
@ -843,23 +848,63 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const
/* /*
* Elaborate a source wire. The "wire" is the declaration of wires, * Elaborate a source wire. The "wire" is the declaration of wires,
* registers, ports and memories. The parser has already merged the * registers, ports and memories. The parser has already merged the
* multiple properties of a wire (i.e., "input wire") so come the * multiple properties of a wire (i.e., "input wire"), so come the
* elaboration this creates an object in the design that represent the * elaboration this creates an object in the design that represents the
* defined item. * defined item.
*/ */
NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
{ {
NetNet::Type wtype = type_; NetNet::Type wtype = type_;
if (wtype == NetNet::IMPLICIT) bool is_implicit_scalar = false;
if (wtype == NetNet::IMPLICIT) {
wtype = NetNet::WIRE; wtype = NetNet::WIRE;
if (wtype == NetNet::IMPLICIT_REG) is_implicit_scalar = true;
}
if (wtype == NetNet::IMPLICIT_REG) {
wtype = NetNet::REG; wtype = NetNet::REG;
is_implicit_scalar = true;
}
unsigned wid = 1; unsigned wid = 1;
long lsb = 0, msb = 0; long lsb = 0, msb = 0;
des->errors += error_cnt_; des->errors += error_cnt_;
// A signal can not have the same name as a scope object.
const NetScope *child = scope->child(hname_t(name_));
if (child) {
cerr << get_fileline() << ": error: signal and ";
child->print_type(cerr);
cerr << " in '" << scope->fullname()
<< "' have the same name '" << name_ << "'." << endl;
des->errors += 1;
}
// A signal can not have the same name as a genvar.
const LineInfo *genvar = scope->find_genvar(name_);
if (genvar) {
cerr << get_fileline() << ": error: signal and genvar in '"
<< scope->fullname() << "' have the same name '" << name_
<< "'." << endl;
des->errors += 1;
}
// A signal can not have the same name as a parameter.
const NetExpr *ex_msb, *ex_lsb;
const NetExpr *parm = scope->get_parameter(name_, ex_msb, ex_lsb);
if (parm) {
cerr << get_fileline() << ": error: signal and parameter in '"
<< scope->fullname() << "' have the same name '" << name_
<< "'." << endl;
des->errors += 1;
}
// A signal can not have the same name as a named event.
const NetEvent *event = scope->find_event(name_);
if (event) {
cerr << get_fileline() << ": error: signal and named event in '"
<< scope->fullname() << "' have the same name '" << name_
<< "'." << endl;
des->errors += 1;
}
if (port_set_ || net_set_) { if (port_set_ || net_set_) {
long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0; long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0;
bool bad_lsb = false, bad_msb = false; bool bad_lsb = false, bad_msb = false;
@ -902,6 +947,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
delete texpr; delete texpr;
nmsb = pmsb; nmsb = pmsb;
nlsb = plsb; nlsb = plsb;
/* An implicit port can have a range so note that here. */
is_implicit_scalar = false;
} }
if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0); if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0);
if (port_msb_ == 0) assert(port_lsb_ == 0); if (port_msb_ == 0) assert(port_lsb_ == 0);
@ -1095,8 +1142,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
} }
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " cerr << get_fileline() << ": debug: Create signal " << wtype;
<< wtype << " ["<<msb<<":"<<lsb<<"] " << name_; if (!get_scalar()) {
cerr << " ["<<msb<<":"<<lsb<<"]";
}
cerr << " " << name_;
if (array_dimensions > 0) { if (array_dimensions > 0) {
cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl;
} }
@ -1108,6 +1158,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0)
: new NetNet(scope, name_, wtype, msb, lsb); : new NetNet(scope, name_, wtype, msb, lsb);
if (wtype == NetNet::WIRE) sig->devirtualize_pins();
ivl_variable_type_t use_data_type = data_type_; ivl_variable_type_t use_data_type = data_type_;
if (use_data_type == IVL_VT_NO_TYPE) { if (use_data_type == IVL_VT_NO_TYPE) {
use_data_type = IVL_VT_LOGIC; use_data_type = IVL_VT_LOGIC;
@ -1124,6 +1176,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
sig->port_type(port_type_); sig->port_type(port_type_);
sig->set_signed(get_signed()); sig->set_signed(get_signed());
sig->set_isint(get_isint()); sig->set_isint(get_isint());
if (is_implicit_scalar) sig->set_scalar(true);
else sig->set_scalar(get_scalar());
if (ivl_discipline_t dis = get_discipline()) { if (ivl_discipline_t dis = get_discipline()) {
sig->set_discipline(dis); sig->set_discipline(dis);

View File

@ -189,6 +189,14 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
need_driver_flag = false; need_driver_flag = false;
} }
/* When we are given a non-default strength value and if the
* drive source is a bit, part or indexed select we need to
* add a driver (BUFZ) to convey the strength information. */
if ((drive0 != Link::STRONG || drive1 != Link::STRONG) &&
(dynamic_cast<NetESelect*>(rval_expr))) {
need_driver_flag = true;
}
if (need_driver_flag) { if (need_driver_flag) {
NetBUFZ*driver = new NetBUFZ(scope, scope->local_symbol(), NetBUFZ*driver = new NetBUFZ(scope, scope->local_symbol(),
rval->vector_width()); rval->vector_width());
@ -234,8 +242,10 @@ unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
gates, then I am expected to make more than one gates, then I am expected to make more than one
gate. Figure out how many are desired. */ gate. Figure out how many are desired. */
if (msb_) { if (msb_) {
need_constant_expr = true;
NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1); NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1);
NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1); NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1);
need_constant_expr = false;
NetEConst*msb_con = dynamic_cast<NetEConst*>(msb_exp); NetEConst*msb_con = dynamic_cast<NetEConst*>(msb_exp);
NetEConst*lsb_con = dynamic_cast<NetEConst*>(lsb_exp); NetEConst*lsb_con = dynamic_cast<NetEConst*>(lsb_exp);
@ -623,7 +633,9 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
return; return;
} }
lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope); lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope);
ivl_assert(*this, lval_sigs[idx]); // The only way this should return zero is if an error
// happened, so for that case just return.
if (lval_sigs[idx] == 0) return;
// For now, assume all the outputs are the same width. // For now, assume all the outputs are the same width.
ivl_assert(*this, idx == 0 || lval_sigs[idx]->vector_width() == lval_sigs[0]->vector_width()); ivl_assert(*this, idx == 0 || lval_sigs[idx]->vector_width() == lval_sigs[0]->vector_width());
@ -966,6 +978,28 @@ static bool need_bufz_for_input_port(const vector<NetNet*>&prts)
return false; return false;
} }
/*
* Convert a wire or tri to a tri0 or tri1 as needed to make
* an unconnected drive pull for floating inputs.
*/
static void convert_net(Design*des, const LineInfo *line,
NetNet *net, NetNet::Type type)
{
// If the types already match just return.
if (net->type() == type) return;
// We can only covert a wire or tri to have a default pull.
if (net->type() == NetNet::WIRE || net->type() == NetNet::TRI) {
net->type(type);
return;
}
// We may have to support this at some point in time!
cerr << line->get_fileline() << ": sorry: Can not pull floating "
"input type '" << net->type() << "'." << endl;
des->errors += 1;
}
/* /*
* Instantiate a module by recursively elaborating it. Set the path of * Instantiate a module by recursively elaborating it. Set the path of
* the recursive elaboration so that signal names get properly * the recursive elaboration so that signal names get properly
@ -1058,7 +1092,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// No named bindings, just use the positional list I // No named bindings, just use the positional list I
// already have. // already have.
assert(pin_count() == rmod->port_count()); ivl_assert(*this, pin_count() == rmod->port_count());
pins = get_pins(); pins = get_pins();
} }
@ -1093,28 +1127,50 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// null parameter is passed in. // null parameter is passed in.
if (pins[idx] == 0) { if (pins[idx] == 0) {
// We need this information to support the
// unconnected_drive directive and for a
// unconnected input warning when asked for.
vector<PEIdent*> mport = rmod->get_port(idx);
if (mport.size() == 0) continue;
// While we're here, look to see if this perm_string pname = peek_tail_name(mport[0]->path());
// unconnected (from the outside) port is an
// input. If so, consider printing a port binding
// warning.
if (warn_portbinding) {
vector<PEIdent*> mport = rmod->get_port(idx);
if (mport.size() == 0)
continue;
perm_string pname = peek_tail_name(mport[0]->path()); NetNet*tmp = instance[0]->find_signal(pname);
ivl_assert(*this, tmp);
NetNet*tmp = instance[0]->find_signal(pname); if (tmp->port_type() == NetNet::PINPUT) {
assert(tmp); // If we have an unconnected input convert it
// as needed if an unconnected_drive directive
// was given. This only works for tri or wire!
switch (rmod->uc_drive) {
case Module::UCD_PULL0:
convert_net(des, this, tmp, NetNet::TRI0);
break;
case Module::UCD_PULL1:
convert_net(des, this, tmp, NetNet::TRI1);
break;
case Module::UCD_NONE:
break;
}
if (tmp->port_type() == NetNet::PINPUT) { // Print a waring for an unconnected input.
if (warn_portbinding) {
cerr << get_fileline() << ": warning: " cerr << get_fileline() << ": warning: "
<< "Instantiating module " << "Instantiating module "
<< rmod->mod_name() << rmod->mod_name()
<< " with dangling input port " << " with dangling input port '"
<< rmod->ports[idx]->name << rmod->ports[idx]->name;
<< "." << endl; switch (rmod->uc_drive) {
case Module::UCD_PULL0:
cerr << "' (pulled low)." << endl;
break;
case Module::UCD_PULL1:
cerr << "' (pulled high)." << endl;
break;
case Module::UCD_NONE:
cerr << "' (floating)." << endl;
break;
}
} }
} }
@ -1146,13 +1202,13 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
for (unsigned ldx = 0 ; ldx < mport.size() ; ldx += 1) { for (unsigned ldx = 0 ; ldx < mport.size() ; ldx += 1) {
unsigned lbase = inst * mport.size(); unsigned lbase = inst * mport.size();
PEIdent*pport = mport[ldx]; PEIdent*pport = mport[ldx];
assert(pport); ivl_assert(*this, pport);
prts[lbase + ldx] prts[lbase + ldx]
= pport->elaborate_port(des, inst_scope); = pport->elaborate_port(des, inst_scope);
if (prts[lbase + ldx] == 0) if (prts[lbase + ldx] == 0)
continue; continue;
assert(prts[lbase + ldx]); ivl_assert(*this, prts[lbase + ldx]);
prts_vector_width += prts[lbase + ldx]->vector_width(); prts_vector_width += prts[lbase + ldx]->vector_width();
} }
} }
@ -1167,7 +1223,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// We know by design that each instance has the same // We know by design that each instance has the same
// width port. Therefore, the prts_pin_count must be an // width port. Therefore, the prts_pin_count must be an
// even multiple of the instance count. // even multiple of the instance count.
assert(prts_vector_width % instance.size() == 0); ivl_assert(*this, prts_vector_width % instance.size() == 0);
unsigned desired_vector_width = prts_vector_width; unsigned desired_vector_width = prts_vector_width;
if (instance.size() != 1) if (instance.size() != 1)
@ -1284,12 +1340,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
} }
assert(sig); ivl_assert(*this, sig);
#ifndef NDEBUG #ifndef NDEBUG
if ((prts.size() >= 1) if ((prts.size() >= 1)
&& (prts[0]->port_type() != NetNet::PINPUT)) { && (prts[0]->port_type() != NetNet::PINPUT)) {
assert(sig->type() != NetNet::REG); ivl_assert(*this, sig->type() != NetNet::REG);
} }
#endif #endif
@ -1515,43 +1571,34 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
module or primitive, it interprets them as parameter module or primitive, it interprets them as parameter
overrides. Correct that misconception here. */ overrides. Correct that misconception here. */
if (overrides_) { if (overrides_) {
PDelays tmp_del; if (overrides_->count() > 2) {
tmp_del.set_delays(overrides_, false); cerr << get_fileline() << ": error: UDPs take at most two "
tmp_del.eval_delays(des, scope, rise_expr, fall_expr, decay_expr); "delay arguments." << endl;
if (dynamic_cast<NetEConst*> (rise_expr)) {
} else {
cerr << get_fileline() << ": error: Delay expressions must be "
<< "constant for primitives." << endl;
cerr << get_fileline() << ": : Cannot calculate "
<< *rise_expr << endl;
des->errors += 1; des->errors += 1;
}
if (dynamic_cast<NetEConst*> (fall_expr)) {
} else { } else {
cerr << get_fileline() << ": error: Delay expressions must be " PDelays tmp_del;
<< "constant for primitives." << endl; tmp_del.set_delays(overrides_, false);
cerr << get_fileline() << ": : Cannot calculate " tmp_del.eval_delays(des, scope, rise_expr, fall_expr,
<< *rise_expr << endl; decay_expr);
des->errors += 1;
if (! dynamic_cast<NetEConst*> (rise_expr)) {
cerr << get_fileline() << ": error: UDP rising delay "
"expression must be constant." << endl;
cerr << get_fileline() << ": : Cannot calculate "
<< *rise_expr << endl;
des->errors += 1;
}
if (! dynamic_cast<NetEConst*> (fall_expr)) {
cerr << get_fileline() << ": error: UDP falling delay "
"expression must be constant." << endl;
cerr << get_fileline() << ": : Cannot calculate "
<< *fall_expr << endl;
des->errors += 1;
}
} }
if (dynamic_cast<NetEConst*> (decay_expr)) {
} else {
cerr << get_fileline() << ": error: Delay expressions must be "
<< "constant for primitives." << endl;
cerr << get_fileline() << ": : Cannot calculate "
<< *rise_expr << endl;
des->errors += 1;
}
} }
assert(udp); assert(udp);
NetUDP*net = new NetUDP(scope, my_name, udp->ports.count(), udp); NetUDP*net = new NetUDP(scope, my_name, udp->ports.count(), udp);
net->rise_time(rise_expr); net->rise_time(rise_expr);
@ -1815,6 +1862,20 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
probe_expr_width(des, scope, expr); probe_expr_width(des, scope, expr);
NetExpr*dex = elab_and_eval(des, scope, expr, -1); NetExpr*dex = elab_and_eval(des, scope, expr, -1);
/* Print a warning if we find default and `timescale based
* delays in the design, since this is likely an error. */
if (scope->time_from_timescale()) dly_used_timescale = true;
else dly_used_no_timescale = true;
if (display_ts_dly_warning &&
dly_used_no_timescale && dly_used_timescale) {
cerr << "warning: Found both default and "
"`timescale based delays. Use" << endl;
cerr << " -Wtimescale to find the "
"module(s) with no `timescale." << endl;
display_ts_dly_warning = false;
}
/* If the delay expression is a real constant or vector /* If the delay expression is a real constant or vector
constant, then evaluate it, scale it to the local time constant, then evaluate it, scale it to the local time
units, and return an adjusted NetEConst. */ units, and return an adjusted NetEConst. */
@ -2583,6 +2644,13 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
ivl_variable_type_t lv_type = lv->expr_type(); ivl_variable_type_t lv_type = lv->expr_type();
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_[idx]); NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_[idx]);
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (rv)) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' can not be a user "
"task argument." << endl;
des->errors += 1;
continue;
}
if (wid > rv->expr_width()) { if (wid > rv->expr_width()) {
rv->set_width(wid); rv->set_width(wid);
rv = pad_to_width(rv, wid, *this); rv = pad_to_width(rv, wid, *this);
@ -3716,15 +3784,26 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
/* Do not elaborate specify delay paths if this feature is /* Do not elaborate specify delay paths if this feature is
turned off. */ turned off. */
if (!gn_specify_blocks_flag) if (!gn_specify_blocks_flag) return;
return;
ivl_assert(*this, conditional || (condition==0)); ivl_assert(*this, conditional || (condition==0));
ndelays = delays.size(); ndelays = delays.size();
if (ndelays > 12) if (ndelays > 12) ndelays = 12;
ndelays = 12;
/* Print a warning if we find default and `timescale based
* delays in the design, since this is likely an error. */
if (scope->time_from_timescale()) dly_used_timescale = true;
else dly_used_no_timescale = true;
if (display_ts_dly_warning &&
dly_used_no_timescale && dly_used_timescale) {
cerr << "warning: Found both default and "
"`timescale based delays. Use" << endl;
cerr << " -Wtimescale to find the "
"module(s) with no `timescale." << endl;
display_ts_dly_warning = false;
}
int shift = scope->time_unit() - des->get_precision(); int shift = scope->time_unit() - des->get_precision();
/* Elaborate the delay values themselves. Remember to scale /* Elaborate the delay values themselves. Remember to scale
@ -4289,6 +4368,7 @@ Design* elaborate(list<perm_string>roots)
scope->set_line(rmod); scope->set_line(rmod);
scope->time_unit(rmod->time_unit); scope->time_unit(rmod->time_unit);
scope->time_precision(rmod->time_precision); scope->time_precision(rmod->time_precision);
scope->time_from_timescale(rmod->time_from_timescale);
scope->default_nettype(rmod->default_nettype); scope->default_nettype(rmod->default_nettype);
des->set_precision(rmod->time_precision); des->set_precision(rmod->time_precision);
@ -4369,6 +4449,7 @@ Design* elaborate(list<perm_string>roots)
NetScope *scope = root_elems[i]->scope; NetScope *scope = root_elems[i]->scope;
rc &= rmod->elaborate(des, scope); rc &= rmod->elaborate(des, scope);
delete root_elems[i];
} }
if (rc == false) { if (rc == false) {

View File

@ -133,7 +133,7 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
<< "Partially evalutate " << *this << "Partially evaluate " << *this
<< " using (a+2)-1 --> (a+1) transform." << endl; << " using (a+2)-1 --> (a+1) transform." << endl;
} }
@ -1161,16 +1161,6 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
if (local_errors > 0) return 0; if (local_errors > 0) return 0;
// Handle the special case that the repeat expression is
// zero. In this case, just return a 0 value with the expected
// width.
if (repeat_val == 0) {
verinum val (verinum::V0, expr_width());
NetEConst*res = new NetEConst(val);
res->set_width(val.len());
return res;
}
// At this point, the "gap" is the width of a single repeat of // At this point, the "gap" is the width of a single repeat of
// the concatenation. The total width of the result is the gap // the concatenation. The total width of the result is the gap
// times the repeat count. // times the repeat count.

View File

@ -122,6 +122,7 @@ NetNet* NetEBAdd::synthesize(Design*des, NetScope*scope, NetExpr*root)
NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, width); NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, width);
osig->local_flag(true); osig->local_flag(true);
osig->data_type(expr_type()); osig->data_type(expr_type());
osig->set_signed(has_sign());
perm_string oname = osig->scope()->local_symbol(); perm_string oname = osig->scope()->local_symbol();
NetAddSub *adder = new NetAddSub(lsig->scope(), oname, width); NetAddSub *adder = new NetAddSub(lsig->scope(), oname, width);
@ -390,6 +391,7 @@ NetNet* NetEBPow::synthesize(Design*des, NetScope*scope, NetExpr*root)
NetNet::IMPLICIT, width); NetNet::IMPLICIT, width);
osig->set_line(*this); osig->set_line(*this);
osig->data_type(expr_type()); osig->data_type(expr_type());
osig->set_signed(has_sign());
osig->local_flag(true); osig->local_flag(true);
connect(powr->pin_Result(), osig->pin(0)); connect(powr->pin_Result(), osig->pin(0));
@ -426,6 +428,7 @@ NetNet* NetEBMult::synthesize(Design*des, NetScope*scope, NetExpr*root)
NetNet::IMPLICIT, width); NetNet::IMPLICIT, width);
osig->set_line(*this); osig->set_line(*this);
osig->data_type(expr_type()); osig->data_type(expr_type());
osig->set_signed(has_sign());
osig->local_flag(true); osig->local_flag(true);
connect(mult->pin_Result(), osig->pin(0)); connect(mult->pin_Result(), osig->pin(0));
@ -601,8 +604,8 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root)
return 0; return 0;
} }
const bool right_flag = op_ == 'r' || op_ == 'R'; const bool right_flag = op_ == 'r' || op_ == 'R';
const bool signed_flag = op_ == 'R'; const bool signed_flag = has_sign() && op_ == 'R';
/* Detect the special case where the shift amount is /* Detect the special case where the shift amount is
constant. Evaluate the shift amount, and simply reconnect constant. Evaluate the shift amount, and simply reconnect
@ -719,28 +722,42 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root)
NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root) NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
{ {
/* First, synthesize the operands. */ /* First, synthesize the operands. */
unsigned nparms = parms_.count();
NetNet**tmp = new NetNet*[parms_.count()]; NetNet**tmp = new NetNet*[parms_.count()];
bool flag = true; bool flag = true;
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
tmp[idx] = parms_[idx]->synthesize(des, scope, root); if (parms_[idx]->expr_width() == 0) {
if (tmp[idx] == 0) /* We need to synthesize a replication of zero. */
flag = false; tmp[idx] = parms_[idx]->synthesize(des, scope, root);
assert(tmp[idx] == 0);
nparms -= 1;
} else {
tmp[idx] = parms_[idx]->synthesize(des, scope, root);
if (tmp[idx] == 0) flag = false;
/* Set the data type to the first one found. */
if (data_type == IVL_VT_NO_TYPE) {
data_type = tmp[idx]->data_type();
}
}
} }
if (flag == false) if (flag == false) return 0;
return 0;
ivl_assert(*this, tmp[0]); ivl_assert(*this, data_type != IVL_VT_NO_TYPE);
/* If this is a replication of zero just return 0. */
if (expr_width() == 0) return 0;
/* Make a NetNet object to carry the output vector. */ /* Make a NetNet object to carry the output vector. */
perm_string path = scope->local_symbol(); perm_string path = scope->local_symbol();
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width()); NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width());
osig->local_flag(true); osig->local_flag(true);
osig->data_type(tmp[0]->data_type()); osig->data_type(data_type);
NetConcat*concat = new NetConcat(scope, scope->local_symbol(), NetConcat*concat = new NetConcat(scope, scope->local_symbol(),
osig->vector_width(), osig->vector_width(),
parms_.count() * repeat()); nparms * repeat());
concat->set_line(*this); concat->set_line(*this);
des->add_node(concat); des->add_node(concat);
connect(concat->pin(0), osig->pin(0)); connect(concat->pin(0), osig->pin(0));
@ -750,7 +767,7 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
for (unsigned rpt = 0; rpt < repeat(); rpt += 1) { for (unsigned rpt = 0; rpt < repeat(); rpt += 1) {
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
unsigned concat_item = parms_.count()-idx-1; unsigned concat_item = parms_.count()-idx-1;
ivl_assert(*this, tmp[concat_item]); if (tmp[concat_item] == 0) continue;
connect(concat->pin(cur_pin), tmp[concat_item]->pin(0)); connect(concat->pin(cur_pin), tmp[concat_item]->pin(0));
cur_pin += 1; cur_pin += 1;
count_input_width += tmp[concat_item]->vector_width(); count_input_width += tmp[concat_item]->vector_width();
@ -773,6 +790,11 @@ NetNet* NetEConst::synthesize(Design*des, NetScope*scope, NetExpr*)
{ {
perm_string path = scope->local_symbol(); perm_string path = scope->local_symbol();
unsigned width=expr_width(); unsigned width=expr_width();
if (width == 0) {
cerr << get_fileline() << ": internal error: "
<< "Found a zero width constant!" << endl;
return 0;
}
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width); NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width);
osig->local_flag(true); osig->local_flag(true);
@ -1347,6 +1369,10 @@ NetNet* NetEUFunc::synthesize(Design*des, NetScope*scope, NetExpr*root)
/* Synthesize the arguments. */ /* Synthesize the arguments. */
bool errors = false; bool errors = false;
for (unsigned idx = 0; idx < eparms.count(); idx += 1) { for (unsigned idx = 0; idx < eparms.count(); idx += 1) {
if (dynamic_cast<NetEEvent*> (parms_[idx])) {
errors = true;
continue;
}
NetNet*tmp = parms_[idx]->synthesize(des, scope, root); NetNet*tmp = parms_[idx]->synthesize(des, scope, root);
if (tmp == 0) { if (tmp == 0) {
cerr << get_fileline() << ": error: Unable to synthesize " cerr << get_fileline() << ": error: Unable to synthesize "

View File

@ -499,65 +499,3 @@ already seems to exist amongst VCD viewers in the wild, this behavior
seems to be acceptable according to the standard, is a better mirror seems to be acceptable according to the standard, is a better mirror
of 4-value behavior in the dead zone, and appears more user friendly of 4-value behavior in the dead zone, and appears more user friendly
when viewed by reasonable viewers. when viewed by reasonable viewers.
$Id: ieee1364-notes.txt,v 1.19 2007/04/18 02:36:13 steve Exp $
$Log: ieee1364-notes.txt,v $
Revision 1.19 2007/04/18 02:36:13 steve
Put to iverilog wiki for further notes.
Revision 1.18 2007/03/22 16:08:16 steve
Spelling fixes from Larry
Revision 1.17 2003/07/15 03:49:22 steve
Spelling fixes.
Revision 1.16 2003/04/14 03:40:21 steve
Make some effort to preserve bits while
operating on constant values.
Revision 1.15 2003/02/16 23:39:08 steve
NaN in dead zones of VCD dumps.
Revision 1.14 2003/02/06 17:51:36 steve
Edge of vectors notes.
Revision 1.13 2002/08/20 04:11:53 steve
Support parameters with defined ranges.
Revision 1.12 2002/06/11 03:34:33 steve
Spelling patch (Larry Doolittle)
Revision 1.11 2002/04/27 02:38:04 steve
Support selecting bits from parameters.
Revision 1.10 2002/03/31 01:54:13 steve
Notes about scheduling
Revision 1.9 2002/01/26 02:08:07 steve
Handle x in l-value of set/x
Revision 1.8 2001/08/01 05:17:31 steve
Accept empty port lists to module instantiation.
Revision 1.7 2001/02/17 05:27:31 steve
I allow function ports to have types.
Revision 1.6 2001/02/12 16:48:04 steve
Rant about bit widths.
Revision 1.5 2001/01/02 17:28:08 steve
Resolve repeat ambiguity in favor of loop.
Revision 1.4 2001/01/01 19:12:35 steve
repeat loops ambiguity.
Revision 1.3 2000/12/15 00:21:46 steve
rounding of time and x in primitives.
Revision 1.2 2000/11/19 22:03:04 steve
Integer parameter comments.
Revision 1.1 2000/07/23 18:06:31 steve
Document ieee1364 issues.

View File

@ -4,7 +4,7 @@ iverilog-vpi - Compile front end for VPI modules
.SH SYNOPSIS .SH SYNOPSIS
.B iverilog-vpi .B iverilog-vpi
[--name=\fIname\fP] [\-\-name=\fIname\fP]
\fIsourcefile\fP... \fIsourcefile\fP...
.SH DESCRIPTION .SH DESCRIPTION
@ -20,7 +20,6 @@ first source file is named \fIfoo.c\fP, the output becomes
\fIfoo.vpi\fP. \fIfoo.vpi\fP.
.SH OPTIONS .SH OPTIONS
.l
\fIiverilog-vpi\fP accepts the following options: \fIiverilog-vpi\fP accepts the following options:
.TP 8 .TP 8
.B -l\fIlibrary\fP .B -l\fIlibrary\fP
@ -104,9 +103,9 @@ requests a 32bit vpi binary instead of the default 64bit binary.
.P .P
Example GNU makefile that takes advantage of these flags: Example GNU makefile that takes advantage of these flags:
.IP "" 4 .IP "" 4
CFLAGS = -Wall -O $(CFLAGS_$@) CFLAGS = \-Wall \-O $(CFLAGS_$@)
.br .br
VPI_CFLAGS := $(shell iverilog-vpi --cflags) VPI_CFLAGS := $(shell iverilog-vpi \-\-cflags)
.br .br
CFLAGS_messagev.o = $(VPI_CFLAGS) CFLAGS_messagev.o = $(VPI_CFLAGS)
.br .br

View File

@ -161,6 +161,7 @@ ivl_scope_event
ivl_scope_events ivl_scope_events
ivl_scope_file ivl_scope_file
ivl_scope_is_auto ivl_scope_is_auto
ivl_scope_is_cell
ivl_scope_lineno ivl_scope_lineno
ivl_scope_logs ivl_scope_logs
ivl_scope_log ivl_scope_log

View File

@ -1537,6 +1537,9 @@ extern unsigned ivl_parameter_lineno(ivl_parameter_t net);
* ivl_scope_is_auto * ivl_scope_is_auto
* Is the task or function declared to be automatic? * Is the task or function declared to be automatic?
* *
* ivl_scope_is_cell
* Is the module defined to be a cell?
*
* ivl_scope_var * ivl_scope_var
* ivl_scope_vars * ivl_scope_vars
* REMOVED * REMOVED
@ -1614,6 +1617,7 @@ extern unsigned ivl_scope_events(ivl_scope_t net);
extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx); extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx);
extern const char* ivl_scope_file(ivl_scope_t net); extern const char* ivl_scope_file(ivl_scope_t net);
extern unsigned ivl_scope_is_auto(ivl_scope_t net); extern unsigned ivl_scope_is_auto(ivl_scope_t net);
extern unsigned ivl_scope_is_cell(ivl_scope_t net);
extern unsigned ivl_scope_lineno(ivl_scope_t net); extern unsigned ivl_scope_lineno(ivl_scope_t net);
extern unsigned ivl_scope_logs(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 ivl_net_logic_t ivl_scope_log(ivl_scope_t net, unsigned idx);

View File

@ -2,7 +2,6 @@
Icarus Verilog LOADABLE TARGET API (ivl_target) Icarus Verilog LOADABLE TARGET API (ivl_target)
Copyright 2002 Stephen Williams <steve@icarus.com> Copyright 2002 Stephen Williams <steve@icarus.com>
$Id: ivl_target.txt,v 1.3 2002/06/11 03:34:33 steve Exp $
The ivl_target API is the interface available to modules that the The ivl_target API is the interface available to modules that the
@ -38,14 +37,3 @@ other LPM device with outputs.
There are ivl_lpm_size() input ports, each with the width There are ivl_lpm_size() input ports, each with the width
ivl_lpm_data2_width(). The actual nexus is indexed by ivl_lpm_data2(). ivl_lpm_data2_width(). The actual nexus is indexed by ivl_lpm_data2().
$Log: ivl_target.txt,v $
Revision 1.3 2002/06/11 03:34:33 steve
Spelling patch (Larry Doolittle)
Revision 1.2 2002/03/17 19:31:17 steve
Add API to support user defined function.
Revision 1.1 2002/03/09 02:10:22 steve
Add the NetUserFunc netlist node.

View File

@ -64,13 +64,8 @@ struct include_stack_t
/* If we are reparsing a macro expansion, file is 0 and this /* If we are reparsing a macro expansion, file is 0 and this
* member points to the string in progress * member points to the string in progress
*/ */
const char* str; char* str;
char* orig_str;
/* If we are reparsing a macro expansion, this member indicates
* the amount of space it occupies in the macro expansion buffer.
* This will be zero for macros without arguments.
*/
int ebs;
int stringify_flag; int stringify_flag;
@ -462,7 +457,7 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
<IFCCOMMENT>\n\r | <IFCCOMMENT>\n\r |
<IFCCOMMENT>\r\n | <IFCCOMMENT>\r\n |
<IFCCOMMENT>\n | <IFCCOMMENT>\n |
<IFCCOMMENT>\r { istack->lineno += 1; } <IFCCOMMENT>\r { istack->lineno += 1; fputc('\n', yyout); }
<IFCCOMMENT>"*/" { BEGIN(comment_enter); } <IFCCOMMENT>"*/" { BEGIN(comment_enter); }
<IFDEF_FALSE,IFDEF_SUPR>[^\r\n] { } <IFDEF_FALSE,IFDEF_SUPR>[^\r\n] { }
@ -599,7 +594,8 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
<MA_ADD>"(" { macro_add_to_arg(0); ma_parenthesis_level++; } <MA_ADD>"(" { macro_add_to_arg(0); ma_parenthesis_level++; }
<MA_ADD>"," { macro_finish_arg(); } <MA_ADD>"," { if (ma_parenthesis_level > 0) macro_add_to_arg(0);
else macro_finish_arg(); }
<MA_ADD>")" { <MA_ADD>")" {
if (ma_parenthesis_level > 0) { if (ma_parenthesis_level > 0) {
@ -1352,10 +1348,17 @@ static void do_expand(int use_args)
struct include_stack_t*isp; struct include_stack_t*isp;
int head = 0; int head = 0;
int tail = 0; int tail = 0;
const char *cp;
unsigned escapes = 0;
char *str_buf = 0;
if (cur_macro->keyword) if (cur_macro->keyword)
{ {
fprintf(yyout, "%s", cur_macro->value); fprintf(yyout, "%s", cur_macro->value);
if (do_expand_stringify_flag) {
do_expand_stringify_flag = 0;
fputc('"', yyout);
}
return; return;
} }
@ -1364,6 +1367,7 @@ static void do_expand(int use_args)
head = exp_buf_size - exp_buf_free; head = exp_buf_size - exp_buf_free;
expand_using_args(); expand_using_args();
tail = exp_buf_size - exp_buf_free; tail = exp_buf_size - exp_buf_free;
exp_buf_free += tail - head;
if (tail == head) if (tail == head)
return; return;
@ -1376,14 +1380,47 @@ static void do_expand(int use_args)
if (use_args) if (use_args)
{ {
isp->str = &exp_buf[head]; isp->str = &exp_buf[head];
isp->ebs = tail - head;
} }
else else
{ {
isp->str = cur_macro->value; isp->str = cur_macro->value;
isp->ebs = 0;
} }
/* Escape some characters if we are making a string version. */
for (cp = isp->str; (cp = strpbrk(cp, "\"\\")); cp += 1, escapes += 1);
if (escapes && isp->stringify_flag) {
unsigned idx = 0;
str_buf = (char *) malloc(strlen(isp->str)+3*escapes+1);
for (cp = isp->str; *cp; cp += 1) {
if (*cp == '"') {
str_buf[idx] = '\\';
str_buf[idx+1] = '0';
str_buf[idx+2] = '4';
str_buf[idx+3] = '2';
idx += 4;
continue;
}
if (*cp == '\\') {
str_buf[idx] = '\\';
str_buf[idx+1] = '1';
str_buf[idx+2] = '3';
str_buf[idx+3] = '4';
idx += 4;
continue;
}
str_buf[idx] = *cp;
idx += 1;
}
str_buf[idx] = 0;
idx += 1;
exp_buf_free -= idx;
isp->str = str_buf;
} else
isp->str = strdup(isp->str);
isp->orig_str = isp->str;
isp->next = istack; isp->next = istack;
istack->yybs = YY_CURRENT_BUFFER; istack->yybs = YY_CURRENT_BUFFER;
istack = isp; istack = isp;
@ -1572,7 +1609,7 @@ static int load_next_input()
else else
line_mask_flag = 1; line_mask_flag = 1;
exp_buf_free += isp->ebs; free(isp->orig_str);
} }
if (isp->stringify_flag) { if (isp->stringify_flag) {
@ -1749,7 +1786,6 @@ void reset_lexor(FILE* out, char* paths[])
isp->path = strdup(paths[0]); isp->path = strdup(paths[0]);
isp->file = fopen(paths[0], "r"); isp->file = fopen(paths[0], "r");
isp->str = 0; isp->str = 0;
isp->ebs = 0;
isp->lineno = 0; isp->lineno = 0;
isp->stringify_flag = 0; isp->stringify_flag = 0;
isp->comment = NULL; isp->comment = NULL;
@ -1779,7 +1815,6 @@ void reset_lexor(FILE* out, char* paths[])
isp->path = strdup(paths[idx]); isp->path = strdup(paths[idx]);
isp->file = 0; isp->file = 0;
isp->str = 0; isp->str = 0;
isp->ebs = 0;
isp->next = 0; isp->next = 0;
isp->lineno = 0; isp->lineno = 0;
isp->stringify_flag = 0; isp->stringify_flag = 0;
@ -1807,4 +1842,5 @@ void destroy_lexor()
# endif # endif
# endif # endif
free(def_buf); free(def_buf);
free(exp_buf);
} }

View File

@ -214,26 +214,34 @@ int main(int argc, char*argv[])
FILE*precomp_out = NULL; FILE*precomp_out = NULL;
/* Define preprocessor keywords that I plan to just pass. */ /* Define preprocessor keywords that I plan to just pass. */
/* From 1364-2005 Chapter 19. */
define_macro("begin_keywords", "`begin_keywords", 1, 0);
define_macro("celldefine", "`celldefine", 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_nettype", "`default_nettype", 1, 0);
define_macro("default_trireg_strength", "`default_trireg_strength", 1, 0); define_macro("end_keywords", "`end_keywords", 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("endcelldefine", "`endcelldefine", 1, 0);
define_macro("endprotect", "`endprotect", 1, 0);
define_macro("line", "`line", 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("nounconnected_drive", "`nounconnected_drive", 1, 0);
define_macro("protect", "`protect", 1, 0); define_macro("pragma", "`pragma", 1, 0);
define_macro("resetall", "`resetall", 1, 0); define_macro("resetall", "`resetall", 1, 0);
define_macro("suppress_faults", "`suppress_faults", 1, 0);
define_macro("timescale", "`timescale", 1, 0); define_macro("timescale", "`timescale", 1, 0);
define_macro("unconnected_drive", "`unconnected_drive", 1, 0); define_macro("unconnected_drive", "`unconnected_drive", 1, 0);
/* From 1364-2005 Annex D. */
define_macro("default_decay_time", "`default_decay_time", 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_path", "`delay_mode_path", 1, 0);
define_macro("delay_mode_unit", "`delay_mode_unit", 1, 0);
define_macro("delay_mode_zero", "`delay_mode_zero", 1, 0);
/* From other places. */
define_macro("disable_portfaults", "`disable_portfaults", 1, 0);
define_macro("enable_portfaults", "`enable_portfaults", 1, 0);
define_macro("endprotect", "`endprotect", 1, 0);
define_macro("nosuppress_faults", "`nosuppress_faults", 1, 0);
define_macro("protect", "`protect", 1, 0);
define_macro("suppress_faults", "`suppress_faults", 1, 0);
define_macro("uselib", "`uselib", 1, 0); define_macro("uselib", "`uselib", 1, 0);
include_cnt = 2; include_cnt = 2;

540
lexor.lex
View File

@ -67,9 +67,6 @@ static const char* set_file_name(char*text)
return path; return path;
} }
extern void pform_set_timescale(int, int, const char*file, unsigned line);
void reset_lexor(); void reset_lexor();
static void line_directive(); static void line_directive();
static void line_directive2(); static void line_directive2();
@ -83,11 +80,15 @@ static verinum*make_unsized_hex(const char*txt);
static int dec_buf_div2(char *buf); static int dec_buf_div2(char *buf);
static void process_timescale(const char*txt); static void process_timescale(const char*txt);
static void process_ucdrive(const char*txt);
static list<int> keyword_mask_stack; static list<int> keyword_mask_stack;
static int comment_enter; static int comment_enter;
static bool in_module = false; static bool in_module = false;
static bool in_UDP = false;
bool in_celldefine = false;
UCDriveType uc_drive = UCD_NONE;
%} %}
%x CCOMMENT %x CCOMMENT
@ -96,6 +97,7 @@ static bool in_module = false;
%x CSTRING %x CSTRING
%s UDPTABLE %s UDPTABLE
%x PPTIMESCALE %x PPTIMESCALE
%x PPUCDRIVE
%x PPDEFAULT_NETTYPE %x PPDEFAULT_NETTYPE
%x PPBEGIN_KEYWORDS %x PPBEGIN_KEYWORDS
%s EDGES %s EDGES
@ -107,8 +109,9 @@ S [afpnumkKMGT]
%% %%
^"#line"[ ]+\"[^\"]*\"[ ]+[0-9]+.* { line_directive(); } /* Recognize the various line directives. */
^"`line"[ ]+[0-9]+[ ]+\"[^\"]*\".* { line_directive2(); } ^"#line"[ \t]+.+ { line_directive(); }
^[ \t]?"`line"[ \t]+.+ { line_directive2(); }
[ \t\b\f\r] { ; } [ \t\b\f\r] { ; }
\n { yylloc.first_line += 1; } \n { yylloc.first_line += 1; }
@ -237,6 +240,14 @@ S [afpnumkKMGT]
in_module = false; in_module = false;
break; break;
case K_primitive:
in_UDP = true;
break;
case K_endprimitive:
in_UDP = false;
break;
default: default:
yylval.text = 0; yylval.text = 0;
break; break;
@ -263,22 +274,35 @@ S [afpnumkKMGT]
return IDENTIFIER; } return IDENTIFIER; }
\$([a-zA-Z0-9$_]+) { \$([a-zA-Z0-9$_]+) {
if (strcmp(yytext,"$setuphold") == 0) /* The 1364-1995 timing checks. */
return K_Ssetuphold;
if (strcmp(yytext,"$attribute") == 0)
return KK_attribute;
if (strcmp(yytext,"$hold") == 0) if (strcmp(yytext,"$hold") == 0)
return K_Shold; return K_Shold;
if (strcmp(yytext,"$nochange") == 0)
return K_Snochange;
if (strcmp(yytext,"$period") == 0) if (strcmp(yytext,"$period") == 0)
return K_Speriod; return K_Speriod;
if (strcmp(yytext,"$recovery") == 0) if (strcmp(yytext,"$recovery") == 0)
return K_Srecovery; return K_Srecovery;
if (strcmp(yytext,"$recrem") == 0)
return K_Srecrem;
if (strcmp(yytext,"$setup") == 0) if (strcmp(yytext,"$setup") == 0)
return K_Ssetup; return K_Ssetup;
if (strcmp(yytext,"$setuphold") == 0)
return K_Ssetuphold;
if (strcmp(yytext,"$skew") == 0)
return K_Sskew;
if (strcmp(yytext,"$width") == 0) if (strcmp(yytext,"$width") == 0)
return K_Swidth; return K_Swidth;
/* The new 1364-2001 timing checks. */
if (strcmp(yytext,"$fullskew") == 0)
return K_Sfullskew;
if (strcmp(yytext,"$recrem") == 0)
return K_Srecrem;
if (strcmp(yytext,"$removal") == 0)
return K_Sremoval;
if (strcmp(yytext,"$timeskew") == 0)
return K_Stimeskew;
if (strcmp(yytext,"$attribute") == 0)
return KK_attribute;
yylval.text = strdupnew(yytext); yylval.text = strdupnew(yytext);
return SYSTEM_IDENTIFIER; } return SYSTEM_IDENTIFIER; }
@ -348,7 +372,7 @@ S [afpnumkKMGT]
return REALTIME; } return REALTIME; }
/* Notice and handle the timescale directive. */ /* Notice and handle the `timescale directive. */
^{W}?`timescale { BEGIN(PPTIMESCALE); } ^{W}?`timescale { BEGIN(PPTIMESCALE); }
<PPTIMESCALE>.* { process_timescale(yytext); } <PPTIMESCALE>.* { process_timescale(yytext); }
@ -362,28 +386,74 @@ S [afpnumkKMGT]
yylloc.first_line += 1; yylloc.first_line += 1;
BEGIN(0); } BEGIN(0); }
/* Notice and handle the `celldefine and `endcelldefine directives. */
^{W}?`celldefine{W}? { in_celldefine = true; }
^{W}?`endcelldefine{W}? { in_celldefine = false; }
/* Notice and handle the resetall directive. */
^{W}?`resetall{W}? {
if (in_module) {
cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
"`resetall directive can not be inside a module "
"definition." << endl;
error_count += 1;
} else if (in_UDP) {
cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
"`resetall directive can not be inside a UDP "
"definition." << endl;
error_count += 1;
} else {
pform_set_default_nettype(NetNet::WIRE, yylloc.text,
yylloc.first_line);
in_celldefine = false;
uc_drive = UCD_NONE;
pform_set_timescale(def_ts_units, def_ts_prec, 0, 0);
} }
/* Notice and handle the `unconnected_drive directive. */
^{W}?`unconnected_drive { BEGIN(PPUCDRIVE); }
<PPUCDRIVE>.* { process_ucdrive(yytext); }
<PPUCDRIVE>\n {
if (in_module) {
cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
"`unconnected_drive directive can not be inside a "
"module definition." << endl;
error_count += 1;
}
yylloc.first_line += 1;
BEGIN(0); }
^{W}?`nounconnected_drive{W}? {
if (in_module) {
cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
"`nounconnected_drive directive can not be inside a "
"module definition." << endl;
error_count += 1;
}
uc_drive = UCD_NONE; }
/* These are directives that I do not yet support. I think that IVL /* These are directives that I do not yet support. I think that IVL
should handle these, not an external preprocessor. */ should handle these, not an external preprocessor. */
/* From 1364-2005 Chapter 19. */
^{W}?`pragme{W}?.* { }
^{W}?`celldefine{W}?.* { } /* From 1364-2005 Annex D. */
^{W}?`default_decay_time{W}?.* { } ^{W}?`default_decay_time{W}?.* { }
^{W}?`default_trireg_strength{W}?.* { } ^{W}?`default_trireg_strength{W}?.* { }
^{W}?`delay_mode_distributed{W}?.* { } ^{W}?`delay_mode_distributed{W}?.* { }
^{W}?`delay_mode_unit{W}?.* { }
^{W}?`delay_mode_path{W}?.* { } ^{W}?`delay_mode_path{W}?.* { }
^{W}?`delay_mode_unit{W}?.* { }
^{W}?`delay_mode_zero{W}?.* { } ^{W}?`delay_mode_zero{W}?.* { }
/* From other places. */
^{W}?`disable_portfaults{W}?.* { } ^{W}?`disable_portfaults{W}?.* { }
^{W}?`enable_portfaults{W}?.* { } ^{W}?`enable_portfaults{W}?.* { }
^{W}?`endcelldefine{W}?.* { }
`endprotect { } `endprotect { }
^{W}?`line{W}?.* { }
^{W}?`nosuppress_faults{W}?.* { } ^{W}?`nosuppress_faults{W}?.* { }
^{W}?`nounconnected_drive{W}?.* { }
`protect { } `protect { }
^{W}?`resetall{W}?.* { }
^{W}?`suppress_faults{W}?.* { } ^{W}?`suppress_faults{W}?.* { }
^{W}?`unconnected_drive{W}?.* { }
^{W}?`uselib{W}?.* { } ^{W}?`uselib{W}?.* { }
^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); } ^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); }
@ -447,16 +517,38 @@ S [afpnumkKMGT]
NetNet::Type net_type; NetNet::Type net_type;
size_t wordlen = strcspn(yytext, " \t\f\r\n"); size_t wordlen = strcspn(yytext, " \t\f\r\n");
yytext[wordlen] = 0; yytext[wordlen] = 0;
/* Add support for other wire types and better error detection. */
if (strcmp(yytext,"wire") == 0) { if (strcmp(yytext,"wire") == 0) {
net_type = NetNet::WIRE; net_type = NetNet::WIRE;
} else if (strcmp(yytext,"tri") == 0) {
net_type = NetNet::TRI;
} else if (strcmp(yytext,"tri0") == 0) {
net_type = NetNet::TRI0;
} else if (strcmp(yytext,"tri1") == 0) {
net_type = NetNet::TRI1;
} else if (strcmp(yytext,"wand") == 0) {
net_type = NetNet::WAND;
} else if (strcmp(yytext,"triand") == 0) {
net_type = NetNet::TRIAND;
} else if (strcmp(yytext,"wor") == 0) {
net_type = NetNet::WOR;
} else if (strcmp(yytext,"trior") == 0) {
net_type = NetNet::TRIOR;
} else if (strcmp(yytext,"none") == 0) { } else if (strcmp(yytext,"none") == 0) {
net_type = NetNet::NONE; net_type = NetNet::NONE;
} else { } else {
cerr << yylloc.text << ":" << yylloc.first_line cerr << yylloc.text << ":" << yylloc.first_line
<< ": error: Net type " << yytext << ": error: Net type " << yytext
<< " is not a valid (and supported)" << " is not a valid (or supported)"
<< " default net type." << endl; << " default net type." << endl;
net_type = NetNet::WIRE; net_type = NetNet::WIRE;
error_count += 1; error_count += 1;
@ -483,6 +575,12 @@ S [afpnumkKMGT]
<< endl; << endl;
} }
^{W}?`elsif{W}?.* {
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: `elsif not supported. Use an external preprocessor."
<< endl;
}
^{W}?`endif{W}?.* { ^{W}?`endif{W}?.* {
cerr << yylloc.text << ":" << yylloc.first_line << cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: `endif not supported. Use an external preprocessor." ": warning: `endif not supported. Use an external preprocessor."
@ -495,6 +593,12 @@ S [afpnumkKMGT]
<< endl; << endl;
} }
^{W}?`ifndef{W}?.* {
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: `ifndef not supported. Use an external preprocessor."
<< endl;
}
^`include{W}?.* { ^`include{W}?.* {
cerr << yylloc.text << ":" << yylloc.first_line << cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: `include not supported. Use an external preprocessor." ": warning: `include not supported. Use an external preprocessor."
@ -936,6 +1040,128 @@ static verinum*make_unsized_dec(const char*ptr)
return res; return res;
} }
/*
* Convert the string to a time unit or precision.
* Returns true on failure.
*/
static bool get_timescale_const(const char *&cp, int &res, bool is_unit)
{
/* Check for the 1 digit. */
if (*cp != '1') {
if (is_unit) {
VLerror(yylloc, "Invalid `timescale unit constant "
"(1st digit)");
} else {
VLerror(yylloc, "Invalid `timescale precision constant "
"(1st digit)");
}
return true;
}
cp += 1;
/* Check the number of zeros after the 1. */
res = strspn(cp, "0");
if (res > 2) {
if (is_unit) {
VLerror(yylloc, "Invalid `timescale unit constant "
"(number of zeros)");
} else {
VLerror(yylloc, "Invalid `timescale precision constant "
"(number of zeros)");
}
return true;
}
cp += res;
/* Skip any space between the digits and the scaling string. */
cp += strspn(cp, " \t");
/* Now process the scaling string. */
if (strncmp("s", cp, 1) == 0) {
res -= 0;
cp += 1;
return false;
} else if (strncmp("ms", cp, 2) == 0) {
res -= 3;
cp += 2;
return false;
} else if (strncmp("us", cp, 2) == 0) {
res -= 6;
cp += 2;
return false;
} else if (strncmp("ns", cp, 2) == 0) {
res -= 9;
cp += 2;
return false;
} else if (strncmp("ps", cp, 2) == 0) {
res -= 12;
cp += 2;
return false;
} else if (strncmp("fs", cp, 2) == 0) {
res -= 15;
cp += 2;
return false;
}
if (is_unit) {
VLerror(yylloc, "Invalid `timescale unit scale");
} else {
VLerror(yylloc, "Invalid `timescale precision scale");
}
return true;
}
/*
* process either a pull0 or a pull1.
*/
static void process_ucdrive(const char*txt)
{
UCDriveType ucd = UCD_NONE;
const char*cp = txt + strspn(txt, " \t");
/* Skip the space after the `unconnected_drive directive. */
if (cp == txt) {
VLerror(yylloc, "Space required after `unconnected_drive "
"directive.");
return;
}
/* Check for the pull keyword. */
if (strncmp("pull", cp, 4) != 0) {
VLerror(yylloc, "pull required for `unconnected_drive "
"directive.");
return;
}
cp += 4;
if (*cp == '0') ucd = UCD_PULL0;
else if (*cp == '1') ucd = UCD_PULL1;
else {
cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
"`unconnected_drive does not support 'pull" << *cp
<< "'." << endl;
error_count += 1;
return;
}
cp += 1;
/* Verify that only space and/or a single line comment is left. */
cp += strspn(cp, " \t");
if (strncmp(cp, "//", 2) != 0 &&
(size_t)(cp-yytext) != strlen(yytext)) {
VLerror(yylloc, "Invalid `unconnected_dirve directive (extra "
"garbage after precision).");
return;
}
uc_drive = ucd;
}
/* /*
* The timescale parameter has the form: * The timescale parameter has the form:
@ -943,98 +1169,46 @@ static verinum*make_unsized_dec(const char*ptr)
*/ */
static void process_timescale(const char*txt) static void process_timescale(const char*txt)
{ {
unsigned num;
const char*cp = txt + strspn(txt, " \t"); const char*cp = txt + strspn(txt, " \t");
char*tmp;
const char*ctmp; /* Skip the space after the `timescale directive. */
if (cp == txt) {
VLerror(yylloc, "Space required after `timescale directive.");
return;
}
int unit = 0; int unit = 0;
int prec = 0; int prec = 0;
num = strtoul(cp, &tmp, 10); /* Get the time units. */
if (num == 0) { if (get_timescale_const(cp, unit, true)) return;
VLerror(yylloc, "Invalid timescale string.");
return;
}
while (num >= 10) { /* Skip any space after the time units, the '/' and any
unit += 1; * space after the '/'. */
num /= 10;
}
if (num != 1) {
VLerror(yylloc, "Invalid timescale unit number.");
return;
}
cp = tmp;
cp += strspn(cp, " \t"); cp += strspn(cp, " \t");
ctmp = cp + strcspn(cp, " \t/"); if (*cp != '/') {
VLerror(yylloc, "`timescale separator '/' appears to be missing.");
if (strncmp("s", cp, ctmp-cp) == 0) {
unit -= 0;
} else if (strncmp("ms", cp, ctmp-cp) == 0) {
unit -= 3;
} else if (strncmp("us", cp, ctmp-cp) == 0) {
unit -= 6;
} else if (strncmp("ns", cp, ctmp-cp) == 0) {
unit -= 9;
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
unit -= 12;
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
unit -= 15;
} else {
VLerror(yylloc, "Invalid timescale unit of measurement");
return; return;
} }
cp += 1;
cp = ctmp;
cp += strspn(cp, " \t/");
num = strtoul(cp, &tmp, 10);
if (num == 0) {
VLerror(yylloc, "Invalid timescale string.");
return;
}
assert(num);
while (num >= 10) {
prec += 1;
num /= 10;
}
if (num != 1) {
VLerror(yylloc, "Invalid timescale precision number.");
return;
}
cp = tmp;
cp += strspn(cp, " \t"); cp += strspn(cp, " \t");
ctmp = cp + strcspn(cp, " \t\r");
if (strncmp("s", cp, ctmp-cp) == 0) { /* Get the time precision. */
prec -= 0; if (get_timescale_const(cp, prec, false)) return;
} else if (strncmp("ms", cp, ctmp-cp) == 0) { /* Verify that only space and/or a single line comment is left. */
prec -= 3; cp += strspn(cp, " \t");
if (strncmp(cp, "//", 2) != 0 &&
(size_t)(cp-yytext) != strlen(yytext)) {
VLerror(yylloc, "Invalid `timescale directive (extra garbage "
"after precision).");
return;
}
} else if (strncmp("us", cp, ctmp-cp) == 0) { /* The time unit must be greater than or equal to the precision. */
prec -= 6; if (unit < prec) {
VLerror(yylloc, "error: `timescale unit must not be less than "
} else if (strncmp("ns", cp, ctmp-cp) == 0) { "the precision.");
prec -= 9;
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
prec -= 12;
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
prec -= 15;
} else {
VLerror(yylloc, "Invalid timescale precision units of measurement");
return; return;
} }
@ -1053,47 +1227,149 @@ int yywrap()
*/ */
static void line_directive() static void line_directive()
{ {
char*qt1 = strchr(yytext, '"'); char *cpr;
assert(qt1); /* Skip any leading space. */
qt1 += 1; char *cp = strchr(yytext, '#');
/* Skip the #line directive. */
assert(strncmp(cp, "#line", 5) == 0);
cp += 5;
/* Skip the space after the #line directive. */
cp += strspn(cp, " \t");
char*qt2 = strchr(qt1, '"'); /* Find the starting " and skip it. */
assert(qt2); char*fn_start = strchr(cp, '"');
if (cp != fn_start) {
VLerror(yylloc, "Invalid #line directive (file name start).");
return;
}
fn_start += 1;
char*buf = new char[qt2-qt1+1]; /* Find the last ". */
strncpy(buf, qt1, qt2-qt1); char*fn_end = strrchr(fn_start, '"');
buf[qt2-qt1] = 0; if (!fn_end) {
VLerror(yylloc, "Invalid #line directive (file name end).");
return;
}
/* Copy the file name and assign it to yylloc. */
char*buf = new char[fn_end-fn_start+1];
strncpy(buf, fn_start, fn_end-fn_start);
buf[fn_end-fn_start] = 0;
/* Skip the space after the file name. */
cp = fn_end;
cp += 1;
cpr = cp;
cpr += strspn(cp, " \t");
if (cp == cpr) {
VLerror(yylloc, "Invalid #line directive (missing space after "
"file name).");
return;
}
cp = cpr;
/* Get the line number and verify that it is correct. */
unsigned long lineno = strtoul(cp, &cpr, 10);
if (cp == cpr) {
VLerror(yylloc, "Invalid line number for #line directive.");
return;
}
cp = cpr;
/* Verify that only space is left. */
cpr += strspn(cp, " \t");
if ((size_t)(cpr-yytext) != strlen(yytext)) {
VLerror(yylloc, "Invalid #line directive (extra garbage after "
"line number).");
return;
}
/* Now we can assign the new values to yyloc. */
yylloc.text = set_file_name(buf); yylloc.text = set_file_name(buf);
yylloc.first_line = lineno;
qt2 += 1;
yylloc.first_line = strtoul(qt2,0,0);
} }
/*
* The line directive matches lines of the form `line N "foo" M and
* calls this function. Here I parse out the file name and line
* number, and change the yylloc to suite. M is ignored.
*/
static void line_directive2() static void line_directive2()
{ {
assert(strncmp(yytext,"`line",5) == 0); char *cpr;
char*cp = yytext + strlen("`line"); /* Skip any leading space. */
cp += strspn(cp, " "); char *cp = strchr(yytext, '`');
yylloc.first_line = strtoul(cp,&cp,10); /* Skip the `line directive. */
assert(strncmp(cp, "`line", 5) == 0);
cp += 5;
yylloc.first_line -= 1; /* strtoul skips leading space. */
unsigned long lineno = strtoul(cp, &cpr, 10);
if (cp == cpr) {
VLerror(yylloc, "Invalid line number for `line directive.");
return;
}
lineno -= 1;
cp = cpr;
cp += strspn(cp, " "); /* Skip the space between the line number and the file name. */
if (*cp == 0) return; cpr += strspn(cp, " \t");
if (cp == cpr) {
VLerror(yylloc, "Invalid `line directive (missing space after "
"line number).");
return;
}
cp = cpr;
char*qt1 = strchr(yytext, '"'); /* Find the starting " and skip it. */
assert(qt1); char*fn_start = strchr(cp, '"');
qt1 += 1; if (cp != fn_start) {
VLerror(yylloc, "Invalid `line directive (file name start).");
return;
}
fn_start += 1;
char*qt2 = strchr(qt1, '"'); /* Find the last ". */
assert(qt2); char*fn_end = strrchr(fn_start, '"');
if (!fn_end) {
VLerror(yylloc, "Invalid `line directive (file name end).");
return;
}
char*buf = new char[qt2-qt1+1]; /* Skip the space after the file name. */
strncpy(buf, qt1, qt2-qt1); cp = fn_end + 1;
buf[qt2-qt1] = 0; cpr = cp;
cpr += strspn(cp, " \t");
if (cp == cpr) {
VLerror(yylloc, "Invalid `line directive (missing space after "
"file name).");
return;
}
cp = cpr;
/* Check that the level is correct, we do not need the level. */
if (strspn(cp, "012") != 1) {
VLerror(yylloc, "Invalid level for `line directive.");
return;
}
cp += 1;
/* Verify that only space and/or a single line comment is left. */
cp += strspn(cp, " \t");
if (strncmp(cp, "//", 2) != 0 &&
(size_t)(cp-yytext) != strlen(yytext)) {
VLerror(yylloc, "Invalid `line directive (extra garbage after "
"level).");
return;
}
/* Copy the file name and assign it and the line number to yylloc. */
char*buf = new char[fn_end-fn_start+1];
strncpy(buf, fn_start, fn_end-fn_start);
buf[fn_end-fn_start] = 0;
yylloc.text = set_file_name(buf); yylloc.text = set_file_name(buf);
yylloc.first_line = lineno;
} }
extern FILE*vl_input; extern FILE*vl_input;
@ -1105,3 +1381,17 @@ void reset_lexor()
/* Announce the first file name. */ /* Announce the first file name. */
yylloc.text = set_file_name(strdupnew(vl_file.c_str())); yylloc.text = set_file_name(strdupnew(vl_file.c_str()));
} }
/*
* Modern version of flex (>=2.5.9) can clean up the scanner data.
*/
void destroy_lexor()
{
# ifdef FLEX_SCANNER
# if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5
# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9
yylex_destroy();
# endif
# endif
# endif
}

View File

@ -11,165 +11,183 @@
%} %}
struct lexor_keyword { const char*name; int mask; int tokenType; }; struct lexor_keyword { const char*name; int mask; int tokenType; };
%% %%
abs, GN_KEYWORDS_VAMS_2_3, K_abs abs, GN_KEYWORDS_VAMS_2_3, K_abs
abstol, GN_KEYWORDS_VAMS_2_3, K_abstol abstol, GN_KEYWORDS_VAMS_2_3, K_abstol
access, GN_KEYWORDS_VAMS_2_3, K_access access, GN_KEYWORDS_VAMS_2_3, K_access
acos, GN_KEYWORDS_VAMS_2_3, K_acos acos, GN_KEYWORDS_VAMS_2_3, K_acos
acosh, GN_KEYWORDS_VAMS_2_3, K_acosh acosh, GN_KEYWORDS_VAMS_2_3, K_acosh
always, GN_KEYWORDS_1364_1995, K_always always, GN_KEYWORDS_1364_1995, K_always
always_comb, GN_KEYWORDS_1800_2005, K_always_comb always_comb, GN_KEYWORDS_1800_2005, K_always_comb
always_ff, GN_KEYWORDS_1800_2005, K_always_ff always_ff, GN_KEYWORDS_1800_2005, K_always_ff
always_latch, GN_KEYWORDS_1800_2005, K_always_latch always_latch, GN_KEYWORDS_1800_2005, K_always_latch
analog, GN_KEYWORDS_VAMS_2_3, K_analog analog, GN_KEYWORDS_VAMS_2_3, K_analog
and, GN_KEYWORDS_1364_1995, K_and and, GN_KEYWORDS_1364_1995, K_and
asin, GN_KEYWORDS_VAMS_2_3, K_asin asin, GN_KEYWORDS_VAMS_2_3, K_asin
asinh, GN_KEYWORDS_VAMS_2_3, K_asinh asinh, GN_KEYWORDS_VAMS_2_3, K_asinh
assert, GN_KEYWORDS_1800_2005, K_assert assert, GN_KEYWORDS_1800_2005, K_assert
assign, GN_KEYWORDS_1364_1995, K_assign assign, GN_KEYWORDS_1364_1995, K_assign
atan, GN_KEYWORDS_VAMS_2_3, K_atan atan, GN_KEYWORDS_VAMS_2_3, K_atan
atan2, GN_KEYWORDS_VAMS_2_3, K_atan2 atan2, GN_KEYWORDS_VAMS_2_3, K_atan2
atanh, GN_KEYWORDS_VAMS_2_3, K_atanh atanh, GN_KEYWORDS_VAMS_2_3, K_atanh
automatic, GN_KEYWORDS_1364_2001, K_automatic automatic, GN_KEYWORDS_1364_2001, K_automatic
begin, GN_KEYWORDS_1364_1995, K_begin begin, GN_KEYWORDS_1364_1995, K_begin
bool, GN_KEYWORDS_ICARUS, K_bool bool, GN_KEYWORDS_ICARUS, K_bool
buf, GN_KEYWORDS_1364_1995, K_buf buf, GN_KEYWORDS_1364_1995, K_buf
bufif0, GN_KEYWORDS_1364_1995, K_bufif0 bufif0, GN_KEYWORDS_1364_1995, K_bufif0
bufif1, GN_KEYWORDS_1364_1995, K_bufif1 bufif1, GN_KEYWORDS_1364_1995, K_bufif1
case, GN_KEYWORDS_1364_1995, K_case case, GN_KEYWORDS_1364_1995, K_case
casex, GN_KEYWORDS_1364_1995, K_casex casex, GN_KEYWORDS_1364_1995, K_casex
casez, GN_KEYWORDS_1364_1995, K_casez casez, GN_KEYWORDS_1364_1995, K_casez
ceil, GN_KEYWORDS_VAMS_2_3, K_ceil ceil, GN_KEYWORDS_VAMS_2_3, K_ceil
cmos, GN_KEYWORDS_1364_1995, K_cmos cell, GN_KEYWORDS_1364_2001_CONFIG, K_cell
continuous, GN_KEYWORDS_VAMS_2_3, K_continuous cmos, GN_KEYWORDS_1364_1995, K_cmos
cos, GN_KEYWORDS_VAMS_2_3, K_cos config, GN_KEYWORDS_1364_2001_CONFIG, K_config
cosh, GN_KEYWORDS_VAMS_2_3, K_cosh continuous, GN_KEYWORDS_VAMS_2_3, K_continuous
ddt_nature, GN_KEYWORDS_VAMS_2_3, K_ddt_nature cos, GN_KEYWORDS_VAMS_2_3, K_cos
deassign, GN_KEYWORDS_1364_1995, K_deassign cosh, GN_KEYWORDS_VAMS_2_3, K_cosh
default, GN_KEYWORDS_1364_1995, K_default ddt_nature, GN_KEYWORDS_VAMS_2_3, K_ddt_nature
defparam, GN_KEYWORDS_1364_1995, K_defparam deassign, GN_KEYWORDS_1364_1995, K_deassign
disable, GN_KEYWORDS_1364_1995, K_disable default, GN_KEYWORDS_1364_1995, K_default
discipline, GN_KEYWORDS_VAMS_2_3, K_discipline defparam, GN_KEYWORDS_1364_1995, K_defparam
discrete, GN_KEYWORDS_VAMS_2_3, K_discrete design, GN_KEYWORDS_1364_2001_CONFIG, K_design
domain, GN_KEYWORDS_VAMS_2_3, K_domain disable, GN_KEYWORDS_1364_1995, K_disable
edge, GN_KEYWORDS_1364_1995, K_edge discipline, GN_KEYWORDS_VAMS_2_3, K_discipline
else, GN_KEYWORDS_1364_1995, K_else discrete, GN_KEYWORDS_VAMS_2_3, K_discrete
end, GN_KEYWORDS_1364_1995, K_end domain, GN_KEYWORDS_VAMS_2_3, K_domain
endcase, GN_KEYWORDS_1364_1995, K_endcase edge, GN_KEYWORDS_1364_1995, K_edge
enddiscipline, GN_KEYWORDS_VAMS_2_3, K_enddiscipline else, GN_KEYWORDS_1364_1995, K_else
endfunction, GN_KEYWORDS_1364_1995, K_endfunction end, GN_KEYWORDS_1364_1995, K_end
endgenerate, GN_KEYWORDS_1364_1995, K_endgenerate endcase, GN_KEYWORDS_1364_1995, K_endcase
endmodule, GN_KEYWORDS_1364_1995, K_endmodule endconfig, GN_KEYWORDS_1364_2001_CONFIG, K_endconfig
endnature, GN_KEYWORDS_VAMS_2_3, K_endnature enddiscipline, GN_KEYWORDS_VAMS_2_3, K_enddiscipline
endprimitive, GN_KEYWORDS_1364_1995, K_endprimitive endfunction, GN_KEYWORDS_1364_1995, K_endfunction
endspecify, GN_KEYWORDS_1364_1995, K_endspecify endgenerate, GN_KEYWORDS_1364_2001, K_endgenerate
endtable, GN_KEYWORDS_1364_1995, K_endtable endmodule, GN_KEYWORDS_1364_1995, K_endmodule
endtask, GN_KEYWORDS_1364_1995, K_endtask endnature, GN_KEYWORDS_VAMS_2_3, K_endnature
event, GN_KEYWORDS_1364_1995, K_event endprimitive, GN_KEYWORDS_1364_1995, K_endprimitive
exclude, GN_KEYWORDS_VAMS_2_3, K_exclude endspecify, GN_KEYWORDS_1364_1995, K_endspecify
exp, GN_KEYWORDS_VAMS_2_3, K_exp endtable, GN_KEYWORDS_1364_1995, K_endtable
floor, GN_KEYWORDS_VAMS_2_3, K_floor endtask, GN_KEYWORDS_1364_1995, K_endtask
flow, GN_KEYWORDS_VAMS_2_3, K_flow event, GN_KEYWORDS_1364_1995, K_event
for, GN_KEYWORDS_1364_1995, K_for exclude, GN_KEYWORDS_VAMS_2_3, K_exclude
force, GN_KEYWORDS_1364_1995, K_force exp, GN_KEYWORDS_VAMS_2_3, K_exp
forever, GN_KEYWORDS_1364_1995, K_forever floor, GN_KEYWORDS_VAMS_2_3, K_floor
fork, GN_KEYWORDS_1364_1995, K_fork flow, GN_KEYWORDS_VAMS_2_3, K_flow
from, GN_KEYWORDS_VAMS_2_3, K_from for, GN_KEYWORDS_1364_1995, K_for
function, GN_KEYWORDS_1364_1995, K_function force, GN_KEYWORDS_1364_1995, K_force
generate, GN_KEYWORDS_1364_2001, K_generate forever, GN_KEYWORDS_1364_1995, K_forever
genvar, GN_KEYWORDS_1364_2001, K_genvar fork, GN_KEYWORDS_1364_1995, K_fork
ground, GN_KEYWORDS_VAMS_2_3, K_ground from, GN_KEYWORDS_VAMS_2_3, K_from
highz0, GN_KEYWORDS_1364_1995, K_highz0 function, GN_KEYWORDS_1364_1995, K_function
highz1, GN_KEYWORDS_1364_1995, K_highz1 generate, GN_KEYWORDS_1364_2001, K_generate
hypot, GN_KEYWORDS_VAMS_2_3, K_hypot genvar, GN_KEYWORDS_1364_2001, K_genvar
idt_nature, GN_KEYWORDS_VAMS_2_3, K_idt_nature ground, GN_KEYWORDS_VAMS_2_3, K_ground
if, GN_KEYWORDS_1364_1995, K_if highz0, GN_KEYWORDS_1364_1995, K_highz0
ifnone, GN_KEYWORDS_1364_1995, K_ifnone highz1, GN_KEYWORDS_1364_1995, K_highz1
inf, GN_KEYWORDS_VAMS_2_3, K_inf hypot, GN_KEYWORDS_VAMS_2_3, K_hypot
initial, GN_KEYWORDS_1364_1995, K_initial idt_nature, GN_KEYWORDS_VAMS_2_3, K_idt_nature
inout, GN_KEYWORDS_1364_1995, K_inout if, GN_KEYWORDS_1364_1995, K_if
input, GN_KEYWORDS_1364_1995, K_input ifnone, GN_KEYWORDS_1364_1995, K_ifnone
integer, GN_KEYWORDS_1364_1995, K_integer incdir, GN_KEYWORDS_1364_2001_CONFIG, K_incdir
join, GN_KEYWORDS_1364_1995, K_join include, GN_KEYWORDS_1364_2001_CONFIG, K_include
large, GN_KEYWORDS_1364_1995, K_large inf, GN_KEYWORDS_VAMS_2_3, K_inf
ln, GN_KEYWORDS_VAMS_2_3, K_ln initial, GN_KEYWORDS_1364_1995, K_initial
localparam, GN_KEYWORDS_1364_2001, K_localparam inout, GN_KEYWORDS_1364_1995, K_inout
log, GN_KEYWORDS_VAMS_2_3, K_log input, GN_KEYWORDS_1364_1995, K_input
logic, GN_KEYWORDS_ICARUS, K_logic instance, GN_KEYWORDS_1364_2001_CONFIG, K_instance
macromodule, GN_KEYWORDS_1364_1995, K_macromodule integer, GN_KEYWORDS_1364_1995, K_integer
max, GN_KEYWORDS_VAMS_2_3, K_max join, GN_KEYWORDS_1364_1995, K_join
medium, GN_KEYWORDS_1364_1995, K_medium large, GN_KEYWORDS_1364_1995, K_large
min, GN_KEYWORDS_VAMS_2_3, K_min liblist, GN_KEYWORDS_1364_2001_CONFIG, K_liblist
module, GN_KEYWORDS_1364_1995, K_module library, GN_KEYWORDS_1364_2001_CONFIG, K_library
nand, GN_KEYWORDS_1364_1995, K_nand ln, GN_KEYWORDS_VAMS_2_3, K_ln
nature, GN_KEYWORDS_VAMS_2_3, K_nature localparam, GN_KEYWORDS_1364_2001, K_localparam
negedge, GN_KEYWORDS_1364_1995, K_negedge log, GN_KEYWORDS_VAMS_2_3, K_log
nmos, GN_KEYWORDS_1364_1995, K_nmos logic, GN_KEYWORDS_ICARUS, K_logic
nor, GN_KEYWORDS_1364_1995, K_nor macromodule, GN_KEYWORDS_1364_1995, K_macromodule
not, GN_KEYWORDS_1364_1995, K_not max, GN_KEYWORDS_VAMS_2_3, K_max
notif0, GN_KEYWORDS_1364_1995, K_notif0 medium, GN_KEYWORDS_1364_1995, K_medium
notif1, GN_KEYWORDS_1364_1995, K_notif1 min, GN_KEYWORDS_VAMS_2_3, K_min
or, GN_KEYWORDS_1364_1995, K_or module, GN_KEYWORDS_1364_1995, K_module
output, GN_KEYWORDS_1364_1995, K_output nand, GN_KEYWORDS_1364_1995, K_nand
parameter, GN_KEYWORDS_1364_1995, K_parameter nature, GN_KEYWORDS_VAMS_2_3, K_nature
pmos, GN_KEYWORDS_1364_1995, K_pmos negedge, GN_KEYWORDS_1364_1995, K_negedge
posedge, GN_KEYWORDS_1364_1995, K_posedge nmos, GN_KEYWORDS_1364_1995, K_nmos
potential, GN_KEYWORDS_VAMS_2_3, K_potential nor, GN_KEYWORDS_1364_1995, K_nor
pow, GN_KEYWORDS_VAMS_2_3, K_pow noshowcancelled, GN_KEYWORDS_1364_2001, K_noshowcancelled
primitive, GN_KEYWORDS_1364_1995, K_primitive not, GN_KEYWORDS_1364_1995, K_not
pull0, GN_KEYWORDS_1364_1995, K_pull0 notif0, GN_KEYWORDS_1364_1995, K_notif0
pull1, GN_KEYWORDS_1364_1995, K_pull1 notif1, GN_KEYWORDS_1364_1995, K_notif1
pulldown, GN_KEYWORDS_1364_1995, K_pulldown or, GN_KEYWORDS_1364_1995, K_or
pullup, GN_KEYWORDS_1364_1995, K_pullup output, GN_KEYWORDS_1364_1995, K_output
rcmos, GN_KEYWORDS_1364_1995, K_rcmos parameter, GN_KEYWORDS_1364_1995, K_parameter
real, GN_KEYWORDS_1364_1995, K_real pmos, GN_KEYWORDS_1364_1995, K_pmos
realtime, GN_KEYWORDS_1364_1995, K_realtime posedge, GN_KEYWORDS_1364_1995, K_posedge
reg, GN_KEYWORDS_1364_1995, K_reg potential, GN_KEYWORDS_VAMS_2_3, K_potential
release, GN_KEYWORDS_1364_1995, K_release pow, GN_KEYWORDS_VAMS_2_3, K_pow
repeat, GN_KEYWORDS_1364_1995, K_repeat primitive, GN_KEYWORDS_1364_1995, K_primitive
rnmos, GN_KEYWORDS_1364_1995, K_rnmos pull0, GN_KEYWORDS_1364_1995, K_pull0
rpmos, GN_KEYWORDS_1364_1995, K_rpmos pull1, GN_KEYWORDS_1364_1995, K_pull1
rtran, GN_KEYWORDS_1364_1995, K_rtran pulldown, GN_KEYWORDS_1364_1995, K_pulldown
rtranif0, GN_KEYWORDS_1364_1995, K_rtranif0 pullup, GN_KEYWORDS_1364_1995, K_pullup
rtranif1, GN_KEYWORDS_1364_1995, K_rtranif1 pulsestyle_onevent, GN_KEYWORDS_1364_2001, K_pulsestyle_onevent
scalared, GN_KEYWORDS_1364_1995, K_scalared pulsestyle_ondetect, GN_KEYWORDS_1364_2001, K_pulsestyle_ondetect
signed, GN_KEYWORDS_1364_2001, K_signed rcmos, GN_KEYWORDS_1364_1995, K_rcmos
sin, GN_KEYWORDS_VAMS_2_3, K_sin real, GN_KEYWORDS_1364_1995, K_real
sinh, GN_KEYWORDS_VAMS_2_3, K_sinh realtime, GN_KEYWORDS_1364_1995, K_realtime
small, GN_KEYWORDS_1364_1995, K_small reg, GN_KEYWORDS_1364_1995, K_reg
specify, GN_KEYWORDS_1364_1995, K_specify release, GN_KEYWORDS_1364_1995, K_release
specparam, GN_KEYWORDS_1364_1995, K_specparam repeat, GN_KEYWORDS_1364_1995, K_repeat
sqrt, GN_KEYWORDS_VAMS_2_3, K_sqrt rnmos, GN_KEYWORDS_1364_1995, K_rnmos
string, GN_KEYWORDS_VAMS_2_3, K_string rpmos, GN_KEYWORDS_1364_1995, K_rpmos
strong0, GN_KEYWORDS_1364_1995, K_strong0 rtran, GN_KEYWORDS_1364_1995, K_rtran
strong1, GN_KEYWORDS_1364_1995, K_strong1 rtranif0, GN_KEYWORDS_1364_1995, K_rtranif0
supply0, GN_KEYWORDS_1364_1995, K_supply0 rtranif1, GN_KEYWORDS_1364_1995, K_rtranif1
supply1, GN_KEYWORDS_1364_1995, K_supply1 scalared, GN_KEYWORDS_1364_1995, K_scalared
table, GN_KEYWORDS_1364_1995, K_table showcancelled, GN_KEYWORDS_1364_2001, K_showcancelled
tan, GN_KEYWORDS_VAMS_2_3, K_tan signed, GN_KEYWORDS_1364_2001, K_signed
tanh, GN_KEYWORDS_VAMS_2_3, K_tanh sin, GN_KEYWORDS_VAMS_2_3, K_sin
task, GN_KEYWORDS_1364_1995, K_task sinh, GN_KEYWORDS_VAMS_2_3, K_sinh
time, GN_KEYWORDS_1364_1995, K_time small, GN_KEYWORDS_1364_1995, K_small
tran, GN_KEYWORDS_1364_1995, K_tran specify, GN_KEYWORDS_1364_1995, K_specify
tranif0, GN_KEYWORDS_1364_1995, K_tranif0 specparam, GN_KEYWORDS_1364_1995, K_specparam
tranif1, GN_KEYWORDS_1364_1995, K_tranif1 sqrt, GN_KEYWORDS_VAMS_2_3, K_sqrt
tri, GN_KEYWORDS_1364_1995, K_tri string, GN_KEYWORDS_VAMS_2_3, K_string
tri0, GN_KEYWORDS_1364_1995, K_tri0 strong0, GN_KEYWORDS_1364_1995, K_strong0
tri1, GN_KEYWORDS_1364_1995, K_tri1 strong1, GN_KEYWORDS_1364_1995, K_strong1
triand, GN_KEYWORDS_1364_1995, K_triand supply0, GN_KEYWORDS_1364_1995, K_supply0
trior, GN_KEYWORDS_1364_1995, K_trior supply1, GN_KEYWORDS_1364_1995, K_supply1
trireg, GN_KEYWORDS_1364_1995, K_trireg table, GN_KEYWORDS_1364_1995, K_table
units, GN_KEYWORDS_VAMS_2_3, K_units tan, GN_KEYWORDS_VAMS_2_3, K_tan
vectored, GN_KEYWORDS_1364_1995, K_vectored tanh, GN_KEYWORDS_VAMS_2_3, K_tanh
wait, GN_KEYWORDS_1364_1995, K_wait task, GN_KEYWORDS_1364_1995, K_task
wand, GN_KEYWORDS_1364_1995, K_wand time, GN_KEYWORDS_1364_1995, K_time
weak0, GN_KEYWORDS_1364_1995, K_weak0 tran, GN_KEYWORDS_1364_1995, K_tran
weak1, GN_KEYWORDS_1364_1995, K_weak1 tranif0, GN_KEYWORDS_1364_1995, K_tranif0
while, GN_KEYWORDS_1364_1995, K_while tranif1, GN_KEYWORDS_1364_1995, K_tranif1
wire, GN_KEYWORDS_1364_1995, K_wire tri, GN_KEYWORDS_1364_1995, K_tri
wone, GN_KEYWORDS_1364_1995, K_wone tri0, GN_KEYWORDS_1364_1995, K_tri0
wor, GN_KEYWORDS_1364_1995, K_wor tri1, GN_KEYWORDS_1364_1995, K_tri1
xnor, GN_KEYWORDS_1364_1995, K_xnor triand, GN_KEYWORDS_1364_1995, K_triand
xor, GN_KEYWORDS_1364_1995, K_xor trior, GN_KEYWORDS_1364_1995, K_trior
trireg, GN_KEYWORDS_1364_1995, K_trireg
units, GN_KEYWORDS_VAMS_2_3, K_units
# Reserved for future use!
unsigned, GN_KEYWORDS_1364_2001, K_unsigned
use, GN_KEYWORDS_1364_2001_CONFIG, K_use
uwire, GN_KEYWORDS_1364_2005, K_uwire
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
# This is the name originally proposed for uwire and is deprecated!
wone, GN_KEYWORDS_1364_2005, 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_mask = 0;

View File

@ -53,6 +53,8 @@ PLI_INT32 tf_igetp(PLI_INT32 n, void *obj)
{ {
value.format = vpiStringVal; value.format = vpiStringVal;
vpi_get_value(arg_h, &value); vpi_get_value(arg_h, &value);
/* The following may generate a compilation warning, but this
* functionality is required by some versions of the standard. */
rtn = (int) value.value.str; /* Oh my */ rtn = (int) value.value.str; /* Oh my */
} else { } else {
value.format = vpiIntVal; value.format = vpiIntVal;

78
main.cc
View File

@ -77,7 +77,7 @@ extern "C" const char*optarg;
/* Count errors detected in flag processing. */ /* Count errors detected in flag processing. */
unsigned flag_errors = 0; unsigned flag_errors = 0;
const char*basedir = "."; const char*basedir = strdup(".");
/* /*
* These are the language support control flags. These support which * These are the language support control flags. These support which
@ -115,6 +115,9 @@ bool warn_implicit = false;
bool warn_timescale = false; bool warn_timescale = false;
bool warn_portbinding = false; bool warn_portbinding = false;
bool warn_inf_loop = false; bool warn_inf_loop = false;
bool warn_ob_select = false;
bool warn_sens_entire_vec = false;
bool warn_sens_entire_arr = false;
bool error_implicit = false; bool error_implicit = false;
@ -128,6 +131,13 @@ bool debug_elab_pexpr = false;
bool debug_synth2 = false; bool debug_synth2 = false;
bool debug_optimizer = false; bool debug_optimizer = false;
/*
* Miscellaneous flags.
*/
bool disable_virtual_pins = false;
unsigned long array_size_limit = 16777216; // Minimum required by IEEE-1364?
unsigned recursive_mod_limit = 10;
/* /*
* Verbose messages enabled. * Verbose messages enabled.
*/ */
@ -135,6 +145,9 @@ bool verbose_flag = false;
unsigned integer_width = 32; unsigned integer_width = 32;
int def_ts_units = 0;
int def_ts_prec = 0;
/* /*
* Keep a heap of identifier strings that I encounter. This is a more * Keep a heap of identifier strings that I encounter. This is a more
* efficient way to allocate those strings. * efficient way to allocate those strings.
@ -214,6 +227,9 @@ static void process_generation_flag(const char*gen)
} else if (strcmp(gen,"2001") == 0) { } else if (strcmp(gen,"2001") == 0) {
generation_flag = GN_VER2001; generation_flag = GN_VER2001;
} else if (strcmp(gen,"2001-noconfig") == 0) {
generation_flag = GN_VER2001_NOCONFIG;
} else if (strcmp(gen,"2005") == 0) { } else if (strcmp(gen,"2005") == 0) {
generation_flag = GN_VER2005; generation_flag = GN_VER2005;
@ -267,7 +283,7 @@ static void parm_to_flagmap(const string&flag)
unsigned off = flag.find('='); unsigned off = flag.find('=');
if (off > flag.size()) { if (off > flag.size()) {
key = flag; key = flag;
value = ""; value = strdup("");
} else { } else {
key = flag.substr(0, off); key = flag.substr(0, off);
@ -386,6 +402,7 @@ static void read_iconfig_file(const char*ipath)
} }
if (strcmp(buf, "basedir") == 0) { if (strcmp(buf, "basedir") == 0) {
free((char *)basedir);
basedir = strdup(cp); basedir = strdup(cp);
} else if (strcmp(buf, "debug") == 0) { } else if (strcmp(buf, "debug") == 0) {
@ -459,6 +476,7 @@ static void read_iconfig_file(const char*ipath)
flags["VPI_MODULE_LIST"] = vpi_module_list; flags["VPI_MODULE_LIST"] = vpi_module_list;
} else if (strcmp(buf, "out") == 0) { } else if (strcmp(buf, "out") == 0) {
free((char *)flags["-o"]);
flags["-o"] = strdup(cp); flags["-o"] = strdup(cp);
} else if (strcmp(buf, "sys_func") == 0) { } else if (strcmp(buf, "sys_func") == 0) {
@ -476,12 +494,21 @@ static void read_iconfig_file(const char*ipath)
case 'l': case 'l':
warn_inf_loop = true; warn_inf_loop = true;
break; break;
case 's':
warn_ob_select = true;
break;
case 'p': case 'p':
warn_portbinding = true; warn_portbinding = true;
break; break;
case 't': case 't':
warn_timescale = true; warn_timescale = true;
break; break;
case 'v':
warn_sens_entire_vec = true;
break;
case 'a':
warn_sens_entire_arr = true;
break;
default: default:
break; break;
} }
@ -516,6 +543,7 @@ static void read_iconfig_file(const char*ipath)
} }
} }
fclose(ifile);
} }
extern Design* elaborate(list <perm_string> root); extern Design* elaborate(list <perm_string> root);
@ -542,6 +570,30 @@ inline static void times(struct tms *) { }
inline static double cycles_diff(struct tms *a, struct tms *b) { return 0; } inline static double cycles_diff(struct tms *a, struct tms *b) { return 0; }
#endif // ! defined(HAVE_TIMES) #endif // ! defined(HAVE_TIMES)
static void EOC_cleanup(void)
{
cleanup_sys_func_table();
for (list<const char*>::iterator suf = library_suff.begin() ;
suf != library_suff.end() ; suf ++ ) {
free((char *)*suf);
}
library_suff.clear();
free((char *) basedir);
free(ivlpp_string);
free(depfile_name);
for (map<string, const char*>::iterator flg = flags.begin() ;
flg != flags.end() ; flg ++ ) {
free((char *)flg->second);
}
flags.clear();
lex_strings.cleanup();
filename_strings.cleanup();
}
int main(int argc, char*argv[]) int main(int argc, char*argv[])
{ {
bool help_flag = false; bool help_flag = false;
@ -554,11 +606,11 @@ int main(int argc, char*argv[])
struct tms cycles[5]; struct tms cycles[5];
library_suff.push_back(".v"); library_suff.push_back(strdup(".v"));
vpi_module_list = strdup("system"); vpi_module_list = strdup("system");
flags["VPI_MODULE_LIST"] = vpi_module_list; flags["VPI_MODULE_LIST"] = vpi_module_list;
flags["-o"] = "a.out"; flags["-o"] = strdup("a.out");
min_typ_max_flag = TYP; min_typ_max_flag = TYP;
min_typ_max_warn = 10; min_typ_max_warn = 10;
@ -650,9 +702,10 @@ int main(int argc, char*argv[])
lexor_keyword_mask |= GN_KEYWORDS_1364_1995; lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
break; break;
case GN_VER2001: case GN_VER2001:
lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG;
case GN_VER2001_NOCONFIG:
lexor_keyword_mask |= GN_KEYWORDS_1364_1995; lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
lexor_keyword_mask |= GN_KEYWORDS_1364_2001; lexor_keyword_mask |= GN_KEYWORDS_1364_2001;
lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG;
break; break;
case GN_VER2005: case GN_VER2005:
lexor_keyword_mask |= GN_KEYWORDS_1364_1995; lexor_keyword_mask |= GN_KEYWORDS_1364_1995;
@ -680,6 +733,9 @@ int main(int argc, char*argv[])
case GN_VER1995: case GN_VER1995:
cout << "IEEE1364-1995"; cout << "IEEE1364-1995";
break; break;
case GN_VER2001_NOCONFIG:
cout << "IEEE1364-2001-noconfig";
break;
case GN_VER2001: case GN_VER2001:
cout << "IEEE1364-2001"; cout << "IEEE1364-2001";
break; break;
@ -709,7 +765,17 @@ int main(int argc, char*argv[])
cout << endl << "PARSING INPUT" << endl; cout << endl << "PARSING INPUT" << endl;
} }
const char *flag_tmp = flags["DISABLE_VIRTUAL_PINS"];
if (flag_tmp) disable_virtual_pins = strcmp(flag_tmp,"true")==0;
flag_tmp = flags["ARRAY_SIZE_LIMIT"];
if (flag_tmp) array_size_limit = strtoul(flag_tmp,NULL,0);
flag_tmp = flags["RECURSIVE_MOD_LIMIT"];
if (flag_tmp) recursive_mod_limit = strtoul(flag_tmp,NULL,0);
/* Parse the input. Make the pform. */ /* Parse the input. Make the pform. */
pform_set_timescale(def_ts_units, def_ts_prec, 0, 0);
int rc = pform_parse(argv[optind]); int rc = pform_parse(argv[optind]);
if (pf_path) { if (pf_path) {
@ -906,6 +972,8 @@ int main(int argc, char*argv[])
<< endl; << endl;
} }
delete des;
EOC_cleanup();
return 0; return 0;
errors_summary: errors_summary:

View File

@ -1,3 +1,8 @@
Please NOTE:
These directions are slightly outdated and need to be updated.
The plan is to rewrite all this using the latest MinGW at
some time in the not too distant future (CR Aug. 2009)
MINGW PORT OF ICARUS VERILOG MINGW PORT OF ICARUS VERILOG
@ -49,7 +54,7 @@ critical, but these are the versions I use.
Mingw32-5.x <http://www.mingw.org> Mingw32-5.x <http://www.mingw.org>
... including the sub-packages binutils, gcc-core and gcc-g++ ... including the sub-packages binutils, gcc-core and gcc-g++
if you are given the option. if you are given the option.
readline-4.2-20010727.zip <http://mingwrep.sourceforge.net> readline-5.0-1 <http://gnuwin32.sourceforge.net>
bzip2-1.0.3 <http://gnuwin32.sourceforge.net> bzip2-1.0.3 <http://gnuwin32.sourceforge.net>
zlib-1.2.3 <http://gnuwin32.sourceforge.net> zlib-1.2.3 <http://gnuwin32.sourceforge.net>
gperf-3.0.1 <http://gnuwin32.sourceforge.net> gperf-3.0.1 <http://gnuwin32.sourceforge.net>
@ -79,7 +84,7 @@ Download the msys-1.x.x.exe and msysdtc-1.x.x.exe binaries. These are
self-installing packages. Install msys first, and then msysDTC. Most self-installing packages. Install msys first, and then msysDTC. Most
likely, you want to install them in c:/msys. (The msysDTK is installed likely, you want to install them in c:/msys. (The msysDTK is installed
in the same location, as it is an add-on.) in the same location, as it is an add-on.)
This install should be easy and reliable. This install should be easy and reliable.
The installation will leave an "msys" icon on your desktop and in the The installation will leave an "msys" icon on your desktop and in the
@ -110,29 +115,6 @@ Finally, as part of installing the mingw32 compilers, remember to add
the mingw/bin directory to your path. You will need that to be able to the mingw/bin directory to your path. You will need that to be able to
find the compilers later. find the compilers later.
* Install Mingw32 Packages
There is a collection of precompiled libraries and add-on packages
that are intended for use with the Mingw32 compiler. These do not come
with simplified Windows installers, but they are pretty easy to
install by hand. Icarus Verilog uses the readline-4.2 package from
that collection.
Since I installed Mingw32 in c:\mingw, I also created a
Mingw-packages directory called c:\mingw-packages. The install, then,
is as easy as this:
<msys shell>
$ cd c:/mingw-packages
$ unzip readline-4.2-20010727.zip
[lots of inflating...]
There is no need to adjust your execution path for this package as we
are only using a library out of here. However, do remember the
directory name, as you will need it later.
Done. On to the next packages.
* Install GnuWin32 Packages * Install GnuWin32 Packages
The GnuWin32 project is a collections of open source programs and The GnuWin32 project is a collections of open source programs and
@ -148,6 +130,7 @@ You will need these gnuwin32 packages to compile Icarus Verilog:
gperf-3.0.1.exe gperf-3.0.1.exe
bison-2.1.exe bison-2.1.exe
flex-2.5.4a.exe flex-2.5.4a.exe
readline-5.0-1.exe
I suggest creating a common directory for holding all your gnuwin32 I suggest creating a common directory for holding all your gnuwin32
packages. I use C:\gnuwin32. The download page at the gnuwin32 site packages. I use C:\gnuwin32. The download page at the gnuwin32 site
@ -218,8 +201,8 @@ without white space.
Now, configure the source to make the makefiles and configuration Now, configure the source to make the makefiles and configuration
details. Run these commands: details. Run these commands:
$ CPPFLAGS="-Ic:/gnuwin32/include -Ic:/mingw-packages/include" $ CPPFLAGS="-Ic:/gnuwin32/include
$ LDFLAGS="-Lc:/gnuwin32/lib -Lc:/mingw-packages/lib" $ LDFLAGS="-Lc:/gnuwin32/lib
$ export CPPFLAGS LDFLAGS $ export CPPFLAGS LDFLAGS
$ ./configure --prefix=c:/iverilog $ ./configure --prefix=c:/iverilog
@ -271,7 +254,8 @@ You may find that you need to put some of the prerequisite DLLs into
the d:\iverilog\bin directory. These include: the d:\iverilog\bin directory. These include:
c:\mingw\bin\mingw10.dll c:\mingw\bin\mingw10.dll
c:\mingw-packages\bin\libreadline.dll c:\gnuwin32\bin\readline.dll
c:\gnuwin32\bin\history.dll
c:\gnuwin32\bin\bzip2.dll c:\gnuwin32\bin\bzip2.dll
c:\gnuwin32\bin\zlib.dll c:\gnuwin32\bin\zlib.dll

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -490,7 +490,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
{ {
NetExpr*expr = (*cur).second.expr; NetExpr*expr = (*cur).second.expr;
assert(expr); if (expr == NULL) return; // This is an invalid parameter so return.
NetECReal*res = 0; NetECReal*res = 0;
eval_expr(expr); eval_expr(expr);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -257,15 +257,13 @@ ivl_variable_type_t NetEBMinMax::expr_type() const
NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r) NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r)
{ {
if (expr_type() == IVL_VT_REAL) if (expr_type() == IVL_VT_REAL) {
expr_width(1); expr_width(1);
else
expr_width(l->expr_width() + r->expr_width());
if (expr_type() == IVL_VT_REAL)
cast_signed(true); cast_signed(true);
else } else {
expr_width(l->expr_width() + r->expr_width());
cast_signed(l->has_sign() && r->has_sign()); cast_signed(l->has_sign() && r->has_sign());
}
} }
NetEBMult::~NetEBMult() NetEBMult::~NetEBMult()
@ -294,8 +292,8 @@ NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r)
{ {
assert(op__ == 'p'); assert(op__ == 'p');
/* This is incorrect! a * (2^b - 1) is close. */ /* You could need up to a * (2^b - 1) bits. */
expr_width(l->expr_width()+r->expr_width()); expr_width(l->expr_width());
cast_signed(l->has_sign() || r->has_sign()); cast_signed(l->has_sign() || r->has_sign());
} }
@ -438,6 +436,7 @@ NetECReal::NetECReal(const verireal&val)
: value_(val) : value_(val)
{ {
expr_width(1); expr_width(1);
cast_signed(true);
} }
NetECReal::~NetECReal() NetECReal::~NetECReal()

View File

@ -173,7 +173,7 @@ void Link::unlink()
bool Link::is_equal(const Link&that) const bool Link::is_equal(const Link&that) const
{ {
return (node_ == that.node_) && (pin_ == that.pin_); return (get_obj() == that.get_obj()) && (get_pin() == that.get_pin());
} }
bool Link::is_linked() const bool Link::is_linked() const

View File

@ -23,6 +23,7 @@
# include <cassert> # include <cassert>
# include <typeinfo> # include <typeinfo>
# include "compiler.h"
# include "netlist.h" # include "netlist.h"
# include "netmisc.h" # include "netmisc.h"
@ -114,6 +115,11 @@ NexusSet* NetESelect::nex_input(bool rem_out)
} }
result->add(*tmp); result->add(*tmp);
delete tmp; delete tmp;
/* See the comment for NetESignal below. */
if (base_ && warn_sens_entire_vec) {
cerr << get_fileline() << ": warning: @* is sensitive to all "
"bits in '" << *expr_ << "'." << endl;
}
return result; return result;
} }
@ -133,7 +139,25 @@ NexusSet* NetESFunc::nex_input(bool rem_out)
NexusSet* NetESignal::nex_input(bool rem_out) NexusSet* NetESignal::nex_input(bool rem_out)
{ {
/*
* This is not what I would expect for the various selects (bit,
* part, index, array). This code adds all the bits/array words
* instead of building the appropriate select and then using it
* as the trigger. Other simulators also add everything.
*/
NexusSet*result = new NexusSet; NexusSet*result = new NexusSet;
/* If we have an array index add it to the sensitivity list. */
if (word_) {
NexusSet*tmp;
tmp = word_->nex_input(rem_out);
result->add(*tmp);
delete tmp;
if (warn_sens_entire_arr) {
cerr << get_fileline() << ": warning: @* is sensitive to all "
<< net_->array_count() << " words in array '"
<< name() << "'." << endl;
}
}
for (unsigned idx = 0 ; idx < net_->pin_count() ; idx += 1) for (unsigned idx = 0 ; idx < net_->pin_count() ; idx += 1)
result->add(net_->pin(idx).nexus()); result->add(net_->pin(idx).nexus());

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -41,17 +41,20 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t)
events_ = 0; events_ = 0;
lcounter_ = 0; lcounter_ = 0;
is_auto_ = false; is_auto_ = false;
is_cell_ = false;
if (up) { if (up) {
default_nettype_ = up->default_nettype(); default_nettype_ = up->default_nettype();
time_unit_ = up->time_unit(); time_unit_ = up->time_unit();
time_prec_ = up->time_precision(); time_prec_ = up->time_precision();
time_from_timescale_ = up->time_from_timescale();
sib_ = up_->sub_; sib_ = up_->sub_;
up_->sub_ = this; up_->sub_ = this;
} else { } else {
default_nettype_ = NetNet::NONE; default_nettype_ = NetNet::NONE;
time_unit_ = 0; time_unit_ = 0;
time_prec_ = 0; time_prec_ = 0;
time_from_timescale_ = false;
assert(t == MODULE); assert(t == MODULE);
} }
@ -230,6 +233,31 @@ NetScope::TYPE NetScope::type() const
return type_; return type_;
} }
void NetScope::print_type(ostream&stream) const
{
switch (type_) {
case BEGIN_END:
stream << "sequential block";
break;
case FORK_JOIN:
stream << "parallel block";
break;
case FUNC:
stream << "function";
break;
case MODULE:
stream << "module <" << (module_name_ ? module_name_.str() : "")
<< "> instance";
break;
case TASK:
stream << "task";
break;
case GENBLOCK:
stream << "generate block";
break;
}
}
void NetScope::set_task_def(NetTaskDef*def) void NetScope::set_task_def(NetTaskDef*def)
{ {
assert( type_ == TASK ); assert( type_ == TASK );
@ -295,6 +323,11 @@ void NetScope::time_precision(int val)
time_prec_ = val; time_prec_ = val;
} }
void NetScope::time_from_timescale(bool val)
{
time_from_timescale_ = val;
}
int NetScope::time_unit() const int NetScope::time_unit() const
{ {
return time_unit_; return time_unit_;
@ -305,6 +338,11 @@ int NetScope::time_precision() const
return time_prec_; return time_prec_;
} }
bool NetScope::time_from_timescale() const
{
return time_from_timescale_;
}
void NetScope::default_nettype(NetNet::Type nt) void NetScope::default_nettype(NetNet::Type nt)
{ {
default_nettype_ = nt; default_nettype_ = nt;
@ -357,6 +395,20 @@ NetEvent* NetScope::find_event(perm_string name)
return 0; return 0;
} }
void NetScope::add_genvar(perm_string name, LineInfo *li)
{
assert((type_ == MODULE) || (type_ == GENBLOCK));
genvars_[name] = li;
}
LineInfo* NetScope::find_genvar(perm_string name)
{
if (genvars_.find(name) != genvars_.end())
return genvars_[name];
else
return 0;
}
void NetScope::add_signal(NetNet*net) void NetScope::add_signal(NetNet*net)
{ {
signals_map_[net->name()]=net; signals_map_[net->name()]=net;

View File

@ -78,8 +78,8 @@ ostream& operator<< (ostream&o, NetNet::Type t)
case NetNet::WIRE: case NetNet::WIRE:
o << "wire"; o << "wire";
break; break;
case NetNet::WONE: case NetNet::UWIRE:
o << "wone"; o << "uwire";
} }
return o; return o;
} }
@ -172,26 +172,51 @@ Link* find_next_output(Link*lnk)
return 0; return 0;
} }
NetPins::NetPins(unsigned npins) void NetPins::devirtualize_pins(void)
: npins_(npins)
{ {
if (pins_) return;
if (npins_ > array_size_limit) {
cerr << get_fileline() << ": error: pin count " << npins_ <<
" exceeds " << array_size_limit <<
" (set by -pARRAY_SIZE_LIMIT)" << endl;
assert(0);
}
if (debug_optimizer && npins_ > 1000) cerr << "debug: devirtualizing " << npins_ << " pins." << endl;
pins_ = new Link[npins_]; pins_ = new Link[npins_];
pins_[0].pin_zero_ = true; pins_[0].pin_zero_ = true;
pins_[0].node_ = this; pins_[0].node_ = this;
pins_[0].dir_ = default_dir_;
pins_[0].init_ = default_init_;
for (unsigned idx = 1 ; idx < npins_ ; idx += 1) { for (unsigned idx = 1 ; idx < npins_ ; idx += 1) {
pins_[idx].pin_zero_ = false; pins_[idx].pin_zero_ = false;
pins_[idx].pin_ = idx; pins_[idx].pin_ = idx;
pins_[idx].dir_ = default_dir_;
pins_[idx].init_ = default_init_;
} }
} }
bool NetPins::pins_are_virtual(void) const
{
return pins_ == NULL;
}
NetPins::NetPins(unsigned npins)
: npins_(npins)
{
pins_ = NULL; // Wait until someone asks.
if (disable_virtual_pins) devirtualize_pins(); // Ask. Bummer.
}
NetPins::~NetPins() NetPins::~NetPins()
{ {
delete[]pins_; if (pins_) delete[]pins_;
} }
Link& NetPins::pin(unsigned idx) Link& NetPins::pin(unsigned idx)
{ {
if (!pins_) devirtualize_pins();
if (idx >= npins_) { if (idx >= npins_) {
cerr << get_fileline() << ": internal error: pin("<<idx<<")" cerr << get_fileline() << ": internal error: pin("<<idx<<")"
<< " out of bounds("<<npins_<<")" << endl; << " out of bounds("<<npins_<<")" << endl;
@ -207,11 +232,27 @@ Link& NetPins::pin(unsigned idx)
const Link& NetPins::pin(unsigned idx) const const Link& NetPins::pin(unsigned idx) const
{ {
if (!pins_ && !disable_virtual_pins) {
cerr << get_fileline() << ": internal error: pin is unexpectedly"
" virtual, try again with -pDISABLE_VIRTUAL_PINS=true" << endl;
assert(0);
}
assert(pins_);
assert(idx < npins_); assert(idx < npins_);
assert(idx == 0? pins_[0].pin_zero_ : pins_[idx].pin_==idx); assert(idx == 0? pins_[0].pin_zero_ : pins_[idx].pin_==idx);
return pins_[idx]; return pins_[idx];
} }
void NetPins::set_default_dir(Link::DIR d)
{
default_dir_ = d;
}
void NetPins::set_default_init(verinum::V val)
{
default_init_ = val;
}
bool NetPins::is_linked(void) bool NetPins::is_linked(void)
{ {
bool linked_flag = false; bool linked_flag = false;
@ -228,6 +269,11 @@ bool NetPins::is_linked(void)
NetObj::NetObj(NetScope*s, perm_string n, unsigned np) NetObj::NetObj(NetScope*s, perm_string n, unsigned np)
: NetPins(np), scope_(s), name_(n), delay1_(0), delay2_(0), delay3_(0) : NetPins(np), scope_(s), name_(n), delay1_(0), delay2_(0), delay3_(0)
{ {
/* Don't
ivl_assert(*this, np > 0);
* because it would happen before we get to print a useful
* message in the NetNet constructor
*/
} }
NetObj::~NetObj() NetObj::~NetObj()
@ -269,6 +315,9 @@ NetBranch::~NetBranch()
NetBus::NetBus(NetScope*s, unsigned pin_count__) NetBus::NetBus(NetScope*s, unsigned pin_count__)
: NetObj(s, perm_string::literal(""), pin_count__) : NetObj(s, perm_string::literal(""), pin_count__)
{ {
for (unsigned idx = 0 ; idx <pin_count__ ; idx += 1) {
pin(idx).set_dir(Link::PASSIVE);
}
} }
NetBus::~NetBus() NetBus::~NetBus()
@ -442,8 +491,8 @@ const Link& NetDelaySrc::condit_pin() const
NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
: NetObj(s, n, 1), : NetObj(s, n, 1),
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), isint_(false), discipline_(0), msb_(npins-1), lsb_(0), signed_(false), isint_(false), is_scalar_(false),
dimensions_(0), discipline_(0), msb_(npins-1), lsb_(0), dimensions_(0),
s0_(0), e0_(0), local_flag_(false), eref_count_(0), lref_count_(0) s0_(0), e0_(0), local_flag_(false), eref_count_(0), lref_count_(0)
{ {
assert(s); assert(s);
@ -479,7 +528,11 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
void NetNet::initialize_value_and_dir(verinum::V init_value, Link::DIR dir) void NetNet::initialize_value_and_dir(verinum::V init_value, Link::DIR dir)
{ {
if (1) { if (pins_are_virtual()) {
if (0) cerr << "NetNet setting Link default value and dir" << endl;
set_default_init(init_value);
set_default_dir(dir);
} else {
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
pin(idx).set_dir(dir); pin(idx).set_dir(dir);
pin(idx).set_init(init_value); pin(idx).set_init(init_value);
@ -491,7 +544,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls) long ms, long ls)
: NetObj(s, n, 1), type_(t), : NetObj(s, n, 1), type_(t),
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
isint_(false), discipline_(0), msb_(ms), lsb_(ls), dimensions_(0), s0_(0), e0_(0), isint_(false), is_scalar_(false), discipline_(0), msb_(ms), lsb_(ls),
dimensions_(0), s0_(0), e0_(0),
local_flag_(false), eref_count_(0), lref_count_(0) local_flag_(false), eref_count_(0), lref_count_(0)
{ {
assert(s); assert(s);
@ -524,10 +578,16 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
static unsigned calculate_count(long s, long e) static unsigned calculate_count(long s, long e)
{ {
if (s >= e) unsigned long r;
return s - e + 1; if (s >= e) {
else r = s - e;
return e - s + 1; } else {
r = e - s;
}
if (r >= UINT_MAX) {
return 0;
}
return r + 1;
} }
NetNet::NetNet(NetScope*s, perm_string n, Type t, NetNet::NetNet(NetScope*s, perm_string n, Type t,
@ -535,10 +595,15 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
: NetObj(s, n, calculate_count(array_s, array_e)), : NetObj(s, n, calculate_count(array_s, array_e)),
type_(t), port_type_(NOT_A_PORT), type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
discipline_(0), msb_(ms), lsb_(ls), dimensions_(1), s0_(array_s), e0_(array_e), is_scalar_(false), discipline_(0), msb_(ms), lsb_(ls),
dimensions_(1), s0_(array_s), e0_(array_e),
local_flag_(false), eref_count_(0), lref_count_(0) local_flag_(false), eref_count_(0), lref_count_(0)
{ {
assert(s); ivl_assert(*this, s);
if (pin_count() == 0) {
cerr << "Array too big [" << array_s << ":" << array_e << "]" << endl;
ivl_assert(*this, 0);
}
verinum::V init_value = verinum::Vz; verinum::V init_value = verinum::Vz;
Link::DIR dir = Link::PASSIVE; Link::DIR dir = Link::PASSIVE;
@ -664,6 +729,16 @@ void NetNet::set_isint(bool flag)
isint_ = flag; isint_ = flag;
} }
bool NetNet::get_scalar() const
{
return is_scalar_;
}
void NetNet::set_scalar(bool flag)
{
is_scalar_ = flag;
}
ivl_discipline_t NetNet::get_discipline() const ivl_discipline_t NetNet::get_discipline() const
{ {
return discipline_; return discipline_;
@ -732,7 +807,9 @@ bool NetNet::array_addr_swapped() const
unsigned NetNet::array_count() const unsigned NetNet::array_count() const
{ {
return calculate_count(s0_, e0_); unsigned c = calculate_count(s0_, e0_);
ivl_assert(*this, c > 0);
return c;
} }
bool NetNet::array_index_is_valid(long sb) const bool NetNet::array_index_is_valid(long sb) const
@ -810,7 +887,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid,
: NetNode(sig->scope(), sig->scope()->local_symbol(), 2), : NetNode(sig->scope(), sig->scope()->local_symbol(), 2),
off_(off), wid_(wid), dir_(dir__) off_(off), wid_(wid), dir_(dir__)
{ {
connect(pin(1), sig->pin(0));
set_line(*sig); set_line(*sig);
switch (dir_) { switch (dir_) {
@ -823,6 +899,8 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid,
pin(1).set_dir(Link::OUTPUT); pin(1).set_dir(Link::OUTPUT);
break; break;
} }
connect(pin(1), sig->pin(0));
} }
NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel, NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel,
@ -830,20 +908,19 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel,
: NetNode(sig->scope(), sig->scope()->local_symbol(), 3), : NetNode(sig->scope(), sig->scope()->local_symbol(), 3),
off_(0), wid_(wid), dir_(VP) off_(0), wid_(wid), dir_(VP)
{ {
connect(pin(1), sig->pin(0));
connect(pin(2), sel->pin(0));
switch (dir_) { switch (dir_) {
case NetPartSelect::VP: case NetPartSelect::VP:
pin(0).set_dir(Link::OUTPUT); pin(0).set_dir(Link::OUTPUT);
pin(1).set_dir(Link::INPUT); pin(1).set_dir(Link::INPUT);
break; break;
case NetPartSelect::PV: case NetPartSelect::PV:
pin(0).set_dir(Link::INPUT); /* Only a vector to part can be a variable select. */
pin(1).set_dir(Link::OUTPUT); assert(0);
break;
} }
pin(2).set_dir(Link::INPUT); pin(2).set_dir(Link::INPUT);
connect(pin(1), sig->pin(0));
connect(pin(2), sel->pin(0));
} }
NetPartSelect::~NetPartSelect() NetPartSelect::~NetPartSelect()
@ -2271,12 +2348,12 @@ NetNet* NetESignal::sig()
return net_; return net_;
} }
unsigned NetESignal::lsi() const long NetESignal::lsi() const
{ {
return net_->lsb(); return net_->lsb();
} }
unsigned NetESignal::msi() const long NetESignal::msi() const
{ {
return net_->msb(); return net_->msb();
} }

View File

@ -193,11 +193,17 @@ class NetPins : public LineInfo {
const Link&pin(unsigned idx) const; const Link&pin(unsigned idx) const;
void dump_node_pins(ostream&, unsigned, const char**pin_names =0) const; void dump_node_pins(ostream&, unsigned, const char**pin_names =0) const;
void set_default_dir(Link::DIR d);
void set_default_init(verinum::V val);
bool is_linked(); bool is_linked();
bool pins_are_virtual(void) const;
void devirtualize_pins(void);
private: private:
Link*pins_; Link*pins_;
const unsigned npins_; const unsigned npins_;
Link::DIR default_dir_;
verinum::V default_init_;
}; };
/* ========= /* =========
@ -536,7 +542,7 @@ class NetNet : public NetObj {
public: public:
enum Type { NONE, IMPLICIT, IMPLICIT_REG, INTEGER, WIRE, TRI, TRI1, enum Type { NONE, IMPLICIT, IMPLICIT_REG, INTEGER, WIRE, TRI, TRI1,
SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG, SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG,
WONE }; UWIRE };
enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT };
@ -575,6 +581,9 @@ class NetNet : public NetObj {
bool get_isint() const; bool get_isint() const;
void set_isint(bool); void set_isint(bool);
bool get_scalar() const;
void set_scalar(bool);
/* Attach a discipline to the net. */ /* Attach a discipline to the net. */
ivl_discipline_t get_discipline() const; ivl_discipline_t get_discipline() const;
void set_discipline(ivl_discipline_t dis); void set_discipline(ivl_discipline_t dis);
@ -644,6 +653,7 @@ class NetNet : public NetObj {
ivl_variable_type_t data_type_; ivl_variable_type_t data_type_;
bool signed_; bool signed_;
bool isint_; // original type of integer bool isint_; // original type of integer
bool is_scalar_;
ivl_discipline_t discipline_; ivl_discipline_t discipline_;
long msb_, lsb_; long msb_, lsb_;
@ -710,6 +720,9 @@ class NetScope : public Attrib {
void rem_event(NetEvent*); void rem_event(NetEvent*);
NetEvent*find_event(perm_string name); NetEvent*find_event(perm_string name);
/* These methods add or find a genvar that lives in this scope. */
void add_genvar(perm_string name, LineInfo *li);
LineInfo* find_genvar(perm_string name);
/* These methods manage signals. The add_ and rem_signal /* These methods manage signals. The add_ and rem_signal
methods are used by the NetNet objects to make themselves methods are used by the NetNet objects to make themselves
@ -728,6 +741,7 @@ class NetScope : public Attrib {
const NetScope* child(const hname_t&name) const; const NetScope* child(const hname_t&name) const;
TYPE type() const; TYPE type() const;
void print_type(ostream&) const;
void set_task_def(NetTaskDef*); void set_task_def(NetTaskDef*);
void set_func_def(NetFuncDef*); void set_func_def(NetFuncDef*);
@ -750,6 +764,10 @@ class NetScope : public Attrib {
void is_auto(bool is_auto__) { is_auto_ = is_auto__; }; void is_auto(bool is_auto__) { is_auto_ = is_auto__; };
bool is_auto() const { return is_auto_; }; bool is_auto() const { return is_auto_; };
/* Is the module a cell (is in a `celldefine) */
void is_cell(bool is_cell__) { is_cell_ = is_cell__; };
bool is_cell() const { return is_cell_; };
const NetTaskDef* task_def() const; const NetTaskDef* task_def() const;
const NetFuncDef* func_def() const; const NetFuncDef* func_def() const;
@ -767,9 +785,11 @@ class NetScope : public Attrib {
void time_unit(int); void time_unit(int);
void time_precision(int); void time_precision(int);
void time_from_timescale(bool);
int time_unit() const; int time_unit() const;
int time_precision() const; int time_precision() const;
bool time_from_timescale() const;
void default_nettype(NetNet::Type); void default_nettype(NetNet::Type);
NetNet::Type default_nettype() const; NetNet::Type default_nettype() const;
@ -877,10 +897,13 @@ class NetScope : public Attrib {
unsigned def_lineno_; unsigned def_lineno_;
signed char time_unit_, time_prec_; signed char time_unit_, time_prec_;
bool time_from_timescale_;
NetNet::Type default_nettype_; NetNet::Type default_nettype_;
NetEvent *events_; NetEvent *events_;
map<perm_string,LineInfo*> genvars_;
typedef std::map<perm_string,NetNet*>::const_iterator signals_map_iter_t; typedef std::map<perm_string,NetNet*>::const_iterator signals_map_iter_t;
std::map <perm_string,NetNet*> signals_map_; std::map <perm_string,NetNet*> signals_map_;
perm_string module_name_; perm_string module_name_;
@ -894,7 +917,7 @@ class NetScope : public Attrib {
NetScope*sub_; NetScope*sub_;
unsigned lcounter_; unsigned lcounter_;
bool is_auto_; bool is_auto_, is_cell_;
}; };
/* /*
@ -3256,6 +3279,7 @@ class NetEBAdd : public NetEBinary {
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual void cast_signed(bool sign_flag);
virtual NetEBAdd* dup_expr() const; virtual NetEBAdd* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
@ -3278,6 +3302,7 @@ class NetEBDiv : public NetEBinary {
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual void cast_signed(bool sign_flag);
virtual NetEBDiv* dup_expr() const; virtual NetEBDiv* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
@ -3408,6 +3433,7 @@ class NetEBMult : public NetEBinary {
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual void cast_signed(bool sign_flag);
virtual NetEBMult* dup_expr() const; virtual NetEBMult* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
@ -3803,8 +3829,8 @@ class NetESignal : public NetExpr {
const NetNet* sig() const; const NetNet* sig() const;
NetNet* sig(); NetNet* sig();
// Declared vector dimensions for the signal. // Declared vector dimensions for the signal.
unsigned msi() const; long msi() const;
unsigned lsi() const; long lsi() const;
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;

View File

@ -16,7 +16,6 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ident "$Id: netlist.txt,v 1.10 2000/07/23 18:06:15 steve Exp $"
Note that the netlist.h header contains detailed descriptions of how Note that the netlist.h header contains detailed descriptions of how
@ -291,49 +290,3 @@ values. These are filled in during scope elaboration and are used in
subsequent elaboration phases to arrange for scaling of delays. This subsequent elaboration phases to arrange for scaling of delays. This
information can also be used by the code generator to scale times back information can also be used by the code generator to scale times back
to the units of the scope, if that is desired. to the units of the scope, if that is desired.
$Log: netlist.txt,v $
Revision 1.10 2000/07/23 18:06:15 steve
Document time scale in netlists.
Revision 1.9 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.8 2000/03/08 04:36:54 steve
Redesign the implementation of scopes and parameters.
I now generate the scopes and notice the parameters
in a separate pass over the pform. Once the scopes
are generated, I can process overrides and evalutate
paremeters before elaboration begins.
Revision 1.7 1999/11/28 23:42:02 steve
NetESignal object no longer need to be NetNode
objects. Let them keep a pointer to NetNet objects.
Revision 1.6 1999/11/21 00:13:09 steve
Support memories in continuous assignments.
Revision 1.5 1999/11/02 04:55:34 steve
Add the synthesize method to NetExpr to handle
synthesis of expressions, and use that method
to improve r-value handling of LPM_FF synthesis.
Modify the XNF target to handle LPM_FF objects.
Revision 1.4 1999/09/29 00:03:27 steve
Spelling fixes from Larry.
Revision 1.3 1999/07/24 02:11:20 steve
Elaborate task input ports.
Revision 1.2 1999/07/21 01:15:29 steve
Document netlist semantics.
Revision 1.1 1999/05/27 04:13:08 steve
Handle expression bit widths with non-fatal errors.

View File

@ -416,6 +416,7 @@ const char *human_readable_op(const char op, bool unary)
case '-': type = "-"; break; case '-': type = "-"; break;
case '*': type = "*"; break; case '*': type = "*"; break;
case '/': type = "/"; break; case '/': type = "/"; break;
case '%': type = "%"; break;
case '<': type = "<"; break; case '<': type = "<"; break;
case '>': type = ">"; break; case '>': type = ">"; break;

View File

@ -231,4 +231,8 @@ const char *human_readable_op(const char op, bool unary = false);
enum const_bool { C_NON, C_0, C_1, C_X }; enum const_bool { C_NON, C_0, C_1, C_X };
const_bool const_logical(const NetExpr*expr); const_bool const_logical(const NetExpr*expr);
extern bool dly_used_no_timescale;
extern bool dly_used_timescale;
extern bool display_ts_dly_warning;
#endif #endif

290
parse.y
View File

@ -80,6 +80,22 @@ static stack<PBlock*> current_block_stack;
const static struct str_pair_t pull_strength = { PGate::PULL, PGate::PULL }; const static struct str_pair_t pull_strength = { PGate::PULL, PGate::PULL };
const static struct str_pair_t str_strength = { PGate::STRONG, PGate::STRONG }; const static struct str_pair_t str_strength = { PGate::STRONG, PGate::STRONG };
static list<pair<perm_string,PExpr*> >* make_port_list(char*id, PExpr*expr)
{
list<pair<perm_string,PExpr*> >*tmp = new list<pair<perm_string,PExpr*> >;
tmp->push_back(make_pair(lex_strings.make(id), expr));
delete[]id;
return tmp;
}
static list<pair<perm_string,PExpr*> >* make_port_list(list<pair<perm_string,
PExpr*> >*tmp,
char*id, PExpr*expr)
{
tmp->push_back(make_pair(lex_strings.make(id), expr));
delete[]id;
return tmp;
}
static list<perm_string>* list_from_identifier(char*id) static list<perm_string>* list_from_identifier(char*id)
{ {
list<perm_string>*tmp = new list<perm_string>; list<perm_string>*tmp = new list<perm_string>;
@ -146,6 +162,9 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
strdup. They can be put into lists with the texts type. */ strdup. They can be put into lists with the texts type. */
char*text; char*text;
list<perm_string>*perm_strings; list<perm_string>*perm_strings;
list<pair<perm_string,PExpr*> >*port_list;
pform_name_t*pform_name; pform_name_t*pform_name;
ivl_discipline_t discipline; ivl_discipline_t discipline;
@ -210,40 +229,56 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
%token K_PO_POS K_PO_NEG K_POW %token K_PO_POS K_PO_NEG K_POW
%token K_PSTAR K_STARP %token K_PSTAR K_STARP
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER %token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER
%token K_abs K_abstol K_access K_acos K_acosh K_asin K_analog K_asinh %token K_edge_descriptor
%token K_atan K_atanh K_atan2 K_automatic
%token K_always K_and K_assign K_begin K_bool K_buf K_bufif0 K_bufif1 K_case
%token K_casex K_casez K_ceil K_cmos K_continuous K_cos K_cosh
%token K_ddt_nature K_deassign K_default K_defparam K_disable K_discrete
%token K_domain K_edge K_edge_descriptor K_discipline
%token K_else K_end K_endcase K_enddiscipline K_endfunction K_endgenerate
%token K_endmodule K_endnature
%token K_endprimitive K_endspecify K_endtable K_endtask K_event
%token K_exclude K_exp K_floor K_flow K_from
%token K_for K_force K_forever K_fork K_function K_generate K_genvar
%token K_ground K_highz0 K_highz1 K_hypot K_idt_nature K_if K_ifnone K_inf
%token K_initial K_inout K_input K_integer K_join K_large K_ln K_localparam
%token K_log K_logic K_macromodule K_max
%token K_medium K_min K_module K_nand K_nature K_negedge
%token K_nmos K_nor K_not K_notif0
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_potential
%token K_pow K_primitive
%token K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_real K_realtime
%token K_reg K_release K_repeat
%token K_rnmos K_rpmos K_rtran K_rtranif0 K_rtranif1 K_scalared
%token K_signed K_sin K_sinh K_small K_specify
%token K_specparam K_sqrt K_string K_strong0 K_strong1 K_supply0 K_supply1
%token K_table
%token K_tan K_tanh K_task
%token K_time K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand
%token K_trior K_trireg K_units K_vectored K_wait K_wand K_weak0 K_weak1
%token K_while K_wire
%token K_wone K_wor K_xnor K_xor
%token K_Shold K_Speriod K_Srecovery K_Srecrem K_Ssetup K_Swidth K_Ssetuphold
/* The base tokens from 1364-1995. */
%token K_always K_and K_assign K_begin K_buf K_bufif0 K_bufif1 K_case
%token K_casex K_casez K_cmos K_deassign K_default K_defparam K_disable
%token K_edge K_else K_end K_endcase K_endfunction K_endmodule
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_for
%token K_force K_forever K_fork K_function K_highz0 K_highz1 K_if
%token K_ifnone K_initial K_inout K_input K_integer K_join K_large
%token K_macromodule K_medium K_module K_nand K_negedge K_nmos K_nor
%token K_not K_notif0 K_notif1 K_or K_output K_parameter K_pmos K_posedge
%token K_primitive K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_real
%token K_realtime K_reg K_release K_repeat K_rnmos K_rpmos K_rtran
%token K_rtranif0 K_rtranif1 K_scalared K_small K_specify K_specparam
%token K_strong0 K_strong1 K_supply0 K_supply1 K_table K_task K_time
%token K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand K_trior
%token K_trireg K_vectored K_wait K_wand K_weak0 K_weak1 K_while K_wire
%token K_wor K_xnor K_xor
%token K_Shold K_Snochange K_Speriod K_Srecovery K_Ssetup K_Ssetuphold
%token K_Sskew K_Swidth
/* Icarus specific tokens. */
%token KK_attribute K_bool K_logic
/* The new tokens from 1364-2001. */
%token K_automatic K_endgenerate K_generate K_genvar K_localparam
%token K_noshowcancelled K_pulsestyle_onevent K_pulsestyle_ondetect
%token K_showcancelled K_signed K_unsigned
%token K_Sfullskew K_Srecrem K_Sremoval K_Stimeskew
/* The 1364-2001 configuration tokens. */
%token K_cell K_config K_design K_endconfig K_incdir K_include K_instance
%token K_liblist K_library K_use
/* The new tokens from 1364-2005. */
%token K_wone K_uwire
/* The new tokens from 1800-2005. */
%token K_always_comb K_always_ff K_always_latch K_assert %token K_always_comb K_always_ff K_always_latch K_assert
%token KK_attribute /* The new tokens for Verilog-AMS 2.3. */
%token K_abs K_abstol K_access K_acos K_acosh K_analog K_asin K_asinh
%token K_atan K_atan2 K_atanh K_ceil K_continuous K_cos K_cosh
%token K_ddt_nature K_discipline K_discrete K_domain K_enddiscipline
%token K_endnature K_exclude K_exp K_floor K_flow K_from K_ground
%token K_hypot K_idt_nature K_inf K_ln K_log K_max K_min K_nature
%token K_potential K_pow K_sin K_sinh K_sqrt K_string K_tan K_tanh
%token K_units
%type <flag> from_exclude %type <flag> from_exclude
%type <number> number %type <number> number
@ -260,7 +295,9 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
%type <expr> udp_initial_expr_opt %type <expr> udp_initial_expr_opt
%type <text> register_variable net_variable real_variable %type <text> register_variable net_variable real_variable
%type <perm_strings> register_variable_list net_variable_list real_variable_list list_of_identifiers %type <perm_strings> register_variable_list net_variable_list
%type <perm_strings> real_variable_list list_of_identifiers
%type <port_list> list_of_port_identifiers
%type <net_decl_assign> net_decl_assign net_decl_assigns %type <net_decl_assign> net_decl_assign net_decl_assigns
@ -682,6 +719,7 @@ delay_value_simple
description description
: module : module
| udp_primitive | udp_primitive
| config_declaration
| nature_declaration | nature_declaration
| discipline_declaration | discipline_declaration
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' | KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')'
@ -746,6 +784,54 @@ nature_item
{ delete[] $3; } { delete[] $3; }
; ;
config_declaration
: K_config IDENTIFIER ';'
K_design lib_cell_identifiers ';'
list_of_config_rule_statements
K_endconfig
{ cerr << @1 << ": sorry: config declarations are not supported and "
"will be skipped." << endl;
delete[] $2;
}
;
lib_cell_identifiers
: /* The BNF implies this can be blank, but I'm not sure exactly what
* this means. */
| lib_cell_identifiers lib_cell_id
;
list_of_config_rule_statements
: /* config rules are optional. */
| list_of_config_rule_statements config_rule_statement
;
config_rule_statement
: K_default K_liblist list_of_libraries ';'
| K_instance hierarchy_identifier K_liblist list_of_libraries ';'
{ delete $2; }
| K_instance hierarchy_identifier K_use lib_cell_id opt_config ';'
{ delete $2; }
| K_cell lib_cell_id K_liblist list_of_libraries ';'
| K_cell lib_cell_id K_use lib_cell_id opt_config ';'
;
opt_config
: /* The use clause takse an optional :config. */
| ':' K_config
lib_cell_id
: IDENTIFIER
{ delete[] $1; }
| IDENTIFIER '.' IDENTIFIER
{ delete[] $1; delete[] $3; }
;
list_of_libraries
: /* A NULL library means use the parents cell library. */
| list_of_libraries IDENTIFIER
{ delete[] $2; }
drive_strength drive_strength
: '(' dr_strength0 ',' dr_strength1 ')' : '(' dr_strength0 ',' dr_strength1 ')'
{ $$.str0 = $2.str0; { $$.str0 = $2.str0;
@ -900,6 +986,21 @@ expression
FILE_NAME(tmp, @2); FILE_NAME(tmp, @2);
$$ = tmp; $$ = tmp;
} }
| '~' '&' expr_primary %prec UNARY_PREC
{ yyerror(@1, "error: '~' '&' is not a valid expression. "
"Please use operator '~&' instead.");
$$ = 0;
}
| '~' '|' expr_primary %prec UNARY_PREC
{ yyerror(@1, "error: '~' '|' is not a valid expression. "
"Please use operator '~|' instead.");
$$ = 0;
}
| '~' '^' expr_primary %prec UNARY_PREC
{ yyerror(@1, "error: '~' '^' is not a valid expression. "
"Please use operator '~^' instead.");
$$ = 0;
}
| K_NAND expr_primary %prec UNARY_PREC | K_NAND expr_primary %prec UNARY_PREC
{ PEUnary*tmp = new PEUnary('A', $2); { PEUnary*tmp = new PEUnary('A', $2);
FILE_NAME(tmp, @2); FILE_NAME(tmp, @2);
@ -1647,6 +1748,17 @@ list_of_identifiers
{ $$ = list_from_identifier($1, $3); } { $$ = list_from_identifier($1, $3); }
; ;
list_of_port_identifiers
: IDENTIFIER
{ $$ = make_port_list($1, 0); }
| IDENTIFIER '=' expression
{ $$ = make_port_list($1, $3); }
| list_of_port_identifiers ',' IDENTIFIER
{ $$ = make_port_list($1, $3, 0); }
| list_of_port_identifiers ',' IDENTIFIER '=' expression
{ $$ = make_port_list($1, $3, $5); }
;
/* The list_of_ports and list_of_port_declarations rules are the /* The list_of_ports and list_of_port_declarations rules are the
port list formats for module ports. The list_of_ports_opt rule is port list formats for module ports. The list_of_ports_opt rule is
@ -1876,7 +1988,20 @@ module : attribute_list_opt module_start IDENTIFIER
{ pform_module_set_ports($6); } { pform_module_set_ports($6); }
module_item_list_opt module_item_list_opt
K_endmodule K_endmodule
{ pform_endmodule($3); { Module::UCDriveType ucd;
switch (uc_drive) {
case UCD_NONE:
default:
ucd = Module::UCD_NONE;
break;
case UCD_PULL0:
ucd = Module::UCD_PULL0;
break;
case UCD_PULL1:
ucd = Module::UCD_PULL1;
break;
}
pform_endmodule($3, in_celldefine, ucd);
delete[]$3; delete[]$3;
} }
@ -1991,9 +2116,20 @@ module_item
SR_BOTH); SR_BOTH);
} }
| K_output var_type signed_opt range_opt list_of_identifiers ';' | K_output var_type signed_opt range_opt list_of_port_identifiers ';'
{ pform_makewire(@1, $4, $3, $5, $2, NetNet::POUTPUT, { list<pair<perm_string,PExpr*> >::const_iterator pp;
IVL_VT_NO_TYPE, 0, SR_BOTH); list<perm_string>*tmp = new list<perm_string>;
for (pp = $5->begin(); pp != $5->end(); pp++) {
tmp->push_back((*pp).first);
}
pform_makewire(@1, $4, $3, tmp, $2, NetNet::POUTPUT,
IVL_VT_NO_TYPE, 0, SR_BOTH);
for (pp = $5->begin(); pp != $5->end(); pp++) {
if ((*pp).second) {
pform_make_reginit(@1, (*pp).first, (*pp).second);
}
}
delete $5;
} }
/* var_type declaration (reg variables) cannot be input or output, /* var_type declaration (reg variables) cannot be input or output,
@ -2124,8 +2260,7 @@ module_item
| K_task automatic_opt IDENTIFIER ';' | K_task automatic_opt IDENTIFIER ';'
{ assert(current_task == 0); { assert(current_task == 0);
current_task = pform_push_task_scope($3, $2); current_task = pform_push_task_scope(@1, $3, $2);
FILE_NAME(current_task, @1);
} }
task_item_list_opt task_item_list_opt
statement_or_null statement_or_null
@ -2137,12 +2272,11 @@ module_item
delete[]$3; delete[]$3;
} }
| K_task automatic_opt IDENTIFIER | K_task automatic_opt IDENTIFIER '('
{ assert(current_task == 0); { assert(current_task == 0);
current_task = pform_push_task_scope($3, $2); current_task = pform_push_task_scope(@1, $3, $2);
FILE_NAME(current_task, @1);
} }
'(' task_port_decl_list ')' ';' task_port_decl_list ')' ';'
block_item_decls_opt block_item_decls_opt
statement_or_null statement_or_null
K_endtask K_endtask
@ -2152,6 +2286,23 @@ module_item
current_task = 0; current_task = 0;
delete[]$3; delete[]$3;
} }
| K_task automatic_opt IDENTIFIER '(' ')' ';'
{ assert(current_task == 0);
current_task = pform_push_task_scope(@1, $3, $2);
}
block_item_decls_opt
statement_or_null
K_endtask
{ current_task->set_ports(0);
current_task->set_statement($9);
pform_pop_scope();
current_task = 0;
cerr << @3 << ": warning: task definition for \"" << $3
<< "\" has an empty port declaration list!" << endl;
delete[]$3;
}
| K_task automatic_opt IDENTIFIER error K_endtask | K_task automatic_opt IDENTIFIER error K_endtask
{ {
pform_pop_scope(); pform_pop_scope();
@ -2166,8 +2317,7 @@ module_item
| K_function automatic_opt function_range_or_type_opt IDENTIFIER ';' | K_function automatic_opt function_range_or_type_opt IDENTIFIER ';'
{ assert(current_function == 0); { assert(current_function == 0);
current_function = pform_push_function_scope($4, $2); current_function = pform_push_function_scope(@1, $4, $2);
FILE_NAME(current_function, @1);
} }
function_item_list statement function_item_list statement
K_endfunction K_endfunction
@ -2181,8 +2331,7 @@ module_item
| K_function automatic_opt function_range_or_type_opt IDENTIFIER | K_function automatic_opt function_range_or_type_opt IDENTIFIER
{ assert(current_function == 0); { assert(current_function == 0);
current_function = pform_push_function_scope($4, $2); current_function = pform_push_function_scope(@1, $4, $2);
FILE_NAME(current_function, @1);
} }
'(' task_port_decl_list ')' ';' '(' task_port_decl_list ')' ';'
block_item_decls_opt block_item_decls_opt
@ -2244,7 +2393,7 @@ module_item
} }
} }
| K_generate K_begin ':' IDENTIFIER { | K_generate K_begin ':' IDENTIFIER {
pform_start_generate_nblock(@1, $4); pform_start_generate_nblock(@2, $4);
} module_item_list_opt K_end K_endgenerate } module_item_list_opt K_end K_endgenerate
{ /* Detect and warn about anachronistic named begin/end use */ { /* Detect and warn about anachronistic named begin/end use */
if (generation_flag > GN_VER2001) { if (generation_flag > GN_VER2001) {
@ -2410,7 +2559,12 @@ net_type
| K_supply1 { $$ = NetNet::SUPPLY1; } | K_supply1 { $$ = NetNet::SUPPLY1; }
| K_wor { $$ = NetNet::WOR; } | K_wor { $$ = NetNet::WOR; }
| K_trior { $$ = NetNet::TRIOR; } | K_trior { $$ = NetNet::TRIOR; }
| K_wone { $$ = NetNet::WONE; } | K_wone { $$ = NetNet::UWIRE;
cerr << @1.text << ":" << @1.first_line << ": warning: "
"'wone' is deprecated, please use 'uwire' "
"instead." << endl;
}
| K_uwire { $$ = NetNet::UWIRE; }
; ;
var_type var_type
@ -3095,10 +3249,20 @@ specify_item
} }
pform_module_specify_path(tmp); pform_module_specify_path(tmp);
} }
| K_Sfullskew '(' spec_reference_event ',' spec_reference_event
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
delete $9;
}
| K_Shold '(' spec_reference_event ',' spec_reference_event | K_Shold '(' spec_reference_event ',' spec_reference_event
',' delay_value spec_notifier_opt ')' ';' ',' delay_value spec_notifier_opt ')' ';'
{ delete $7; { delete $7;
} }
| K_Snochange '(' spec_reference_event ',' spec_reference_event
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
delete $9;
}
| K_Speriod '(' spec_reference_event ',' delay_value | K_Speriod '(' spec_reference_event ',' delay_value
spec_notifier_opt ')' ';' spec_notifier_opt ')' ';'
{ delete $5; { delete $5;
@ -3107,6 +3271,15 @@ specify_item
',' delay_value spec_notifier_opt ')' ';' ',' delay_value spec_notifier_opt ')' ';'
{ delete $7; { delete $7;
} }
| K_Srecrem '(' spec_reference_event ',' spec_reference_event
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
delete $9;
}
| K_Sremoval '(' spec_reference_event ',' spec_reference_event
',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
}
| K_Ssetup '(' spec_reference_event ',' spec_reference_event | K_Ssetup '(' spec_reference_event ',' spec_reference_event
',' delay_value spec_notifier_opt ')' ';' ',' delay_value spec_notifier_opt ')' ';'
{ delete $7; { delete $7;
@ -3116,10 +3289,13 @@ specify_item
{ delete $7; { delete $7;
delete $9; delete $9;
} }
| K_Srecrem '(' spec_reference_event ',' spec_reference_event | K_Sskew '(' spec_reference_event ',' spec_reference_event
',' delay_value ',' delay_value spec_notifier_opt ')' ';' ',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
}
| K_Stimeskew '(' spec_reference_event ',' spec_reference_event
',' delay_value spec_notifier_opt ')' ';'
{ delete $7; { delete $7;
delete $9;
} }
| K_Swidth '(' spec_reference_event ',' delay_value ',' expression | K_Swidth '(' spec_reference_event ',' delay_value ',' expression
spec_notifier_opt ')' ';' spec_notifier_opt ')' ';'
@ -3129,6 +3305,18 @@ specify_item
| K_Swidth '(' spec_reference_event ',' delay_value ')' ';' | K_Swidth '(' spec_reference_event ',' delay_value ')' ';'
{ delete $5; { delete $5;
} }
| K_pulsestyle_onevent specify_path_identifiers ';'
{ delete $2;
}
| K_pulsestyle_ondetect specify_path_identifiers ';'
{ delete $2;
}
| K_showcancelled specify_path_identifiers ';'
{ delete $2;
}
| K_noshowcancelled specify_path_identifiers ';'
{ delete $2;
}
; ;
specify_item_list specify_item_list

View File

@ -1,7 +1,7 @@
#ifndef __parse_api_H #ifndef __parse_api_H
#define __parse_api_H #define __parse_api_H
/* /*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -46,4 +46,9 @@ extern int pform_parse(const char*path, FILE*file =0);
extern string vl_file; extern string vl_file;
extern void pform_set_timescale(int units, int prec, const char*file,
unsigned lineno);
extern int def_ts_units;
extern int def_ts_prec;
#endif #endif

View File

@ -1,7 +1,7 @@
#ifndef __parse_misc_H #ifndef __parse_misc_H
#define __parse_misc_H #define __parse_misc_H
/* /*
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -60,9 +60,15 @@ extern void VLerror(const YYLTYPE&loc, const char*msg);
#define yywarn VLwarn #define yywarn VLwarn
extern void VLwarn(const YYLTYPE&loc, const char*msg); extern void VLwarn(const YYLTYPE&loc, const char*msg);
extern void destroy_lexor();
extern ostream& operator << (ostream&, const YYLTYPE&loc); extern ostream& operator << (ostream&, const YYLTYPE&loc);
extern unsigned error_count, warn_count; extern unsigned error_count, warn_count;
extern unsigned long based_size; extern unsigned long based_size;
extern bool in_celldefine;
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
extern UCDriveType uc_drive;
#endif #endif

195
pform.cc
View File

@ -70,11 +70,11 @@ static NetNet::Type pform_default_nettype = NetNet::WIRE;
* These variables track the current time scale, as well as where the * These variables track the current time scale, as well as where the
* timescale was set. This supports warnings about tangled timescales. * timescale was set. This supports warnings about tangled timescales.
*/ */
static int pform_time_unit = 0; static int pform_time_unit;
static int pform_time_prec = 0; static int pform_time_prec;
static char*pform_timescale_file = 0; static char*pform_timescale_file = 0;
static unsigned pform_timescale_line = 0; static unsigned pform_timescale_line;
static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno) static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno)
{ {
@ -103,7 +103,7 @@ void pform_pop_scope()
} }
} }
PTask* pform_push_task_scope(char*name, bool is_auto) PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
{ {
perm_string task_name = lex_strings.make(name); perm_string task_name = lex_strings.make(name);
@ -111,11 +111,30 @@ PTask* pform_push_task_scope(char*name, bool is_auto)
if (pform_cur_generate) { if (pform_cur_generate) {
task = new PTask(task_name, pform_cur_generate->lexical_scope, task = new PTask(task_name, pform_cur_generate->lexical_scope,
is_auto); is_auto);
FILE_NAME(task, loc);
// Check if the task is already in the dictionary.
if (pform_cur_generate->tasks.find(task->pscope_name()) !=
pform_cur_generate->tasks.end()) {
cerr << task->get_fileline() << ": error: duplicate "
"definition for task '" << name << "' in '"
<< pform_cur_module->mod_name() << "' (generate)."
<< endl;
error_count += 1;
}
pform_cur_generate->tasks[task->pscope_name()] = task; pform_cur_generate->tasks[task->pscope_name()] = task;
pform_cur_generate->lexical_scope = task; pform_cur_generate->lexical_scope = task;
} else { } else {
task = new PTask(task_name, lexical_scope, task = new PTask(task_name, lexical_scope,
is_auto); is_auto);
FILE_NAME(task, loc);
// Check if the task is already in the dictionary.
if (pform_cur_module->tasks.find(task->pscope_name()) !=
pform_cur_module->tasks.end()) {
cerr << task->get_fileline() << ": error: duplicate "
"definition for task '" << name << "' in '"
<< pform_cur_module->mod_name() << "'." << endl;
error_count += 1;
}
pform_cur_module->tasks[task->pscope_name()] = task; pform_cur_module->tasks[task->pscope_name()] = task;
lexical_scope = task; lexical_scope = task;
} }
@ -123,7 +142,8 @@ PTask* pform_push_task_scope(char*name, bool is_auto)
return task; return task;
} }
PFunction* pform_push_function_scope(char*name, bool is_auto) PFunction* pform_push_function_scope(const struct vlltype&loc, char*name,
bool is_auto)
{ {
perm_string func_name = lex_strings.make(name); perm_string func_name = lex_strings.make(name);
@ -131,11 +151,30 @@ PFunction* pform_push_function_scope(char*name, bool is_auto)
if (pform_cur_generate) { if (pform_cur_generate) {
func = new PFunction(func_name, pform_cur_generate->lexical_scope, func = new PFunction(func_name, pform_cur_generate->lexical_scope,
is_auto); is_auto);
FILE_NAME(func, loc);
// Check if the function is already in the dictionary.
if (pform_cur_generate->funcs.find(func->pscope_name()) !=
pform_cur_generate->funcs.end()) {
cerr << func->get_fileline() << ": error: duplicate "
"definition for function '" << name << "' in '"
<< pform_cur_module->mod_name() << "' (generate)."
<< endl;
error_count += 1;
}
pform_cur_generate->funcs[func->pscope_name()] = func; pform_cur_generate->funcs[func->pscope_name()] = func;
pform_cur_generate->lexical_scope = func; pform_cur_generate->lexical_scope = func;
} else { } else {
func = new PFunction(func_name, lexical_scope, func = new PFunction(func_name, lexical_scope,
is_auto); is_auto);
FILE_NAME(func, loc);
// Check if the function is already in the dictionary.
if (pform_cur_module->funcs.find(func->pscope_name()) !=
pform_cur_module->funcs.end()) {
cerr << func->get_fileline() << ": error: duplicate "
"definition for function '" << name << "' in '"
<< pform_cur_module->mod_name() << "'." << endl;
error_count += 1;
}
pform_cur_module->funcs[func->pscope_name()] = func; pform_cur_module->funcs[func->pscope_name()] = func;
lexical_scope = func; lexical_scope = func;
} }
@ -259,10 +298,25 @@ void pform_set_timescale(int unit, int prec,
first_flag = false; first_flag = false;
} }
pform_timescale_file = strdup(file); if (file) pform_timescale_file = strdup(file);
else pform_timescale_file = 0;
pform_timescale_line = lineno; pform_timescale_line = lineno;
if (warn_timescale && first_flag && (pform_modules.size() > 0)) { if (!warn_timescale || !first_flag || !file) return;
/* Look to see if we have any modules without a timescale. */
bool have_no_ts = false;
map<perm_string,Module*>::iterator mod;
for (mod = pform_modules.begin(); mod != pform_modules.end(); mod++) {
const Module*mp = (*mod).second;
if (mp->time_from_timescale ||
mp->timescale_warn_done) continue;
have_no_ts = true;
break;
}
/* If we do then print a message for the new ones. */
if (have_no_ts) {
cerr << file << ":" << lineno << ": warning: " cerr << file << ":" << lineno << ": warning: "
<< "Some modules have no timescale. This may cause" << "Some modules have no timescale. This may cause"
<< endl; << endl;
@ -273,7 +327,10 @@ void pform_set_timescale(int unit, int prec,
map<perm_string,Module*>::iterator mod; map<perm_string,Module*>::iterator mod;
for (mod = pform_modules.begin() for (mod = pform_modules.begin()
; mod != pform_modules.end() ; mod++) { ; mod != pform_modules.end() ; mod++) {
const Module*mp = (*mod).second; Module*mp = (*mod).second;
if (mp->time_from_timescale ||
mp->timescale_warn_done) continue;
mp->timescale_warn_done = true;
cerr << file << ":" << lineno << ": : " cerr << file << ":" << lineno << ": : "
<< " -- module " << (*mod).first << " -- module " << (*mod).first
@ -342,6 +399,9 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno,
pform_cur_module = new Module(lex_name); pform_cur_module = new Module(lex_name);
pform_cur_module->time_unit = pform_time_unit; pform_cur_module->time_unit = pform_time_unit;
pform_cur_module->time_precision = pform_time_prec; pform_cur_module->time_precision = pform_time_prec;
/* If we have a timescale file then the time information is from
* a timescale directive. */
pform_cur_module->time_from_timescale = pform_timescale_file != 0;
pform_cur_module->default_nettype = pform_default_nettype; pform_cur_module->default_nettype = pform_default_nettype;
FILE_NAME(pform_cur_module, file, lineno); FILE_NAME(pform_cur_module, file, lineno);
@ -407,11 +467,14 @@ void pform_module_set_ports(vector<Module::port_t*>*ports)
} }
} }
void pform_endmodule(const char*name) void pform_endmodule(const char*name, bool in_celldefine,
Module::UCDriveType uc_drive)
{ {
assert(pform_cur_module); assert(pform_cur_module);
perm_string mod_name = pform_cur_module->mod_name(); perm_string mod_name = pform_cur_module->mod_name();
assert(strcmp(name, mod_name) == 0); assert(strcmp(name, mod_name) == 0);
pform_cur_module->is_cell = in_celldefine;
pform_cur_module->uc_drive = uc_drive;
map<perm_string,Module*>::const_iterator test = map<perm_string,Module*>::const_iterator test =
pform_modules.find(mod_name); pform_modules.find(mod_name);
@ -434,13 +497,31 @@ void pform_endmodule(const char*name)
pform_cur_module = 0; pform_cur_module = 0;
} }
static void pform_add_genvar(const struct vlltype&li, const perm_string&name,
map<perm_string,LineInfo*>&genvars)
{
LineInfo*lni = new LineInfo();
FILE_NAME(lni, li);
if (genvars.find(name) != genvars.end()) {
cerr << lni->get_fileline() << ": error: genvar '"
<< name << "' has already been declared." << endl;
cerr << genvars[name]->get_fileline()
<< ": the previous declaration is here." << endl;
error_count += 1;
delete lni;
} else {
genvars[name] = lni;
}
}
void pform_genvars(const struct vlltype&li, list<perm_string>*names) void pform_genvars(const struct vlltype&li, list<perm_string>*names)
{ {
list<perm_string>::const_iterator cur; list<perm_string>::const_iterator cur;
for (cur = names->begin(); cur != names->end() ; *cur++) { for (cur = names->begin(); cur != names->end() ; *cur++) {
LineInfo*lni = new LineInfo(); if (pform_cur_generate)
FILE_NAME(lni, li); pform_add_genvar(li, *cur, pform_cur_generate->genvars);
pform_cur_module->genvars[*cur] = lni; else
pform_add_genvar(li, *cur, pform_cur_module->genvars);
} }
delete names; delete names;
@ -455,7 +536,6 @@ void pform_start_generate_for(const struct vlltype&li,
FILE_NAME(gen, li); FILE_NAME(gen, li);
// For now, assume that generates do not nest.
gen->parent = pform_cur_generate; gen->parent = pform_cur_generate;
pform_cur_generate = gen; pform_cur_generate = gen;
@ -476,7 +556,6 @@ void pform_start_generate_if(const struct vlltype&li, PExpr*test)
FILE_NAME(gen, li); FILE_NAME(gen, li);
// For now, assume that generates do not nest.
gen->parent = pform_cur_generate; gen->parent = pform_cur_generate;
pform_cur_generate = gen; pform_cur_generate = gen;
@ -499,7 +578,6 @@ void pform_start_generate_else(const struct vlltype&li)
FILE_NAME(gen, li); FILE_NAME(gen, li);
// For now, assume that generates do not nest.
gen->parent = pform_cur_generate; gen->parent = pform_cur_generate;
pform_cur_generate = gen; pform_cur_generate = gen;
@ -1028,13 +1106,13 @@ static void pform_set_net_range(perm_string name,
if (range == 0) { if (range == 0) {
/* This is the special case that we really mean a /* This is the special case that we really mean a
scalar. Set a fake range. */ scalar. Set a fake range. */
cur->set_range(0, 0, rt); cur->set_range(0, 0, rt, true);
} else { } else {
assert(range->count() == 2); assert(range->count() == 2);
assert((*range)[0]); assert((*range)[0]);
assert((*range)[1]); assert((*range)[1]);
cur->set_range((*range)[0], (*range)[1], rt); cur->set_range((*range)[0], (*range)[1], rt, false);
} }
cur->set_signed(signed_flag); cur->set_signed(signed_flag);
@ -1068,9 +1146,21 @@ void pform_set_net_range(list<perm_string>*names,
*/ */
static void pform_make_event(perm_string name, const char*fn, unsigned ln) static void pform_make_event(perm_string name, const char*fn, unsigned ln)
{ {
LexicalScope*scope = pform_get_cur_scope();
// Check if the named event is already in the dictionary.
if (scope->events.find(name) != scope->events.end()) {
LineInfo tloc;
FILE_NAME(&tloc, fn, ln);
cerr << tloc.get_fileline() << ": error: duplicate definition "
"for named event '" << name << "' in '"
<< pform_cur_module->mod_name() << "'." << endl;
error_count += 1;
}
PEvent*event = new PEvent(name); PEvent*event = new PEvent(name);
FILE_NAME(event, fn, ln); FILE_NAME(event, fn, ln);
pform_get_cur_scope()->events[name] = event; scope->events[name] = event;
} }
void pform_make_events(list<perm_string>*names, const char*fn, unsigned ln) void pform_make_events(list<perm_string>*names, const char*fn, unsigned ln)
@ -1396,14 +1486,16 @@ void pform_module_define_port(const struct vlltype&li,
if (range == 0) { if (range == 0) {
cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT : cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT :
SR_BOTH); SR_BOTH,
true);
} else { } else {
assert(range->count() == 2); assert(range->count() == 2);
assert((*range)[0]); assert((*range)[0]);
assert((*range)[1]); assert((*range)[1]);
cur->set_range((*range)[0], (*range)[1], cur->set_range((*range)[0], (*range)[1],
(type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH,
false);
} }
if (attr) { if (attr) {
@ -1483,7 +1575,7 @@ void pform_makewire(const vlltype&li, perm_string name,
<< " to " << dt << "." << endl; << " to " << dt << "." << endl;
} }
ivl_assert(*cur, flag); ivl_assert(*cur, flag);
cur->set_range(0, 0, SR_NET); cur->set_range(0, 0, SR_NET, true);
cur->set_signed(true); cur->set_signed(true);
break; break;
default: default:
@ -1673,7 +1765,7 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
/* If there is a range involved, it needs to be set. */ /* If there is a range involved, it needs to be set. */
if (range) if (range)
curw->set_range((*range)[0], (*range)[1], SR_PORT); curw->set_range((*range)[0], (*range)[1], SR_PORT, false);
svector<PWire*>*tmp = new svector<PWire*>(*res, curw); svector<PWire*>*tmp = new svector<PWire*>(*res, curw);
@ -1763,13 +1855,32 @@ void pform_set_parameter(const struct vlltype&loc,
bool signed_flag, svector<PExpr*>*range, PExpr*expr, bool signed_flag, svector<PExpr*>*range, PExpr*expr,
LexicalScope::range_t*value_range) LexicalScope::range_t*value_range)
{ {
if (pform_get_cur_scope() == pform_cur_generate) { LexicalScope*scope = pform_get_cur_scope();
if (scope == pform_cur_generate) {
VLerror("parameter declarations are not permitted in generate blocks"); VLerror("parameter declarations are not permitted in generate blocks");
return; return;
} }
// Check if the parameter name is already in the dictionary.
if (scope->parameters.find(name) != scope->parameters.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: duplicate definition "
"for parameter '" << name << "' in '"
<< pform_cur_module->mod_name() << "'." << endl;
error_count += 1;
}
if (scope->localparams.find(name) != scope->localparams.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: localparam and "
"parameter in '" << pform_cur_module->mod_name()
<< "' have the same name '" << name << "'." << endl;
error_count += 1;
}
assert(expr); assert(expr);
Module::param_expr_t&parm = pform_get_cur_scope()->parameters[name]; Module::param_expr_t&parm = scope->parameters[name];
FILE_NAME(&parm, loc); FILE_NAME(&parm, loc);
parm.expr = expr; parm.expr = expr;
@ -1788,7 +1899,7 @@ void pform_set_parameter(const struct vlltype&loc,
parm.signed_flag = signed_flag; parm.signed_flag = signed_flag;
parm.range = value_range; parm.range = value_range;
if (pform_get_cur_scope() == pform_cur_module) if (scope == pform_cur_module)
pform_cur_module->param_names.push_back(name); pform_cur_module->param_names.push_back(name);
} }
@ -1796,6 +1907,26 @@ void pform_set_localparam(const struct vlltype&loc,
perm_string name, ivl_variable_type_t type, perm_string name, ivl_variable_type_t type,
bool signed_flag, svector<PExpr*>*range, PExpr*expr) bool signed_flag, svector<PExpr*>*range, PExpr*expr)
{ {
LexicalScope*scope = pform_get_cur_scope();
// Check if the localparam name is already in the dictionary.
if (scope->localparams.find(name) != scope->localparams.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: duplicate definition "
"for localparam '" << name << "' in '"
<< pform_cur_module->mod_name() << "'." << endl;
error_count += 1;
}
if (scope->parameters.find(name) != scope->parameters.end()) {
LineInfo tloc;
FILE_NAME(&tloc, loc);
cerr << tloc.get_fileline() << ": error: parameter and "
"localparam in '" << pform_cur_module->mod_name()
<< "' have the same name '" << name << "'." << endl;
error_count += 1;
}
assert(expr); assert(expr);
Module::param_expr_t&parm = pform_get_cur_scope()->localparams[name]; Module::param_expr_t&parm = pform_get_cur_scope()->localparams[name];
FILE_NAME(&parm, loc); FILE_NAME(&parm, loc);
@ -1819,6 +1950,15 @@ void pform_set_localparam(const struct vlltype&loc,
void pform_set_specparam(perm_string name, PExpr*expr) void pform_set_specparam(perm_string name, PExpr*expr)
{ {
// Check if the specparam name is already in the dictionary.
if (pform_cur_module->specparams.find(name) !=
pform_cur_module->specparams.end()) {
cerr << expr->get_fileline() << ": error: duplicate definition "
"for specparam '" << name << "' in '"
<< pform_cur_module->mod_name() << "'." << endl;
error_count += 1;
}
assert(expr); assert(expr);
pform_cur_module->specparams[name] = expr; pform_cur_module->specparams[name] = expr;
} }
@ -1933,7 +2073,7 @@ static void pform_set_reg_integer(perm_string name)
cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)), cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)),
new PENumber(new verinum((uint64_t)0, integer_width)), new PENumber(new verinum((uint64_t)0, integer_width)),
SR_NET); SR_NET, false);
cur->set_signed(true); cur->set_signed(true);
} }
@ -1964,7 +2104,7 @@ static void pform_set_reg_time(perm_string name)
cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)), cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)),
new PENumber(new verinum((uint64_t)0, integer_width)), new PENumber(new verinum((uint64_t)0, integer_width)),
SR_NET); SR_NET, false);
} }
void pform_set_reg_time(list<perm_string>*names) void pform_set_reg_time(list<perm_string>*names)
@ -2045,6 +2185,7 @@ int pform_parse(const char*path, FILE*file)
error_count += 1; error_count += 1;
} }
destroy_lexor();
return error_count; return error_count;
} }

13
pform.h
View File

@ -1,7 +1,7 @@
#ifndef __pform_H #ifndef __pform_H
#define __pform_H #define __pform_H
/* /*
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -159,7 +159,8 @@ extern void pform_module_define_port(const struct vlltype&li,
extern Module::port_t* pform_module_port_reference(perm_string name, extern Module::port_t* pform_module_port_reference(perm_string name,
const char*file, const char*file,
unsigned lineno); unsigned lineno);
extern void pform_endmodule(const char*); extern void pform_endmodule(const char*, bool in_celldefine,
Module::UCDriveType uc_drive);
extern void pform_make_udp(perm_string name, list<perm_string>*parms, extern void pform_make_udp(perm_string name, list<perm_string>*parms,
svector<PWire*>*decl, list<string>*table, svector<PWire*>*decl, list<string>*table,
@ -180,8 +181,10 @@ extern void pform_make_udp(perm_string name,
*/ */
extern void pform_pop_scope(); extern void pform_pop_scope();
extern PTask*pform_push_task_scope(char*name, bool is_auto); extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name,
extern PFunction*pform_push_function_scope(char*name, bool is_auto); bool is_auto);
extern PFunction*pform_push_function_scope(const struct vlltype&loc, char*name,
bool is_auto);
extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt); extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt);
extern void pform_put_behavior_in_scope(AProcess*proc); extern void pform_put_behavior_in_scope(AProcess*proc);
@ -191,7 +194,7 @@ extern verinum* pform_verinum_with_size(verinum*s, verinum*val,
/* /*
* This function takes the list of names as new genvars to declare in * This function takes the list of names as new genvars to declare in
* the current module scope. * the current module or generate scope.
*/ */
extern void pform_genvars(const struct vlltype&li, list<perm_string>*names); extern void pform_genvars(const struct vlltype&li, list<perm_string>*names);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -410,6 +410,8 @@ void PDelays::dump_delays(ostream&out) const
if (delay_[0] && delay_[1] && delay_[2]) if (delay_[0] && delay_[1] && delay_[2])
out << "#(" << *delay_[0] << "," << *delay_[1] << "," << out << "#(" << *delay_[0] << "," << *delay_[1] << "," <<
*delay_[2] << ")"; *delay_[2] << ")";
else if (delay_[0] && delay_[1])
out << "#(" << *delay_[0] << "," << *delay_[1] << ")";
else if (delay_[0]) else if (delay_[0])
out << "#" << *delay_[0]; out << "#" << *delay_[0];
else else
@ -1032,6 +1034,12 @@ void PGenerate::dump(ostream&out, unsigned indent) const
(*idx)->dump(out, indent+2); (*idx)->dump(out, indent+2);
} }
typedef map<perm_string,LineInfo*>::const_iterator genvar_iter_t;
for (genvar_iter_t cur = genvars.begin()
; cur != genvars.end() ; cur++) {
out << setw(indent+2) << "" << "genvar " << ((*cur).first) << ";" << endl;
}
for (list<PGenerate*>::const_iterator idx = generate_schemes.begin() for (list<PGenerate*>::const_iterator idx = generate_schemes.begin()
; idx != generate_schemes.end() ; idx++) { ; idx != generate_schemes.end() ; idx++) {
(*idx)->dump(out, indent+2); (*idx)->dump(out, indent+2);
@ -1147,7 +1155,9 @@ void Module::dump(ostream&out) const
out << " *) "; out << " *) ";
} }
out << "module " << mod_name() << ";" << endl; out << "module " << mod_name() << ";";
if (is_cell) out << " // Is in `celldefine.";
out << endl;
for (unsigned idx = 0 ; idx < ports.size() ; idx += 1) { for (unsigned idx = 0 ; idx < ports.size() ; idx += 1) {
port_t*cur = ports[idx]; port_t*cur = ports[idx];

View File

@ -10,4 +10,6 @@
echo "Building version_tag.h with git describe" echo "Building version_tag.h with git describe"
tmp=`git describe | sed -e 's;\(.*\);#define VERSION_TAG "\1";'` tmp=`git describe | sed -e 's;\(.*\);#define VERSION_TAG "\1";'`
echo "$tmp" > version_tag.h echo "#ifndef VERSION_TAG" > version_tag.h
echo "$tmp" >> version_tag.h
echo "#endif" >> version_tag.h

65
scripts/MAKE_RELEASE.sh Normal file
View File

@ -0,0 +1,65 @@
#!/bin/sh
# This script makes a release from a git repository. The input is
# the number for a snapshot and the path to a temporary directory.
# for example:
#
# sh scripts/MAKE_RELEASE.sh 0.9.1 ~/tmp
#
# The above assumes that there is a tag "v0_9_1" at the point
# to be released. (The tag has the "v", but the argument to this
# script does not have the "v"). This script extracts based on the
# tag, uses the temporary directory to stage intermediate results,
# and finally creates a file called verilog-0.9.1.tar.gz that
# contains the release ready to go.
#
# The complete steps to make a release x.y.z generally are:
#
# git tag -a v0_9_1
# (Make the tag in the local git repository.)
#
# sh scripts/MAKE_RELEASE.sh 0.9.1 ~/tmp
# (Make the snapshot bundle verilog-0.9.1.tar.gz)
#
# git push --tags
# (Publish the tag to the repository.)
#
id=$1
destdir=$2
# The git tag to use.
tag="v"`echo $id | tr '.' '_'`
# 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_tag.h"
echo "Create $versionh ..."
echo "#ifndef VERSION_TAG" > $versionh
echo "#define VERSION_TAG \"$tag\"" >> $versionh
echo "#endif" >> $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

View File

@ -47,9 +47,11 @@ fi
echo "Exporting $tag to $destdir/$prefix..." echo "Exporting $tag to $destdir/$prefix..."
git archive --prefix="$prefix/" $tag | ( cd "$destdir" && tar xf - ) git archive --prefix="$prefix/" $tag | ( cd "$destdir" && tar xf - )
versionh="$destdir/$prefix/version.h" versionh="$destdir/$prefix/version_tag.h"
echo "Create $versionh ..." echo "Create $versionh ..."
echo "#define VERSION_TAG \"$tag\"" > $versionh echo "#ifndef VERSION_TAG" > $versionh
echo "#define VERSION_TAG \"$tag\"" >> $versionh
echo "#endif" >> $versionh
echo "Running autoconf.sh..." echo "Running autoconf.sh..."
( cd $destdir/$prefix && sh autoconf.sh ) ( cd $destdir/$prefix && sh autoconf.sh )

View File

@ -106,6 +106,18 @@ bool NetEBAdd::set_width(unsigned w, bool)
return wid == w; return wid == w;
} }
void NetEBAdd::cast_signed(bool sign_flag)
{
if (has_sign() == sign_flag)
return;
if (sign_flag == false) {
left_->cast_signed(sign_flag);
right_->cast_signed(sign_flag);
}
cast_signed_base_(sign_flag);
}
/* /*
* The bitwise logical operators have operands the same size as the * The bitwise logical operators have operands the same size as the
* result. Anything else is a mess. I first try to get the operands to * result. Anything else is a mess. I first try to get the operands to
@ -168,6 +180,19 @@ bool NetEBDiv::set_width(unsigned w, bool)
return w == expr_width(); return w == expr_width();
} }
void NetEBDiv::cast_signed(bool sign_flag)
{
if (has_sign() == sign_flag)
return;
if (sign_flag == false) {
left_->cast_signed(sign_flag);
right_->cast_signed(sign_flag);
}
cast_signed_base_(sign_flag);
}
bool NetEBLogic::set_width(unsigned w, bool) bool NetEBLogic::set_width(unsigned w, bool)
{ {
bool flag; bool flag;
@ -192,6 +217,19 @@ bool NetEBMult::set_width(unsigned w, bool)
return true; return true;
} }
void NetEBMult::cast_signed(bool sign_flag)
{
if (has_sign() == sign_flag)
return;
if (sign_flag == false) {
left_->cast_signed(sign_flag);
right_->cast_signed(sign_flag);
}
cast_signed_base_(sign_flag);
}
bool NetEBPow::set_width(unsigned w, bool last_chance) bool NetEBPow::set_width(unsigned w, bool last_chance)
{ {
return w == expr_width(); return w == expr_width();

View File

@ -1,5 +1,3 @@
# $Id: README-solaris_pkg.txt,v 1.3 2007/02/26 19:49:49 steve Exp $
Notes about the solaris package. Notes about the solaris package.
I. Installing a prebuilt solaris package I. Installing a prebuilt solaris package

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2004-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -46,6 +46,16 @@ struct sfunc_return_type_cell : sfunc_return_type {
static struct sfunc_return_type_cell*sfunc_stack = 0; static struct sfunc_return_type_cell*sfunc_stack = 0;
void cleanup_sys_func_table()
{
struct sfunc_return_type_cell *next, *cur = sfunc_stack;
while (cur) {
next = cur->next;
delete cur;
cur = next;
}
}
const struct sfunc_return_type* lookup_sys_func(const char*name) const struct sfunc_return_type* lookup_sys_func(const char*name)
{ {
/* First, try to find then name in the function stack. */ /* First, try to find then name in the function stack. */
@ -186,7 +196,7 @@ int load_sys_func_table(const char*path)
fprintf(stderr, "%s:%s: Unknown type: %s\n", fprintf(stderr, "%s:%s: Unknown type: %s\n",
path, name, stype); path, name, stype);
} }
fclose(fd);
return 0; return 0;
} }

View File

@ -1268,6 +1268,8 @@ extern "C" unsigned ivl_lpm_size(ivl_lpm_t net)
return net->u_.ufunc.ports - 1; return net->u_.ufunc.ports - 1;
case IVL_LPM_REPEAT: case IVL_LPM_REPEAT:
return net->u_.repeat.count; return net->u_.repeat.count;
case IVL_LPM_CONCAT:
return net->u_.concat.inputs;
default: default:
assert(0); assert(0);
return 0; return 0;
@ -1655,6 +1657,12 @@ extern "C" unsigned ivl_scope_is_auto(ivl_scope_t net)
return net->is_auto; return net->is_auto;
} }
extern "C" unsigned ivl_scope_is_cell(ivl_scope_t net)
{
assert(net);
return net->is_cell;
}
extern "C" unsigned ivl_scope_lineno(ivl_scope_t net) extern "C" unsigned ivl_scope_lineno(ivl_scope_t net)
{ {
assert(net); assert(net);
@ -1893,10 +1901,17 @@ extern "C" const char* ivl_signal_name(ivl_signal_t net)
extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word) extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word)
{ {
assert(word < net->array_words); assert(word < net->array_words);
if (net->array_words > 1) if (net->array_words > 1) {
return net->pins[word]; if (net->pins) {
else return net->pins[word];
} else {
// net->pins can be NULL for a virtualized reg array.
assert(net->type_ == IVL_SIT_REG);
return NULL;
}
} else {
return net->pin; return net->pin;
}
} }
extern "C" int ivl_signal_msb(ivl_signal_t net) extern "C" int ivl_signal_msb(ivl_signal_t net)

View File

@ -199,7 +199,7 @@ void dll_target::expr_concat(const NetEConcat*net)
cur->type_ = IVL_EX_CONCAT; cur->type_ = IVL_EX_CONCAT;
cur->value_ = IVL_VT_VECTOR; cur->value_ = IVL_VT_VECTOR;
cur->width_ = net->expr_width(); cur->width_ = net->expr_width();
cur->signed_ = 0; cur->signed_ = net->has_sign() ? 1 : 0;
cur->u_.concat_.rept = net->repeat(); cur->u_.concat_.rept = net->repeat();
cur->u_.concat_.parms = net->nparms(); cur->u_.concat_.parms = net->nparms();
@ -308,6 +308,7 @@ void dll_target::expr_event(const NetEEvent*net)
assert(expr_); assert(expr_);
expr_->type_ = IVL_EX_EVENT; expr_->type_ = IVL_EX_EVENT;
FILE_NAME(expr_, net);
expr_->value_= IVL_VT_VOID; expr_->value_= IVL_VT_VOID;
/* Locate the event by name. Save the ivl_event_t in the /* Locate the event by name. Save the ivl_event_t in the
@ -351,6 +352,7 @@ void dll_target::expr_select(const NetESelect*net)
expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
assert(expr_); assert(expr_);
FILE_NAME(expr_, net);
expr_->type_ = IVL_EX_SELECT; expr_->type_ = IVL_EX_SELECT;
expr_->value_= IVL_VT_VECTOR; expr_->value_= IVL_VT_VECTOR;
@ -450,10 +452,10 @@ void dll_target::expr_signal(const NetESignal*net)
/* Make account for the special case that this is a reference /* Make account for the special case that this is a reference
to an array as a whole. We detect this case by noting that to an array as a whole. We detect this case by noting that
this is an array (more than 1 word) and there is no word this is an array (more than 0 array dimensions) and that
select expression. In that case, this is an IVL_EX_ARRAY there is no word select expression. For this case, we have
expression instead of a SIGNAL expression. */ an IVL_EX_ARRAY expression instead of a SIGNAL expression. */
if (sig->array_words > 1 && word_expr == 0) { if (sig->array_dimensions_ > 0 && word_expr == 0) {
expr_->type_ = IVL_EX_ARRAY; expr_->type_ = IVL_EX_ARRAY;
expr_->width_ = 0; // Doesn't make much sense for arrays. expr_->width_ = 0; // Doesn't make much sense for arrays.
} }

View File

@ -2147,6 +2147,7 @@ bool dll_target::part_select(const NetPartSelect*net)
obj->type = IVL_LPM_PART_PV; obj->type = IVL_LPM_PART_PV;
break; break;
} }
FILE_NAME(obj, net);
obj->name = net->name(); // NetPartSelect names are permallocated. obj->name = net->name(); // NetPartSelect names are permallocated.
assert(net->scope()); assert(net->scope());
obj->scope = find_scope(des_, net->scope()); obj->scope = find_scope(des_, net->scope());
@ -2389,6 +2390,7 @@ void dll_target::scope(const NetScope*net)
scop->nattr = net->attr_cnt(); scop->nattr = net->attr_cnt();
scop->attr = fill_in_attributes(net); scop->attr = fill_in_attributes(net);
scop->is_auto = net->is_auto(); scop->is_auto = net->is_auto();
scop->is_cell = net->is_cell();
switch (net->type()) { switch (net->type()) {
case NetScope::MODULE: case NetScope::MODULE:
@ -2510,6 +2512,10 @@ void dll_target::signal(const NetNet*net)
assert(0); assert(0);
break; break;
case NetNet::UWIRE:
cerr << net->get_fileline()
<< ": warning: uwire is not currently supported, converting "
"it to a wire!" << endl;
case NetNet::TRI: case NetNet::TRI:
case NetNet::WIRE: case NetNet::WIRE:
case NetNet::IMPLICIT: case NetNet::IMPLICIT:
@ -2560,12 +2566,22 @@ void dll_target::signal(const NetNet*net)
obj->array_base = net->array_first(); obj->array_base = net->array_first();
obj->array_words = net->array_count(); obj->array_words = net->array_count();
obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0; obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0;
assert(obj->array_words == net->pin_count());
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: "
"t-dll creating nexus array " << obj->array_words << " long" << endl;
if (obj->array_words > 1 && net->pins_are_virtual()) {
obj->pins = NULL;
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: "
"t-dll used NULL for big nexus array" << endl;
return;
}
if (obj->array_words > 1) if (obj->array_words > 1)
obj->pins = new ivl_nexus_t[obj->array_words]; obj->pins = new ivl_nexus_t[obj->array_words];
for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) { for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) {
const Nexus*nex = net->pin(idx).nexus(); const Nexus*nex = net->pins_are_virtual() ? 0 : net->pin(idx).nexus();
if (nex == 0) { if (nex == 0) {
// Special case: This pin is connected to // Special case: This pin is connected to
// nothing. This can happen, for example, if the // nothing. This can happen, for example, if the
@ -2597,6 +2613,7 @@ void dll_target::signal(const NetNet*net)
obj->pin = tmp; obj->pin = tmp;
} }
} }
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: t-dll done with big nexus array" << endl;
} }
bool dll_target::signal_paths(const NetNet*net) bool dll_target::signal_paths(const NetNet*net)

View File

@ -606,6 +606,8 @@ struct ivl_scope_s {
ivl_statement_t def; ivl_statement_t def;
unsigned is_auto; unsigned is_auto;
unsigned is_cell;
unsigned ports; unsigned ports;
ivl_signal_t*port; ivl_signal_t*port;

View File

@ -2,7 +2,6 @@
FPGA LOADABLE CODE GENERATOR FOR Icarus Verilog FPGA LOADABLE CODE GENERATOR FOR Icarus Verilog
Copyright 2001 Stephen Williams Copyright 2001 Stephen Williams
$Id: fpga.txt,v 1.12 2005/09/19 21:45:36 steve Exp $
The FPGA code generator supports a variety of FPGA devices, writing The FPGA code generator supports a variety of FPGA devices, writing
XNF or EDIF depending on the target. You can select the architecture XNF or EDIF depending on the target. You can select the architecture
@ -186,42 +185,3 @@ Compile a single-file design with command line tools like so:
% map -o map.ncd foo.ngd % map -o map.ncd foo.ngd
% par -w map.ncd foo.ncd % par -w map.ncd foo.ncd
---
$Log: fpga.txt,v $
Revision 1.12 2005/09/19 21:45:36 steve
Spelling patches from Larry.
Revision 1.11 2003/08/07 05:17:34 steve
Add arch=lpm to the documentation.
Revision 1.10 2003/07/04 03:57:19 steve
Allow attributes on Verilog 2001 port declarations.
Revision 1.9 2003/07/04 01:08:03 steve
PAD attribute can be used to assign pins.
Revision 1.8 2003/07/02 00:26:49 steve
Fix spelling of part= flag.
Revision 1.7 2003/03/24 02:28:38 steve
Document the virtex2 architecture.
Revision 1.6 2003/03/24 00:47:54 steve
Add new virtex2 architecture family, and
also the new edif.h EDIF management functions.
Revision 1.5 2002/04/30 04:26:42 steve
Spelling errors.
Revision 1.4 2001/09/16 22:26:47 steve
Support the cellref attribute.
Revision 1.3 2001/09/16 01:48:16 steve
Suppor the PAD attribute on signals.
Revision 1.2 2001/09/06 04:28:40 steve
Separate the virtex and generic-edif code generators.
Revision 1.1 2001/09/02 23:58:49 steve
Add documentation for the code generator.

View File

@ -430,7 +430,7 @@ static void show_lpm_cmp_ne(ivl_lpm_t net)
} }
/* IVL_LPM_CONCAT /* IVL_LPM_CONCAT
* The concat device takes N inputs (N=ivl_lpm_selects) and generates * The concat device takes N inputs (N=ivl_lpm_size) and generates
* a single output. The total output is known from the ivl_lpm_width * a single output. The total output is known from the ivl_lpm_width
* function. The widths of all the inputs are inferred from the widths * function. The widths of all the inputs are inferred from the widths
* of the signals connected to the nexus of the inputs. The compiler * of the signals connected to the nexus of the inputs. The compiler
@ -444,10 +444,10 @@ static void show_lpm_concat(ivl_lpm_t net)
unsigned width = ivl_lpm_width(net); unsigned width = ivl_lpm_width(net);
fprintf(out, " LPM_CONCAT %s: <width=%u, inputs=%u>\n", fprintf(out, " LPM_CONCAT %s: <width=%u, inputs=%u>\n",
ivl_lpm_basename(net), width, ivl_lpm_selects(net)); ivl_lpm_basename(net), width, ivl_lpm_size(net));
fprintf(out, " O: %p\n", ivl_lpm_q(net,0)); fprintf(out, " O: %p\n", ivl_lpm_q(net,0));
for (idx = 0 ; idx < ivl_lpm_selects(net) ; idx += 1) { for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
ivl_nexus_t nex = ivl_lpm_data(net, idx); ivl_nexus_t nex = ivl_lpm_data(net, idx);
unsigned signal_width = width_of_nexus(nex); unsigned signal_width = width_of_nexus(nex);
@ -1272,15 +1272,21 @@ static void show_signal(ivl_signal_t net)
ivl_nexus_t nex = ivl_signal_nex(net, idx); ivl_nexus_t nex = ivl_signal_nex(net, idx);
fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] <width=%u%s> <discipline=%s> nexus=%p\n", fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] "
"<width=%u%s> <discipline=%s> ",
type, sign, port, data_type, type, sign, port, data_type,
ivl_signal_msb(net), ivl_signal_lsb(net), ivl_signal_msb(net), ivl_signal_lsb(net),
ivl_signal_basename(net), ivl_signal_basename(net),
idx, ivl_signal_array_base(net)+idx, idx, ivl_signal_array_base(net)+idx,
ivl_signal_width(net), ivl_signal_width(net),
ivl_signal_local(net)? ", local":"", ivl_signal_local(net)? ", local":"",
discipline_txt, discipline_txt);
nex); if (nex == NULL) {
fprintf(out, "nexus=<virtual>\n");
continue;
} else {
fprintf(out, "nexus=%p\n", nex);
}
show_nexus_details(net, nex); show_nexus_details(net, nex);
} }
@ -1527,7 +1533,8 @@ static int show_scope(ivl_scope_t net, void*x)
is_auto = ivl_scope_is_auto(net) ? "automatic " : ""; is_auto = ivl_scope_is_auto(net) ? "automatic " : "";
switch (ivl_scope_type(net)) { switch (ivl_scope_type(net)) {
case IVL_SCT_MODULE: case IVL_SCT_MODULE:
fprintf(out, " module %s", ivl_scope_tname(net)); fprintf(out, " module %s%s", ivl_scope_tname(net),
ivl_scope_is_cell(net) ? " (cell)" : "");
break; break;
case IVL_SCT_FUNCTION: case IVL_SCT_FUNCTION:
fprintf(out, " function %s%s", is_auto, ivl_scope_tname(net)); fprintf(out, " function %s%s", is_auto, ivl_scope_tname(net));

View File

@ -1,7 +1,7 @@
/* /*
* VHDL code generation for expressions. * VHDL code generation for expressions.
* *
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk) * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -107,8 +107,10 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e)
if (ivl_signal_array_count(sig) > 0 && (off = ivl_expr_oper1(e))) { if (ivl_signal_array_count(sig) > 0 && (off = ivl_expr_oper1(e))) {
// Select from an array // Select from an array
vhdl_expr *vhd_off = translate_expr(off); vhdl_expr *vhd_off = translate_expr(off);
if (NULL == vhd_off) if (NULL == vhd_off) {
delete ref;
return NULL; return NULL;
}
vhdl_type integer(VHDL_TYPE_INTEGER); vhdl_type integer(VHDL_TYPE_INTEGER);
ref->set_slice(vhd_off->cast(&integer)); ref->set_slice(vhd_off->cast(&integer));

View File

@ -1,7 +1,7 @@
/* /*
* VHDL code generation for LPM devices. * VHDL code generation for LPM devices.
* *
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk) * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -48,10 +48,12 @@ static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
vhdl_binop_expr *expr = vhdl_binop_expr *expr =
new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type); new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type);
for (int i = ivl_lpm_selects(lpm) - 1; i >= 0; i--) { for (int i = ivl_lpm_size(lpm) - 1; i >= 0; i--) {
vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i)); vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i));
if (NULL == e) if (NULL == e) {
delete expr;
return NULL; return NULL;
}
expr->add_expr(e); expr->add_expr(e);
} }
@ -68,8 +70,10 @@ static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i)); vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i));
if (NULL == e) if (NULL == e) {
delete expr;
return NULL; return NULL;
}
expr->add_expr(e->cast(result_type)); expr->add_expr(e->cast(result_type));
} }
@ -95,8 +99,10 @@ static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i)); vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i));
if (NULL == e) if (NULL == e) {
delete expr;
return NULL; return NULL;
}
expr->add_expr(e); expr->add_expr(e);
} }
@ -135,8 +141,10 @@ static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) { for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) {
vhdl_var_ref *ref = readable_ref(scope, ivl_lpm_data(lpm, i)); vhdl_var_ref *ref = readable_ref(scope, ivl_lpm_data(lpm, i));
if (NULL == ref) if (NULL == ref) {
delete fcall;
return NULL; return NULL;
}
fcall->add_expr(ref); fcall->add_expr(ref);
} }
@ -195,8 +203,10 @@ static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
vhdl_type *atype = new vhdl_type(*adecl->get_type()); vhdl_type *atype = new vhdl_type(*adecl->get_type());
vhdl_expr *select = readable_ref(scope, ivl_lpm_select(lpm)); vhdl_expr *select = readable_ref(scope, ivl_lpm_select(lpm));
if (NULL == select) if (NULL == select) {
delete atype;
return NULL; return NULL;
}
vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype); vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype);
vhdl_type integer(VHDL_TYPE_INTEGER); vhdl_type integer(VHDL_TYPE_INTEGER);

View File

@ -95,8 +95,13 @@ int draw_process(ivl_process_t proc, void *cd)
ivl_scope_tname(scope), ivl_process_file(proc), ivl_scope_tname(scope), ivl_process_file(proc),
ivl_process_lineno(proc)); ivl_process_lineno(proc));
// A process should occur in a module scope, therefore it // Skip over any generate and begin scopes until we find
// should have already been assigned a VHDL entity // the module that contains them - this is where we will
// generate the process
while (ivl_scope_type(scope) == IVL_SCT_GENERATE
|| ivl_scope_type(scope) == IVL_SCT_BEGIN)
scope = ivl_scope_parent(scope);
assert(ivl_scope_type(scope) == IVL_SCT_MODULE); assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
vhdl_entity *ent = find_entity(scope); vhdl_entity *ent = find_entity(scope);
assert(ent != NULL); assert(ent != NULL);

View File

@ -472,12 +472,50 @@ static void avoid_name_collision(string& name, vhdl_scope* scope)
} }
} }
// Concatenate the expanded genvar values together to make a unique
// instance name
// This isn't ideal: it would be better to replace the Verilog
// generate with an equivalent VHDL generate, but this isn't possible
// with the current API
static string genvar_unique_suffix(ivl_scope_t scope)
{
ostringstream suffix;
while (scope && ivl_scope_type(scope) == IVL_SCT_GENERATE) {
for (unsigned i = 0; i < ivl_scope_params(scope); i++) {
ivl_parameter_t param = ivl_scope_param(scope, i);
ivl_expr_t e = ivl_parameter_expr(param);
if (ivl_expr_type(e) == IVL_EX_NUMBER) {
vhdl_expr* value = translate_expr(e);
assert(value);
value = value->cast(vhdl_type::integer());
suffix << "_" << ivl_parameter_basename(param);
value->emit(suffix, 0);
delete value;
}
else {
error("Only numeric genvars supported at the moment");
return "_ERROR"; // Never used
}
}
scope = ivl_scope_parent(scope);
}
return suffix.str();
}
// Declare a single signal in a scope // Declare a single signal in a scope
static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig) static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig,
ivl_scope_t scope)
{ {
remember_signal(sig, ent->get_arch()->get_scope()); remember_signal(sig, ent->get_arch()->get_scope());
string name(make_safe_name(sig)); string name(make_safe_name(sig));
name += genvar_unique_suffix(scope);
avoid_name_collision(name, ent->get_arch()->get_scope()); avoid_name_collision(name, ent->get_arch()->get_scope());
rename_signal(sig, name); rename_signal(sig, name);
@ -586,14 +624,14 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope)
ivl_signal_t sig = ivl_scope_sig(scope, i); ivl_signal_t sig = ivl_scope_sig(scope, i);
if (ivl_signal_port(sig) != IVL_SIP_NONE) if (ivl_signal_port(sig) != IVL_SIP_NONE)
declare_one_signal(ent, sig); declare_one_signal(ent, sig, scope);
} }
for (int i = 0; i < nsigs; i++) { for (int i = 0; i < nsigs; i++) {
ivl_signal_t sig = ivl_scope_sig(scope, i); ivl_signal_t sig = ivl_scope_sig(scope, i);
if (ivl_signal_port(sig) == IVL_SIP_NONE) if (ivl_signal_port(sig) == IVL_SIP_NONE)
declare_one_signal(ent, sig); declare_one_signal(ent, sig, scope);
} }
} }
@ -873,9 +911,6 @@ static int draw_skeleton_scope(ivl_scope_t scope, void *_unused)
case IVL_SCT_MODULE: case IVL_SCT_MODULE:
create_skeleton_entity_for(scope, depth); create_skeleton_entity_for(scope, depth);
break; break;
case IVL_SCT_GENERATE:
error("No translation for generate statements yet");
return 1;
case IVL_SCT_FORK: case IVL_SCT_FORK:
error("No translation for fork statements yet"); error("No translation for fork statements yet");
return 1; return 1;
@ -901,6 +936,20 @@ static int draw_all_signals(ivl_scope_t scope, void *_parent)
declare_signals(ent, scope); declare_signals(ent, scope);
} }
else if (ivl_scope_type(scope) == IVL_SCT_GENERATE) {
// Because generate scopes don't appear in the
// output VHDL all their signals are added to the
// containing entity (after being uniqued)
ivl_scope_t parent = ivl_scope_parent(scope);
while (ivl_scope_type(parent) == IVL_SCT_GENERATE)
parent = ivl_scope_parent(scope);
vhdl_entity* ent = find_entity(parent);
assert(ent);
declare_signals(ent, scope);
}
return ivl_scope_children(scope, draw_all_signals, scope); return ivl_scope_children(scope, draw_all_signals, scope);
} }
@ -952,6 +1001,7 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent)
j++) { j++) {
// Make sure the nexus code is generated // Make sure the nexus code is generated
ivl_nexus_t nex = ivl_signal_nex(sig, j); ivl_nexus_t nex = ivl_signal_nex(sig, j);
if (!nex) continue; // skip virtual pins
seen_nexus(nex); seen_nexus(nex);
nexus_private_t *priv = nexus_private_t *priv =
@ -1031,6 +1081,10 @@ static int draw_hierarchy(ivl_scope_t scope, void *_parent)
if (ivl_scope_type(scope) == IVL_SCT_MODULE && _parent) { if (ivl_scope_type(scope) == IVL_SCT_MODULE && _parent) {
ivl_scope_t parent = static_cast<ivl_scope_t>(_parent); ivl_scope_t parent = static_cast<ivl_scope_t>(_parent);
// Skip over any containing generate scopes
while (ivl_scope_type(parent) == IVL_SCT_GENERATE)
parent = ivl_scope_parent(parent);
if (!is_default_scope_instance(parent)) if (!is_default_scope_instance(parent))
return 0; // Not generating code for the parent instance so return 0; // Not generating code for the parent instance so
// don't generate for the child // don't generate for the child
@ -1053,6 +1107,7 @@ static int draw_hierarchy(ivl_scope_t scope, void *_parent)
// And an instantiation statement // And an instantiation statement
string inst_name(ivl_scope_basename(scope)); string inst_name(ivl_scope_basename(scope));
inst_name += genvar_unique_suffix(ivl_scope_parent(scope));
if (inst_name == ent->get_name() || parent_scope->have_declared(inst_name)) { if (inst_name == ent->get_name() || parent_scope->have_declared(inst_name)) {
// Cannot have instance name the same as type in VHDL // Cannot have instance name the same as type in VHDL
inst_name += "_Inst"; inst_name += "_Inst";

View File

@ -170,8 +170,12 @@ vhdl_entity* find_entity(const string& name)
// name should be the same as the Verilog module type name. // name should be the same as the Verilog module type name.
// Note that this will return NULL if no entity has been recorded // Note that this will return NULL if no entity has been recorded
// for this scope type. // for this scope type.
vhdl_entity* find_entity(const ivl_scope_t scope) vhdl_entity* find_entity(ivl_scope_t scope)
{ {
// Skip over generate scopes
while (ivl_scope_type(scope) == IVL_SCT_GENERATE)
scope = ivl_scope_parent(scope);
assert(ivl_scope_type(scope) == IVL_SCT_MODULE); assert(ivl_scope_type(scope) == IVL_SCT_MODULE);
scope_name_map_t::iterator it = g_scope_names.find(ivl_scope_tname(scope)); scope_name_map_t::iterator it = g_scope_names.find(ivl_scope_tname(scope));

View File

@ -39,7 +39,7 @@ ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope)
// Manage the set of VHDL entities // Manage the set of VHDL entities
void remember_entity(vhdl_entity *ent, ivl_scope_t scope); void remember_entity(vhdl_entity *ent, ivl_scope_t scope);
vhdl_entity* find_entity(const ivl_scope_t scope); vhdl_entity* find_entity(ivl_scope_t scope);
vhdl_entity* find_entity(const std::string& name); vhdl_entity* find_entity(const std::string& name);
void emit_all_entities(std::ostream& os, int max_depth); void emit_all_entities(std::ostream& os, int max_depth);
void free_all_vhdl_objects(); void free_all_vhdl_objects();

View File

@ -313,11 +313,11 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
if (NULL == test) if (NULL == test)
return; return;
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
if (!check_valid_assignment(decl->assignment_type(), proc, stmt)) if (!check_valid_assignment(decl->assignment_type(), proc, stmt))
return; return;
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
// True part // True part
{ {
vhdl_abstract_assign_stmt *a = vhdl_abstract_assign_stmt *a =
@ -552,7 +552,7 @@ static void get_nexuses_from_expr(ivl_expr_t expr, set<ivl_nexus_t> &out)
/* /*
* Attempt to identify common forms of wait statements and produce * Attempt to identify common forms of wait statements and produce
* more idiomatic VHDL than would be produced by the generic * more idiomatic VHDL than would be produced by the generic
* draw_wait funciton. The main application of this is a input to * draw_wait function. The main application of this is a input to
* synthesis tools that don't synthesise the full VHDL language. * synthesis tools that don't synthesise the full VHDL language.
* If none of these patterns are matched, the function returns false * If none of these patterns are matched, the function returns false
* and the default draw_wait is used. * and the default draw_wait is used.
@ -1342,6 +1342,7 @@ int draw_casezx(vhdl_procedural *proc, stmt_container *container,
"expression labels can be translated to VHDL", "expression labels can be translated to VHDL",
ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), ivl_stmt_file(stmt), ivl_stmt_lineno(stmt),
(is_casez ? "z" : "x")); (is_casez ? "z" : "x"));
delete all;
return 1; return 1;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -19,9 +19,6 @@
# include "vvp_priv.h" # include "vvp_priv.h"
# include <assert.h> # include <assert.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <stdlib.h> # include <stdlib.h>
# include <string.h> # include <string.h>
@ -51,12 +48,20 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
if (number_is_immediate(d_rise, 64, 0) && if (number_is_immediate(d_rise, 64, 0) &&
number_is_immediate(d_fall, 64, 0) && number_is_immediate(d_fall, 64, 0) &&
number_is_immediate(d_decay, 64, 0)) { number_is_immediate(d_decay, 64, 0)) {
assert( ! number_is_unknown(d_rise));
assert( ! number_is_unknown(d_fall));
assert( ! number_is_unknown(d_decay));
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n", fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
net, get_number_immediate(d_rise), net, get_number_immediate(d_rise),
get_number_immediate(d_rise), get_number_immediate(d_fall),
get_number_immediate(d_rise), net); get_number_immediate(d_decay), net);
} else { } else {
ivl_signal_t sig; ivl_signal_t sig;
// We do not currently support calculating the decay from
// the rise and fall variable delays.
assert(d_decay != 0);
assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL); assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL); assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL); assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL);

View File

@ -388,14 +388,21 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
number_is_immediate(d_fall, 64, 0) && number_is_immediate(d_fall, 64, 0) &&
number_is_immediate(d_decay, 64, 0)) { number_is_immediate(d_decay, 64, 0)) {
assert(! number_is_unknown(d_rise));
assert(! number_is_unknown(d_fall));
assert(! number_is_unknown(d_decay));
fprintf(vvp_out, "L_%p .delay " fprintf(vvp_out, "L_%p .delay "
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n", "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
cptr, get_number_immediate64(d_rise), cptr, get_number_immediate64(d_rise),
get_number_immediate64(d_rise), get_number_immediate64(d_fall),
get_number_immediate64(d_rise), cptr); get_number_immediate64(d_decay), cptr);
} else { } else {
ivl_signal_t sig; ivl_signal_t sig;
// We do not currently support calculating the decay
// from the rise and fall variable delays.
assert(d_decay != 0);
assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL); assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL); assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL); assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL);
@ -502,6 +509,16 @@ static char* draw_island_port(ivl_island_t island,
/* Omit LPMPART_BI device pin-data(0) drivers. */ /* Omit LPMPART_BI device pin-data(0) drivers. */
# define OMIT_PART_BI_DATA 0x0001 # define OMIT_PART_BI_DATA 0x0001
static ivl_nexus_ptr_t *drivers = 0x0;
static unsigned adrivers = 0;
void EOC_cleanup_drivers()
{
free(drivers);
drivers = NULL;
adrivers = 0;
}
char* draw_net_input_x(ivl_nexus_t nex, char* draw_net_input_x(ivl_nexus_t nex,
ivl_nexus_ptr_t omit_ptr, int omit_flags, ivl_nexus_ptr_t omit_ptr, int omit_flags,
struct vvp_nexus_data*nex_data) struct vvp_nexus_data*nex_data)
@ -512,8 +529,6 @@ char* draw_net_input_x(ivl_nexus_t nex,
unsigned idx; unsigned idx;
int level; int level;
unsigned ndrivers = 0; unsigned ndrivers = 0;
static ivl_nexus_ptr_t *drivers = 0x0;
static unsigned adrivers = 0;
const char*resolv_type; const char*resolv_type;

View File

@ -109,6 +109,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
if (word_ex) { if (word_ex) {
/* Some array select have been evaluated. */ /* Some array select have been evaluated. */
if (number_is_immediate(word_ex,IMM_WID, 0)) { if (number_is_immediate(word_ex,IMM_WID, 0)) {
assert(! number_is_unknown(word_ex));
use_word = get_number_immediate(word_ex); use_word = get_number_immediate(word_ex);
word_ex = 0; word_ex = 0;
} }
@ -125,11 +126,14 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
Create the right code to handle it. */ Create the right code to handle it. */
ivl_signal_t sig = ivl_expr_signal(expr); ivl_signal_t sig = ivl_expr_signal(expr);
unsigned use_word = 0; unsigned use_word = 0;
unsigned use_word_defined = 0;
ivl_expr_t word_ex = ivl_expr_oper1(expr); ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex) { if (word_ex) {
/* Some array select have been evaluated. */ /* Some array select have been evaluated. */
if (number_is_immediate(word_ex, IMM_WID, 0)) { if (number_is_immediate(word_ex, IMM_WID, 0)) {
assert(! number_is_unknown(word_ex));
use_word = get_number_immediate(word_ex); use_word = get_number_immediate(word_ex);
use_word_defined = 1;
word_ex = 0; word_ex = 0;
} }
} }
@ -156,6 +160,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
result->vec = av; result->vec = av;
result->vec_flag = 1; result->vec_flag = 1;
} else { } else {
assert(use_word_defined);
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", snprintf(buffer, sizeof buffer, "&A<v%p, %u>",
sig, use_word); sig, use_word);
} }
@ -182,6 +187,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
/* This is a constant bit/part select. */ /* This is a constant bit/part select. */
if (number_is_immediate(bexpr, 64, 1)) { if (number_is_immediate(bexpr, 64, 1)) {
assert(! number_is_unknown(bexpr));
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>", snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
ivl_expr_signal(vexpr), ivl_expr_signal(vexpr),
get_number_immediate(bexpr), get_number_immediate(bexpr),
@ -203,9 +209,19 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
return 0; return 0;
} }
} else { } else {
/* Fallback case: evaluate the expression. */ /* Fallback case: evaluate the expression. */
struct vector_info rv; struct vector_info rv;
rv = draw_eval_expr(bexpr, STUFF_OK_XZ); rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
/* We need to enhance &PV<> to support a signed index. */
if (ivl_expr_signed(bexpr) &&
(ivl_expr_width(bexpr) < 8*sizeof(int))) {
fprintf(stderr, "%s:%u: tgt-vvp warning: V0.9 may give "
"incorrect results for a select with a "
"signed index less than %zu bits.\n",
ivl_expr_file(expr),
ivl_expr_lineno(expr),
8*sizeof(int));
}
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>", snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
ivl_expr_signal(vexpr), ivl_expr_signal(vexpr),
rv.base, rv.wid, rv.base, rv.wid,

View File

@ -174,6 +174,12 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
case IVL_EX_ULONG: case IVL_EX_ULONG:
{ {
assert(number_is_immediate(expr, IMM_WID, 1)); assert(number_is_immediate(expr, IMM_WID, 1));
if (number_is_unknown(expr)) {
/* We are loading a 'bx so mimic %ix/get. */
fprintf(vvp_out, " %%ix/load %u, 0, 0;\n", ix);
fprintf(vvp_out, " %%mov 4, 1, 1;\n");
break;
}
long imm = get_number_immediate(expr); long imm = get_number_immediate(expr);
if (imm >= 0) { if (imm >= 0) {
fprintf(vvp_out, " %%ix/load %u, %ld, 0;\n", ix, imm); fprintf(vvp_out, " %%ix/load %u, %ld, 0;\n", ix, imm);
@ -192,6 +198,7 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
unsigned word = 0; unsigned word = 0;
if (ivl_signal_dimensions(sig) > 0) { if (ivl_signal_dimensions(sig) > 0) {
ivl_expr_t ixe; ivl_expr_t ixe;
char*type = ivl_expr_signed(expr) ? "/s" : "";
/* Detect the special case that this is a /* Detect the special case that this is a
variable array. In this case, the ix/getv variable array. In this case, the ix/getv
@ -199,20 +206,21 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
if (ivl_signal_type(sig) == IVL_SIT_REG) { if (ivl_signal_type(sig) == IVL_SIT_REG) {
struct vector_info rv; struct vector_info rv;
rv = draw_eval_expr(expr, 0); rv = draw_eval_expr(expr, 0);
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", fprintf(vvp_out, " %%ix/get%s %u, %u, %u;\n",
ix, rv.base, rv.wid); type, ix, rv.base, rv.wid);
clr_vector(rv); clr_vector(rv);
break; break;
} }
ixe = ivl_expr_oper1(expr); ixe = ivl_expr_oper1(expr);
if (number_is_immediate(ixe, IMM_WID, 0)) if (number_is_immediate(ixe, IMM_WID, 0)) {
assert(! number_is_unknown(ixe));
word = get_number_immediate(ixe); word = get_number_immediate(ixe);
else { } else {
struct vector_info rv; struct vector_info rv;
rv = draw_eval_expr(expr, 0); rv = draw_eval_expr(expr, 0);
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", fprintf(vvp_out, " %%ix/get%s %u, %u, %u;\n",
ix, rv.base, rv.wid); type, ix, rv.base, rv.wid);
clr_vector(rv); clr_vector(rv);
break; break;
} }
@ -226,8 +234,14 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
default: { default: {
struct vector_info rv; struct vector_info rv;
rv = draw_eval_expr(expr, 0); rv = draw_eval_expr(expr, 0);
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", /* Is this a signed expression? */
ix, rv.base, rv.wid); if (ivl_expr_signed(expr)) {
fprintf(vvp_out, " %%ix/get/s %u, %u, %u;\n",
ix, rv.base, rv.wid);
} else {
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
ix, rv.base, rv.wid);
}
clr_vector(rv); clr_vector(rv);
break; break;
} }
@ -274,7 +288,10 @@ static struct vector_info draw_eq_immediate(ivl_expr_t exp, unsigned ewid,
{ {
unsigned wid; unsigned wid;
struct vector_info lv; struct vector_info lv;
unsigned long imm = get_number_immediate(re); unsigned long imm;
assert(number_is_immediate(re, IMM_WID, 0));
assert(! number_is_unknown(re));
imm = get_number_immediate(re);
wid = ivl_expr_width(le); wid = ivl_expr_width(le);
lv = draw_eval_expr_wid(le, wid, stuff_ok_flag); lv = draw_eval_expr_wid(le, wid, stuff_ok_flag);
@ -991,6 +1008,8 @@ static struct vector_info draw_logic_immediate(ivl_expr_t exp,
unsigned wid) unsigned wid)
{ {
struct vector_info lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ); struct vector_info lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
assert(number_is_immediate(re, IMM_WID, 0));
assert(! number_is_unknown(re));
unsigned long imm = get_number_immediate(re); unsigned long imm = get_number_immediate(re);
assert(lv.base >= 4); assert(lv.base >= 4);
@ -1241,8 +1260,10 @@ static struct vector_info draw_load_add_immediate(ivl_expr_t le,
int signed_flag) int signed_flag)
{ {
struct vector_info lv; struct vector_info lv;
long imm = get_number_immediate(re); long imm;
assert(! number_is_unknown(re));
assert(number_is_immediate(re, IMM_WID, 1)); assert(number_is_immediate(re, IMM_WID, 1));
imm = get_number_immediate(re);
lv.base = allocate_vector(wid); lv.base = allocate_vector(wid);
lv.wid = wid; lv.wid = wid;
if (lv.base == 0) { if (lv.base == 0) {
@ -1270,6 +1291,8 @@ static struct vector_info draw_add_immediate(ivl_expr_t le,
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ); lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
assert(lv.wid == wid); assert(lv.wid == wid);
assert(! number_is_unknown(re));
assert(number_is_immediate(re, IMM_WID, 0));
imm = get_number_immediate(re); imm = get_number_immediate(re);
/* This shouldn't generally happen, because the elaborator /* This shouldn't generally happen, because the elaborator
@ -1308,7 +1331,7 @@ static struct vector_info draw_add_immediate(ivl_expr_t le,
} }
break; break;
case 2: /* Left expression is X or Z */ case 2: /* Left expression is 'bx or 'bz */
case 3: case 3:
lv.base = 2; lv.base = 2;
break; break;
@ -1335,6 +1358,8 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ); lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
assert(lv.wid == wid); assert(lv.wid == wid);
assert(! number_is_unknown(re));
assert(number_is_immediate(re, IMM_WID, 0));
imm = get_number_immediate(re); imm = get_number_immediate(re);
if (imm == 0) if (imm == 0)
return lv; return lv;
@ -1379,6 +1404,8 @@ static struct vector_info draw_mul_immediate(ivl_expr_t le,
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ); lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
assert(lv.wid == wid); assert(lv.wid == wid);
assert(! number_is_unknown(re));
assert(number_is_immediate(re, IMM_WID, 0));
imm = get_number_immediate(re); imm = get_number_immediate(re);
if (imm == 0) if (imm == 0)
return lv; return lv;
@ -1396,9 +1423,9 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
struct vector_info lv; struct vector_info lv;
struct vector_info rv; struct vector_info rv;
const char*sign_string = ivl_expr_signed(le) && ivl_expr_signed(re)? "/s" : ""; int signed_flag = ivl_expr_signed(le) && ivl_expr_signed(re) ? 1 : 0;
const char*sign_string = signed_flag ? "/s" : "";
int signed_flag = ivl_expr_signed(exp)? 1 : 0;
if ((ivl_expr_opcode(exp) == '+') if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(le) == IVL_EX_SIGNAL) && (ivl_expr_type(le) == IVL_EX_SIGNAL)
@ -1619,82 +1646,118 @@ static struct vector_info draw_binary_expr(ivl_expr_t exp,
static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid, static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid,
int stuff_ok_flag) int stuff_ok_flag)
{ {
unsigned off, rep; unsigned off, rep, expr_wid, concat_wid, num_sube, idx;
struct vector_info res; struct vector_info res;
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1; int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1;
/* Allocate a vector to hold the result. */ /* Find out how wide the base concatenation expression is. */
res.base = allocate_vector(wid); num_sube = ivl_expr_parms(exp);
res.wid = wid; expr_wid = 0;
if (res.base == 0) { for (idx = 0 ; idx < num_sube; idx += 1) {
fprintf(stderr, "%s:%u: vvp.tgt error: " expr_wid += ivl_expr_width(ivl_expr_parm(exp, idx));
"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 /* Get the repeat count. This must be a constant that has been
evaluated at compile time. The operands will be repeated to evaluated at compile time. The operands will be repeated to
form the result. */ form the result. */
rep = ivl_expr_repeat(exp); rep = ivl_expr_repeat(exp);
off = 0;
while (rep > 0) { /* Allocate a vector to hold the result. */
if (rep == 0) {
/* If the replication is zero we need to allocate temporary
* space to build the concatenation. */
res.base = allocate_vector(expr_wid);
res.wid = expr_wid;
} else {
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),
rep ? wid : expr_wid);
vvp_errors += 1;
}
/* Each repeat, evaluate the sub-expressions, from lsb /* If the result is the right size we can just build this in place. */
to msb, and copy each into the result vector. The concat_wid = rep*expr_wid;
expressions are arranged in the concatenation from if (concat_wid <= wid) {
MSB to LSB, to go through them backwards. off = 0;
/* Evaluate the base expression. */
Abort the loop if the result vector gets filled up. */ for (idx = num_sube; idx > 0; idx -= 1) {
unsigned idx = ivl_expr_parms(exp);
while ((idx > 0) && (off < wid)) {
ivl_expr_t arg = ivl_expr_parm(exp, idx-1); ivl_expr_t arg = ivl_expr_parm(exp, idx-1);
unsigned awid = ivl_expr_width(arg); unsigned awid = ivl_expr_width(arg);
unsigned trans;
struct vector_info avec; struct vector_info avec;
assert(awid+off <= expr_wid);
/* Try to locate the subexpression in the /* Try to locate the subexpression in the
lookaside map. */ * lookaside map and use it when available. */
avec.base = allocate_vector_exp(arg, awid, alloc_exclusive); avec.base = allocate_vector_exp(arg, awid, alloc_exclusive);
avec.wid = awid; avec.wid = awid;
trans = awid;
if ((off + awid) > wid)
trans = wid - off;
if (avec.base != 0) { if (avec.base != 0) {
assert(awid == avec.wid); assert(awid == avec.wid);
fprintf(vvp_out, " %%mov %u, %u, %u; Reuse "
fprintf(vvp_out, " %%mov %u, %u, %u; Reuse calculated expression\n", "calculated expression.\n",
res.base+off, res.base+off, avec.base, awid);
avec.base, trans); clr_vector(avec);
clr_vector(avec);
} else { } else {
struct vector_info dest; struct vector_info dest;
dest.base = res.base+off; dest.base = res.base+off;
dest.wid = trans; dest.wid = awid;
draw_eval_expr_dest(arg, dest, 0); draw_eval_expr_dest(arg, dest, 0);
} }
off += awid;
idx -= 1;
off += trans;
assert(off <= wid);
} }
rep -= 1;
}
/* Pad the result with 0, if necessary. */ /* Now repeat the expression as needed. */
if (off < wid) { if (rep != 0) {
fprintf(vvp_out, " %%mov %u, 0, %u;\n", rep -= 1;
res.base+off, wid-off); } else {
/* Clear the temporary space and return nothing.
* This will be caught in draw_eval_expr_dest()
* and dropped. */
clr_vector(res);
res.base = 0;
res.wid = 0;
}
while (rep > 0) {
fprintf(vvp_out, " %%mov %u, %u, %u; Repetition %u\n",
res.base+expr_wid*rep, res.base, expr_wid,
rep+1);
rep -= 1;
}
/* Pad the expression when needed. */
if (wid > concat_wid) {
/* We can get a signed concatenation with $signed({...}). */
if (ivl_expr_signed(exp)) {
unsigned base = res.base+concat_wid-1;
for (idx = 1; idx <= wid-concat_wid; idx += 1) {
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
base+idx, base);
}
} else {
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
res.base+concat_wid, wid-concat_wid);
}
}
} else {
/* The concatenation is too big for the result so draw it
* at full width and then copy the bits that are needed. */
struct vector_info full_res;
full_res = draw_concat_expr(exp, concat_wid, stuff_ok_flag);
assert(full_res.base);
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base,
full_res.base, wid);
clr_vector(full_res);
} }
/* Save the accumulated result in the lookaside map. */ /* Save the accumulated result in the lookaside map. */
@ -1853,7 +1916,7 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
/* /*
* This little helper function generates the instructions to pad a * This little helper function generates the instructions to pad a
* vector in place. It is assumed that the calling functio has set up * vector in place. It is assumed that the calling function has set up
* the first sub_sidth bits of the dest vector, and the signed_flag is * the first sub_sidth bits of the dest vector, and the signed_flag is
* true if the extension is to be signed. * true if the extension is to be signed.
*/ */
@ -2217,7 +2280,7 @@ static struct vector_info draw_select_array(ivl_expr_t sube,
unsigned bit_width, unsigned bit_width,
unsigned wid) unsigned wid)
{ {
unsigned idx; unsigned idx, label;
ivl_signal_t sig = ivl_expr_signal(sube); ivl_signal_t sig = ivl_expr_signal(sube);
/* unsigned sig_wid = ivl_expr_width(sube); */ /* unsigned sig_wid = ivl_expr_width(sube); */
ivl_expr_t ix = ivl_expr_oper1(sube); ivl_expr_t ix = ivl_expr_oper1(sube);
@ -2227,7 +2290,18 @@ static struct vector_info draw_select_array(ivl_expr_t sube,
shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO); shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO);
draw_eval_expr_into_integer(ix, 3); draw_eval_expr_into_integer(ix, 3);
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid); label = local_count++;
/* We can safely skip the bit index load below if the array word
* index is undefined. We need to do this so that the bit index
* load does not reset bit 4 to zero by loading a defined value. */
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, label);
if (ivl_expr_signed(bit_idx)) {
fprintf(vvp_out, " %%ix/get/s 0, %u, %u;\n", shiv.base,
shiv.wid);
} else {
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
}
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, label);
if (shiv.base >= 8) if (shiv.base >= 8)
clr_vector(shiv); clr_vector(shiv);
@ -2258,7 +2332,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
/* Use this word of the signal. */ /* Use this word of the signal. */
unsigned use_word = 0; unsigned use_word = 0;
unsigned use_wid; unsigned use_wid, lab_x, lab_end;
/* If this is an access to an array, try to get the index as a /* If this is an access to an array, try to get the index as a
constant. If it is (and the array is not a reg array then constant. If it is (and the array is not a reg array then
@ -2275,6 +2349,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
/* The index is constant, so we can return to direct /* The index is constant, so we can return to direct
readout with the specific word selected. */ readout with the specific word selected. */
assert(! number_is_unknown(ix));
use_word = get_number_immediate(ix); use_word = get_number_immediate(ix);
} }
@ -2282,6 +2357,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
the signal (or the entire width). Just load the early bits the signal (or the entire width). Just load the early bits
in one go. */ in one go. */
if (number_is_immediate(bit_idx, 32, 0) if (number_is_immediate(bit_idx, 32, 0)
&& !number_is_unknown(bit_idx)
&& get_number_immediate(bit_idx) == 0 && get_number_immediate(bit_idx) == 0
&& (ivl_expr_width(sube) >= bit_wid)) { && (ivl_expr_width(sube) >= bit_wid)) {
@ -2307,6 +2383,12 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
res.wid = wid; res.wid = wid;
assert(res.base); assert(res.base);
lab_x = local_count++;
lab_end = local_count++;
/* If the index is 'bx then we just return 'bx. */
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, lab_x);
use_wid = res.wid; use_wid = res.wid;
if (use_wid > bit_wid) if (use_wid > bit_wid)
use_wid = bit_wid; use_wid = bit_wid;
@ -2317,6 +2399,11 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
fprintf(vvp_out, " %%movi %u, 0, %u;\n", fprintf(vvp_out, " %%movi %u, 0, %u;\n",
res.base + use_wid, res.wid - use_wid); res.base + use_wid, res.wid - use_wid);
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_end);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_x);
fprintf(vvp_out, " %%mov %u, 2, %u;\n", res.base, res.wid);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_end);
return res; return res;
} }
@ -2335,6 +2422,7 @@ static void draw_select_signal_dest(ivl_expr_t sube,
if ((ivl_signal_dimensions(sig) == 0) if ((ivl_signal_dimensions(sig) == 0)
&& (ivl_expr_width(sube) >= dest.wid) && (ivl_expr_width(sube) >= dest.wid)
&& number_is_immediate(bit_idx, 32, 0) && number_is_immediate(bit_idx, 32, 0)
&& ! number_is_unknown(bit_idx)
&& get_number_immediate(bit_idx) == 0) { && get_number_immediate(bit_idx) == 0) {
unsigned use_word = 0; unsigned use_word = 0;
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Select %u out of %u bits\n", fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Select %u out of %u bits\n",
@ -2365,6 +2453,8 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
ivl_expr_t shift = ivl_expr_oper2(exp); ivl_expr_t shift = ivl_expr_oper2(exp);
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO)? 0 : 1; int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO)? 0 : 1;
int cmp;
unsigned lab_l, lab_end;
res.wid = wid; res.wid = wid;
@ -2408,7 +2498,12 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
return res; return res;
} }
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid); if (ivl_expr_signed(shift)) {
fprintf(vvp_out, " %%ix/get/s 0, %u, %u;\n", shiv.base,
shiv.wid);
} else {
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
}
clr_vector(shiv); clr_vector(shiv);
/* If the subv result is a magic constant, then make a copy in /* If the subv result is a magic constant, then make a copy in
@ -2422,7 +2517,27 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
subv = res; subv = res;
} }
lab_l = local_count++;
lab_end = local_count++;
/* If we have an undefined index then just produce a 'bx result. */
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, lab_l);
cmp = allocate_word();
assert(subv.wid >= wid);
/* Determine if we need to shift a 'bx into the top. */
fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", cmp, subv.wid - wid);
fprintf(vvp_out, " %%cmp/ws %u, 0;\n", cmp);
clr_word(cmp);
fprintf(vvp_out, " %%jmp/1 T_%d.%d, 5;\n", thread_count, lab_l);
/* Clear the cmp bit if the two values are equal. */
fprintf(vvp_out, " %%mov 4, 0, 1;\n");
fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", subv.base, subv.wid); fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", subv.base, subv.wid);
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_end);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_l);
/* Multiply by -1. */
fprintf(vvp_out, " %%ix/mul 0, %u, %u;\n", 0xFFFFFFFF, 0xFFFFFFFF);
fprintf(vvp_out, " %%shiftl/i0 %u, %u;\n", subv.base, subv.wid);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_end);
if (subv.wid > wid) { if (subv.wid > wid) {
res.base = subv.base; res.base = subv.base;
@ -2456,7 +2571,7 @@ static void draw_select_expr_dest(ivl_expr_t exp, struct vector_info dest,
/* If the shift expression is not present, then this is really /* If the shift expression is not present, then this is really
a pad expression, and that can be handled pretty a pad expression, and that can be handled pretty
easily. Evalutate the subexpression into the destination, easily. Evaluate the subexpression into the destination,
then pad in place. */ then pad in place. */
if (shift == 0) { if (shift == 0) {
struct vector_info subv; struct vector_info subv;
@ -2843,8 +2958,9 @@ static void draw_eval_expr_dest(ivl_expr_t exp, struct vector_info dest,
tmp = draw_eval_expr_wid(exp, dest.wid, stuff_ok_flag); tmp = draw_eval_expr_wid(exp, dest.wid, stuff_ok_flag);
assert(tmp.wid == dest.wid); assert(tmp.wid == dest.wid);
fprintf(vvp_out, " %%mov %u, %u, %u;\n", /* If the replication is 0 we can have a zero width, so skip it. */
dest.base, tmp.base, dest.wid); if (dest.wid) fprintf(vvp_out, " %%mov %u, %u, %u;\n",
dest.base, tmp.base, dest.wid);
if (tmp.base >= 8) if (tmp.base >= 8)
save_expression_lookaside(tmp.base, exp, tmp.wid); save_expression_lookaside(tmp.base, exp, tmp.wid);
@ -2867,6 +2983,12 @@ struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned wid,
res.base = 0; res.base = 0;
res.wid = 0; res.wid = 0;
break; break;
case IVL_EX_EVENT:
fprintf(stderr, "%s:%u: vvp-tgt error: A named event is not "
"handled in this context (expression).\n",
ivl_expr_file(exp), ivl_expr_lineno(exp));
exit(1);
break;
case IVL_EX_STRING: case IVL_EX_STRING:
res = draw_string_expr(exp, wid); res = draw_string_expr(exp, wid);

View File

@ -22,9 +22,6 @@
*/ */
# include "vvp_priv.h" # include "vvp_priv.h"
# include <string.h> # include <string.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <stdlib.h> # include <stdlib.h>
# include <math.h> # include <math.h>
# include <assert.h> # include <assert.h>
@ -55,9 +52,6 @@ static int draw_binary_real(ivl_expr_t expr)
{ {
int l, r = -1; 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(expr)) { switch (ivl_expr_opcode(expr)) {
case 'E': case 'E':
case 'N': case 'N':
@ -70,22 +64,8 @@ static int draw_binary_real(ivl_expr_t expr)
case 'A': case 'A':
case 'O': case 'O':
case 'X': case 'X':
{ /* These should be caught in draw_eval_real(). */
struct vector_info vi; assert(0);
int res;
const char*sign_flag;
vi = draw_eval_expr(expr, STUFF_OK_XZ);
res = allocate_word();
sign_flag = ivl_expr_signed(expr)? "/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(expr)); l = draw_eval_real(ivl_expr_oper1(expr));
@ -120,16 +100,20 @@ static int draw_binary_real(ivl_expr_t expr)
int lab_out = local_count++; int lab_out = local_count++;
int lab_r = local_count++; int lab_r = local_count++;
/* If r is NaN, the go out and accept l as result. */ /* 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, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out); 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. */ /* 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, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r); fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count,
lab_r);
/* If l <= r then go out. */ /* If l <= r then go out. */
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l); fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out); 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. */ /* 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 %%mov/wr %d, %d;\n", thread_count,
lab_r, l, r);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
break; break;
} }
@ -138,16 +122,20 @@ static int draw_binary_real(ivl_expr_t expr)
int lab_out = local_count++; int lab_out = local_count++;
int lab_r = local_count++; int lab_r = local_count++;
/* If r is NaN, the go out and accept l as result. */ /* 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, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out); 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. */ /* 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, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r); fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count,
lab_r);
/* if l >= r then go out. */ /* if l >= r then go out. */
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r); 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, " %%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 %%mov/wr %d, %d;\n", thread_count,
lab_r, l, r);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
break; break;
} }
@ -508,8 +496,10 @@ static int draw_unary_real(ivl_expr_t expr)
return sub; return sub;
} }
fprintf(vvp_out, "; XXXX unary (%c) on sube in %d\n", ivl_expr_opcode(expr), sub); fprintf(vvp_out, "; XXXX unary (%c) on sube in %d\n",
fprintf(stderr, "XXXX evaluate unary (%c) on sube in %d\n", ivl_expr_opcode(expr), sub); ivl_expr_opcode(expr), sub);
fprintf(stderr, "XXXX evaluate unary (%c) on sube in %d\n",
ivl_expr_opcode(expr), sub);
return 0; return 0;
} }
@ -517,6 +507,27 @@ int draw_eval_real(ivl_expr_t expr)
{ {
int res = 0; int res = 0;
/* If this expression/sub-expression is not real then we need
* to evaluate it as a bit value and then convert the bit based
* result to a real value. This is required to get integer
* division to work correctly. */
if (ivl_expr_value(expr) != IVL_VT_REAL) {
struct vector_info vi;
int res;
const char*sign_flag;
vi = draw_eval_expr(expr, STUFF_OK_XZ);
res = allocate_word();
sign_flag = ivl_expr_signed(expr)? "/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;
}
switch (ivl_expr_type(expr)) { switch (ivl_expr_type(expr)) {
case IVL_EX_BINARY: case IVL_EX_BINARY:

View File

@ -140,6 +140,7 @@ int target_design(ivl_design_t des)
} }
fclose(vvp_out); fclose(vvp_out);
EOC_cleanup_drivers();
return rc + vvp_errors; return rc + vvp_errors;
} }

View File

@ -1,7 +1,7 @@
#ifndef __vvp_priv_H #ifndef __vvp_priv_H
#define __vvp_priv_H #define __vvp_priv_H
/* /*
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -141,6 +141,7 @@ struct vvp_nexus_data {
* cache it. * cache it.
*/ */
extern const char* draw_net_input(ivl_nexus_t nex); extern const char* draw_net_input(ivl_nexus_t nex);
void EOC_cleanup_drivers();
/* /*
* See draw_net_input.c for details on draw_net_input_x. (It would be * See draw_net_input.c for details on draw_net_input_x. (It would be

View File

@ -87,7 +87,8 @@ static void set_to_lvariable(ivl_lval_t lval,
if (part_off_ex == 0) { if (part_off_ex == 0) {
part_off = 0; part_off = 0;
} else if (number_is_immediate(part_off_ex, IMM_WID, 0)) { } else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
!number_is_unknown(part_off_ex)) {
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
part_off_ex = 0; part_off_ex = 0;
} }
@ -96,6 +97,7 @@ static void set_to_lvariable(ivl_lval_t lval,
it to select the word, and pay no further heed to the it to select the word, and pay no further heed to the
expression itself. */ expression itself. */
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) { if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
assert(! number_is_unknown(word_ix));
use_word = get_number_immediate(word_ix); use_word = get_number_immediate(word_ix);
word_ix = 0; word_ix = 0;
} }
@ -233,12 +235,14 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
if (part_off_ex == 0) { if (part_off_ex == 0) {
part_off = 0; part_off = 0;
} else if (number_is_immediate(part_off_ex, IMM_WID, 0)) { } else if (number_is_immediate(part_off_ex, IMM_WID, 0)) {
assert(! number_is_unknown(part_off_ex));
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
part_off_ex = 0; part_off_ex = 0;
} }
/* This code is common to all the different types of array delays. */ /* This code is common to all the different types of array delays. */
if (number_is_immediate(word_ix, IMM_WID, 0)) { if (number_is_immediate(word_ix, IMM_WID, 0)) {
assert(! number_is_unknown(word_ix));
fprintf(vvp_out, " %%ix/load 3, %lu, 0; address\n", fprintf(vvp_out, " %%ix/load 3, %lu, 0; address\n",
get_number_immediate(word_ix)); get_number_immediate(word_ix));
} else { } else {
@ -317,6 +321,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
if (part_off_ex == 0) { if (part_off_ex == 0) {
part_off = 0; part_off = 0;
} else if (number_is_immediate(part_off_ex, IMM_WID, 0)) { } else if (number_is_immediate(part_off_ex, IMM_WID, 0)) {
assert(! number_is_unknown(part_off_ex));
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
part_off_ex = 0; part_off_ex = 0;
} }
@ -647,7 +652,15 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
word_ix = ivl_lval_idx(lval); word_ix = ivl_lval_idx(lval);
assert(word_ix); assert(word_ix);
assert(number_is_immediate(word_ix, IMM_WID, 0)); assert(number_is_immediate(word_ix, IMM_WID, 0));
assert(! number_is_unknown(word_ix));
use_word = get_number_immediate(word_ix); use_word = get_number_immediate(word_ix);
/* This method no longer works since variable arrays do not
* support <variable_id>_<idx> access any more. We need real
* array specific opcodes (%assign/ar, etc.). */
fprintf(stderr, "%s:%u: vvp-tgt sorry: non-blocking assignment "
"to a real array word is not supported.\n",
ivl_expr_file(rval), ivl_expr_lineno(rval));
exit(1);
} }
if (del && (ivl_expr_type(del) == IVL_EX_DELAY)) { if (del && (ivl_expr_type(del) == IVL_EX_DELAY)) {
@ -1105,11 +1118,13 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
part_off = 0; part_off = 0;
} else { } else {
assert(number_is_immediate(part_off_ex, IMM_WID, 0)); assert(number_is_immediate(part_off_ex, IMM_WID, 0));
assert(! number_is_unknown(part_off_ex));
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
} }
if (word_idx != 0) { if (word_idx != 0) {
assert(number_is_immediate(word_idx, IMM_WID, 0)); assert(number_is_immediate(word_idx, IMM_WID, 0));
assert(! number_is_unknown(word_idx));
use_word = get_number_immediate(word_idx); use_word = get_number_immediate(word_idx);
} }
@ -1174,6 +1189,7 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
* part select (this could give us multiple drivers). */ * part select (this could give us multiple drivers). */
part_off_ex = ivl_lval_part_off(lval); part_off_ex = ivl_lval_part_off(lval);
if (ivl_signal_width(lsig) > ivl_signal_width(rsig) || if (ivl_signal_width(lsig) > ivl_signal_width(rsig) ||
// Do we need checks for number_is{immediate,unknown} of part_of_ex?
(part_off_ex && get_number_immediate(part_off_ex) != 0)) { (part_off_ex && get_number_immediate(part_off_ex) != 0)) {
fprintf(stderr, "%s:%u: vvp-tgt sorry: cannot %s signal to " fprintf(stderr, "%s:%u: vvp-tgt sorry: cannot %s signal to "
"a bit/part select.\n", ivl_expr_file(rval), "a bit/part select.\n", ivl_expr_file(rval),
@ -1184,11 +1200,13 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
/* At least for now, only handle force to fixed words of an array. */ /* At least for now, only handle force to fixed words of an array. */
if ((lword_idx = ivl_lval_idx(lval)) != 0) { if ((lword_idx = ivl_lval_idx(lval)) != 0) {
assert(number_is_immediate(lword_idx, IMM_WID, 0)); assert(number_is_immediate(lword_idx, IMM_WID, 0));
assert(! number_is_unknown(lword_idx));
use_lword = get_number_immediate(lword_idx); use_lword = get_number_immediate(lword_idx);
} }
if ((rword_idx = ivl_expr_oper1(rval)) != 0) { if ((rword_idx = ivl_expr_oper1(rval)) != 0) {
assert(number_is_immediate(rword_idx, IMM_WID, 0)); assert(number_is_immediate(rword_idx, IMM_WID, 0));
assert(! number_is_unknown(rword_idx));
use_rword = get_number_immediate(rword_idx); use_rword = get_number_immediate(rword_idx);
} }
@ -1272,11 +1290,13 @@ static int show_stmt_deassign(ivl_statement_t net)
part_off = 0; part_off = 0;
if (part_off_ex != 0) { if (part_off_ex != 0) {
assert(number_is_immediate(part_off_ex, 64, 0)); assert(number_is_immediate(part_off_ex, 64, 0));
assert(! number_is_unknown(part_off_ex));
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
} }
if (word_idx != 0) { if (word_idx != 0) {
assert(number_is_immediate(word_idx, IMM_WID, 0)); assert(number_is_immediate(word_idx, IMM_WID, 0));
assert(! number_is_unknown(word_idx));
use_word = get_number_immediate(word_idx); use_word = get_number_immediate(word_idx);
} }
@ -1567,6 +1587,7 @@ static int show_stmt_release(ivl_statement_t net)
part_off = 0; part_off = 0;
if (part_off_ex != 0) { if (part_off_ex != 0) {
assert(number_is_immediate(part_off_ex, 64, 0)); assert(number_is_immediate(part_off_ex, 64, 0));
assert(! number_is_unknown(part_off_ex));
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
} }
@ -1581,6 +1602,7 @@ static int show_stmt_release(ivl_statement_t net)
if (word_idx != 0) { if (word_idx != 0) {
assert(number_is_immediate(word_idx, IMM_WID, 0)); assert(number_is_immediate(word_idx, IMM_WID, 0));
assert(! number_is_unknown(word_idx));
use_word = get_number_immediate(word_idx); use_word = get_number_immediate(word_idx);
} }

View File

@ -558,6 +558,9 @@ static void draw_delay(ivl_net_logic_t lptr)
assert(number_is_immediate(d0, 64, 0)); assert(number_is_immediate(d0, 64, 0));
assert(number_is_immediate(d1, 64, 0)); assert(number_is_immediate(d1, 64, 0));
assert(number_is_immediate(d2, 64, 0)); assert(number_is_immediate(d2, 64, 0));
assert(! number_is_unknown(d0));
assert(! number_is_unknown(d1));
assert(! number_is_unknown(d2));
if (d0 == d1 && d1 == d2) if (d0 == d1 && d1 == d2)
fprintf(vvp_out, " (%lu)", get_number_immediate(d0)); fprintf(vvp_out, " (%lu)", get_number_immediate(d0));
@ -615,6 +618,8 @@ static void draw_udp_in_scope(ivl_net_logic_t lptr)
static ivl_udp_t *udps = 0x0; static ivl_udp_t *udps = 0x0;
static int nudps = 0; static int nudps = 0;
int i; int i;
unsigned ninp;
const char **input_strings;
for (i=0; i<nudps; i++) for (i=0; i<nudps; i++)
if (udps[i] == udp) if (udps[i] == udp)
@ -628,26 +633,38 @@ static void draw_udp_in_scope(ivl_net_logic_t lptr)
draw_udp_def(udp); draw_udp_def(udp);
} }
fprintf(vvp_out, "L_%p .udp", lptr); /*
fprintf(vvp_out, " UDP_%s", * We need to process the arguments first so any evaluation code
vvp_mangle_id(ivl_udp_name(udp))); * (.resolv, etc.) can be built before we build the .udp call.
draw_delay(lptr); * This matches what is done for the other primitives.
*/
for (pdx = 1 ; pdx < ivl_logic_pins(lptr) ; pdx += 1) { ninp = ivl_logic_pins(lptr) - 1;
ivl_nexus_t nex = ivl_logic_pin(lptr, pdx); input_strings = calloc(ninp, sizeof(char*));
for (pdx = 0 ; pdx < ninp ; pdx += 1) {
ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1);
/* Unlike other logic gates, primitives may have unconnected /* Unlike other logic gates, primitives may have unconnected
inputs. The proper behavior is to attach a HiZ to the inputs. The proper behavior is to attach a HiZ to the
port. */ port. */
if (nex == 0) { if (nex == 0) {
assert(ivl_logic_width(lptr) == 1); assert(ivl_logic_width(lptr) == 1);
fprintf(vvp_out, ", C4<z>"); input_strings[pdx] = "C4<z>";
} else { } else {
fprintf(vvp_out, ", %s", draw_net_input(nex)); input_strings[pdx] = draw_net_input(nex);
} }
} }
fprintf(vvp_out, "L_%p .udp", lptr);
fprintf(vvp_out, " UDP_%s",
vvp_mangle_id(ivl_udp_name(udp)));
draw_delay(lptr);
for (pdx = 0 ; pdx < ninp ; pdx += 1) {
fprintf(vvp_out, ", %s", input_strings[pdx]);
}
free(input_strings);
fprintf(vvp_out, ";\n"); fprintf(vvp_out, ";\n");
} }
@ -665,25 +682,12 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
ivl_drive_t str0, str1; ivl_drive_t str0, str1;
int level; int level;
int ninp = ivl_logic_pins(lptr) - 1; int ninp;
typedef const char*const_charp; const char **input_strings;
const_charp*input_strings = calloc(ninp, sizeof(const_charp));
for (pdx = 0 ; pdx < ninp ; pdx += 1) {
ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1);
if (nex == 0) {
/* Only UDPs can have unconnected inputs. */
assert(ivl_logic_type(lptr) == IVL_LO_UDP);
input_strings[pdx] = 0;
} else {
input_strings[pdx] = draw_net_input(nex);
}
}
switch (ivl_logic_type(lptr)) { switch (ivl_logic_type(lptr)) {
case IVL_LO_UDP: case IVL_LO_UDP:
free(input_strings);
draw_udp_in_scope(lptr); draw_udp_in_scope(lptr);
return; return;
@ -706,7 +710,6 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
/* Skip pullup and pulldown objects. Things that have /* Skip pullup and pulldown objects. Things that have
pull objects as inputs will instead generate the pull objects as inputs will instead generate the
appropriate C<?> symbol. */ appropriate C<?> symbol. */
free(input_strings);
return; return;
case IVL_LO_AND: case IVL_LO_AND:
@ -819,7 +822,6 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
input_strings[pdx] = draw_net_input(ivl_logic_pin(lptr, pdx+1)); input_strings[pdx] = draw_net_input(ivl_logic_pin(lptr, pdx+1));
level = 0; level = 0;
ninp = ivl_logic_pins(lptr) - 1;
while (ninp) { while (ninp) {
int inst; int inst;
for (inst = 0; inst < ninp; inst += 4) { for (inst = 0; inst < ninp; inst += 4) {
@ -875,12 +877,18 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
&& number_is_immediate(fall_exp,64,0) && number_is_immediate(fall_exp,64,0)
&& number_is_immediate(decay_exp,64,0)) { && number_is_immediate(decay_exp,64,0)) {
assert(! number_is_unknown(rise_exp));
assert(! number_is_unknown(fall_exp));
assert(! number_is_unknown(decay_exp));
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n", fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
lptr, get_number_immediate(rise_exp), lptr, get_number_immediate(rise_exp),
get_number_immediate(rise_exp), get_number_immediate(fall_exp),
get_number_immediate(rise_exp), lptr); get_number_immediate(decay_exp), lptr);
} else { } else {
ivl_signal_t sig; ivl_signal_t sig;
// We do not currently support calculating the decay from
// the rise and fall variable delays.
assert(decay_exp != 0);
assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL); assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL);
assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL); assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
assert(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL); assert(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL);
@ -1077,11 +1085,14 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net)
assert(number_is_immediate(d_rise, 64, 0)); assert(number_is_immediate(d_rise, 64, 0));
assert(number_is_immediate(d_fall, 64, 0)); assert(number_is_immediate(d_fall, 64, 0));
assert(number_is_immediate(d_decay, 64, 0)); assert(number_is_immediate(d_decay, 64, 0));
assert(! number_is_unknown(d_rise));
assert(! number_is_unknown(d_fall));
assert(! number_is_unknown(d_decay));
dly = "/d"; dly = "/d";
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n", fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
net, get_number_immediate(d_rise), net, get_number_immediate(d_rise),
get_number_immediate(d_rise), get_number_immediate(d_fall),
get_number_immediate(d_rise), net); get_number_immediate(d_decay), net);
} }
return dly; return dly;
@ -1333,7 +1344,7 @@ static unsigned lpm_concat_inputs(ivl_lpm_t net, unsigned start,
static void draw_lpm_concat(ivl_lpm_t net) static void draw_lpm_concat(ivl_lpm_t net)
{ {
const char*src_table[4]; const char*src_table[4];
unsigned icnt = ivl_lpm_selects(net); unsigned icnt = ivl_lpm_size(net);
const char*dly = draw_lpm_output_delay(net); const char*dly = draw_lpm_output_delay(net);
if (icnt <= 4) { if (icnt <= 4) {
@ -1859,12 +1870,14 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
fprintf(vvp_out, ">;\n"); fprintf(vvp_out, ">;\n");
break; break;
case IVL_EX_REALNUM: case IVL_EX_REALNUM:
fprintf(vvp_out, "P_%p .param/real \"%s\" %d %d, %s; value=%#g\n", { char *res = draw_Cr_to_string(ivl_expr_dvalue(pex));
par, ivl_parameter_basename(par), fprintf(vvp_out, "P_%p .param/real \"%s\" %d %d, %s; "
ivl_file_table_index(ivl_parameter_file(par)), "value=%#g\n", par, ivl_parameter_basename(par),
ivl_parameter_lineno(par), ivl_file_table_index(ivl_parameter_file(par)),
draw_Cr_to_string(ivl_expr_dvalue(pex)), ivl_parameter_lineno(par), res,
ivl_expr_dvalue(pex)); ivl_expr_dvalue(pex));
free(res);
}
break; break;
default: default:
fprintf(vvp_out, "; parameter type %d unsupported\n", fprintf(vvp_out, "; parameter type %d unsupported\n",

View File

@ -11,7 +11,7 @@ License.
Verilog-A math library built for Icarus Verilog Verilog-A math library built for Icarus Verilog
http://www.icarus.com/eda/verilog/ http://www.icarus.com/eda/verilog/
Copyright (C) 2007-2008 Cary R. (cygcary@yahoo.com) Copyright (C) 2007-2009 Cary R. (cygcary@yahoo.com)
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -38,7 +38,7 @@ like all Verilog-D system functions the name must be prefixed with a '$'.
For reference the functions are: For reference the functions are:
$ln(x) -- Natural logarithm $ln(x) -- Natural logarithm
$log(x) -- Decimal logarithm $log10(x) -- Decimal logarithm // $log is being deprecated!
$exp(x) -- Exponential $exp(x) -- Exponential
$sqrt(x) -- Square root $sqrt(x) -- Square root
$min(x,y) -- Minimum $min(x,y) -- Minimum

View File

@ -10,11 +10,11 @@
# #
Summary: Icarus Verilog Summary: Icarus Verilog
Name: verilog%{suff} Name: verilog%{suff}
Version: 0.9.0.%{rev_date} Version: 0.9.1
Release: 0 Release: 0
License: GPL License: GPL
Group: Productivity/Scientific/Electronics Group: Productivity/Scientific/Electronics
Source: verilog%{suff}-%{rev_date}.tar.gz Source: verilog%{suff}-%{version}.tar.gz
URL: http://www.icarus.com/eda/verilog/index.html URL: http://www.icarus.com/eda/verilog/index.html
Packager: Stephen Williams <steve@icarus.com> Packager: Stephen Williams <steve@icarus.com>
@ -32,7 +32,7 @@ engineering formats, including simulation. It strives to be true
to the IEEE-1364 standard. to the IEEE-1364 standard.
%prep %prep
%setup -n verilog%{suff}-%{rev_date} %setup -n verilog%{suff}-%{version}
%build %build
if test X%{suff} != X if test X%{suff} != X

View File

@ -419,6 +419,7 @@ uint64_t verinum::as_ulong64() const
*/ */
signed long verinum::as_long() const signed long verinum::as_long() const
{ {
#define IVLLBITS (8 * sizeof(long) - 1)
if (nbits_ == 0) if (nbits_ == 0)
return 0; return 0;
@ -426,33 +427,43 @@ signed long verinum::as_long() const
return 0; return 0;
signed long val = 0; signed long val = 0;
unsigned diag_top = 0;
unsigned top = nbits_;
if (top > IVLLBITS) {
diag_top = top;
top = IVLLBITS;
}
int lost_bits=0;
if (has_sign_ && (bits_[nbits_-1] == V1)) { if (has_sign_ && (bits_[nbits_-1] == V1)) {
unsigned top = nbits_;
if (top > (8 * sizeof(long) - 1))
top = 8 * sizeof(long) - 1;
val = -1; val = -1;
signed long mask = ~1L; signed long mask = ~1L;
for (unsigned idx = 0 ; idx < top ; idx += 1) { for (unsigned idx = 0 ; idx < top ; idx += 1) {
if (bits_[idx] == V0) if (bits_[idx] == V0) val &= mask;
val &= mask;
mask = (mask << 1) | 1L; mask = (mask << 1) | 1L;
} }
if (diag_top) {
for (unsigned idx = top; idx < diag_top; idx += 1) {
if (bits_[idx] == V0) lost_bits=1;
}
}
} else { } else {
unsigned top = nbits_;
if (top > (8 * sizeof(long) - 1))
top = 8 * sizeof(long) - 1;
signed long mask = 1; signed long mask = 1;
for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1) for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1) {
if (bits_[idx] == V1) if (bits_[idx] == V1) val |= mask;
val |= mask; }
if (diag_top) {
for (unsigned idx = top; idx < diag_top; idx += 1) {
if (bits_[idx] == V1) lost_bits=1;
}
}
} }
if (lost_bits) cerr << "warning: verinum::as_long() truncated " <<
diag_top << " bits to " << IVLLBITS << ", returns " << val << endl;
return val; return val;
#undef IVLLBITS
} }
double verinum::as_double() const double verinum::as_double() const

View File

@ -174,6 +174,6 @@ verireal operator- (const verireal&l)
ostream& operator<< (ostream&out, const verireal&v) ostream& operator<< (ostream&out, const verireal&v)
{ {
out << v.value_; out << showpoint << v.value_;
return out; return out;
} }

View File

@ -3,5 +3,5 @@
* Edit this definition in version_base.in to define the base version * Edit this definition in version_base.in to define the base version
* number for the compiled result. * number for the compiled result.
*/ */
#define VERSION "0.9.devel" #define VERSION "0.9.1"
#endif #endif

View File

@ -23,6 +23,7 @@
# include "sys_priv.h" # include "sys_priv.h"
# include <assert.h> # include <assert.h>
# include <string.h> # include <string.h>
# include <errno.h>
# include <ctype.h> # include <ctype.h>
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
@ -263,7 +264,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
s_vpi_value value; s_vpi_value value;
char *result, *fmtb; char *result, *fmtb;
unsigned int size; unsigned int size;
unsigned int ini_size = 256; /* The initial size of the buffer. */ unsigned int ini_size = 512; /* The initial size of the buffer. */
/* Make sure the width fits in the initial buffer. */ /* Make sure the width fits in the initial buffer. */
if (width+1 > ini_size) ini_size = width + 1; if (width+1 > ini_size) ini_size = width + 1;
@ -328,7 +329,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
if (ld_zero == 1) { if (ld_zero == 1) {
/* Strip the leading zeros if a width is not given. */ /* Strip the leading zeros if a width is not given. */
if (width == -1) while (*cp == '0') cp++; if (width == -1) while (*cp == '0' && *(cp+1) != '\0') cp++;
/* Pad with leading zeros. */ /* Pad with leading zeros. */
else if (ljust == 0 && (signed)swidth < width) { else if (ljust == 0 && (signed)swidth < width) {
unsigned pad = (unsigned)width - swidth; unsigned pad = (unsigned)width - swidth;
@ -337,7 +338,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
strcpy(cp+pad, value.value.str); strcpy(cp+pad, value.value.str);
free_flag = 1; free_flag = 1;
/* For a left aligned value also strip the leading zeros. */ /* For a left aligned value also strip the leading zeros. */
} else if (ljust != 0) while (*cp == '0') cp++; } else if (ljust != 0) while (*cp == '0' && *(cp+1) != '\0') cp++;
} }
/* If a width was not given, use a width of zero. */ /* If a width was not given, use a width of zero. */
@ -488,12 +489,15 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
/* If the default buffer is too small make it big enough. /* If the default buffer is too small make it big enough.
* *
* This size may not always be correct, but if the default * This should always give enough space. The maximum double
* size is big enough for any practical value then all we * is approximately 1.8*10^308 this means we could need 310
* need to worry about is extra padding and this should work * characters plus the precision. We'll use 320 to give some
* correctly for that case, but since this uses the standard * extra buffer space. The initial buffers size should work
* sprintf() routine we don't know exactly what it will do. */ * for most cases, but to be safe we add the precision to
* the maximum size (think %6.300f when passed 1.2*10^308). */
size = width + 1; size = width + 1;
if (size < 320) size = 320;
size += prec;
if (size > ini_size) result = realloc(result, size*sizeof(char)); if (size > ini_size) result = realloc(result, size*sizeof(char));
sprintf(result, fmtb+1, value.value.real); sprintf(result, fmtb+1, value.value.real);
size = strlen(result) + 1; size = strlen(result) + 1;
@ -583,7 +587,8 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
type = vpi_get(vpiType, info->items[*idx]); type = vpi_get(vpiType, info->items[*idx]);
if (((type == vpiConstant || type == vpiParameter) && if (((type == vpiConstant || type == vpiParameter) &&
vpi_get(vpiConstType, info->items[*idx]) == vpiRealConst) || vpi_get(vpiConstType, info->items[*idx]) == vpiRealConst) ||
type == vpiRealVar ) { type == vpiRealVar || (type == vpiSysFuncCall &&
vpi_get(vpiFuncType, info->items[*idx]) == vpiRealFunc)) {
value.format = vpiRealVal; value.format = vpiRealVal;
} else { } else {
value.format = vpiDecStrVal; value.format = vpiDecStrVal;
@ -1116,18 +1121,26 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8 *name)
/* Get the file/MC descriptor and verify it is valid. */ /* Get the file/MC descriptor and verify it is valid. */
if(name[1] == 'f') { if(name[1] == 'f') {
errno = 0;
vpiHandle arg = vpi_scan(argv); vpiHandle arg = vpi_scan(argv);
s_vpi_value val; s_vpi_value val;
val.format = vpiIntVal; val.format = vpiIntVal;
vpi_get_value(arg, &val); vpi_get_value(arg, &val);
fd_mcd = val.value.integer; fd_mcd = val.value.integer;
/* If the MCD is zero we have nothing to do so just return. */
if (fd_mcd == 0) {
vpi_free_object(argv);
return 0;
}
if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) ||
( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF)) { ( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor/MCD (0x%x) given " vpi_printf("invalid file descriptor/MCD (0x%x) given "
"to %s.\n", fd_mcd, name); "to %s.\n", fd_mcd, name);
vpi_control(vpiFinish, 1); errno = EBADF;
vpi_free_object(argv); vpi_free_object(argv);
return 0; return 0;
} }
@ -1176,23 +1189,29 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8 *name)
*/ */
static PLI_INT32 strobe_cb(p_cb_data cb) static PLI_INT32 strobe_cb(p_cb_data cb)
{ {
char* result; char* result = NULL;
unsigned int size, location=0; unsigned int size, location=0;
struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data; struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data;
/* Because %u and %z may put embedded NULL characters into the /* We really need to cancel any $fstrobe() calls for a file when it
* returned string strlen() may not match the real size! */ * is closed, but for now we will just skip processing the result.
result = get_display(&size, info); * Which has the same basic effect. */
while (location < size) { if ((! IS_MCD(info->fd_mcd) && vpi_get_file(info->fd_mcd) != NULL) ||
if (result[location] == '\0') { ( IS_MCD(info->fd_mcd) && my_mcd_printf(info->fd_mcd, "") != EOF)) {
my_mcd_printf(info->fd_mcd, "%c", '\0'); /* Because %u and %z may put embedded NULL characters into the
location += 1; * returned string strlen() may not match the real size! */
} else { result = get_display(&size, info);
my_mcd_printf(info->fd_mcd, "%s", &result[location]); while (location < size) {
location += strlen(&result[location]); if (result[location] == '\0') {
my_mcd_printf(info->fd_mcd, "%c", '\0');
location += 1;
} else {
my_mcd_printf(info->fd_mcd, "%s", &result[location]);
location += strlen(&result[location]);
}
} }
my_mcd_printf(info->fd_mcd, "\n");
} }
my_mcd_printf(info->fd_mcd, "\n");
free(info->filename); free(info->filename);
free(info->items); free(info->items);
@ -1222,18 +1241,26 @@ static PLI_INT32 sys_strobe_calltf(PLI_BYTE8*name)
/* Get the file/MC descriptor and verify it is valid. */ /* Get the file/MC descriptor and verify it is valid. */
if(name[1] == 'f') { if(name[1] == 'f') {
errno = 0;
vpiHandle arg = vpi_scan(argv); vpiHandle arg = vpi_scan(argv);
s_vpi_value val; s_vpi_value val;
val.format = vpiIntVal; val.format = vpiIntVal;
vpi_get_value(arg, &val); vpi_get_value(arg, &val);
fd_mcd = val.value.integer; fd_mcd = val.value.integer;
/* If the MCD is zero we have nothing to do so just return. */
if (fd_mcd == 0) {
vpi_free_object(argv);
return 0;
}
if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) ||
( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF)) { ( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor/MCD (0x%x) given " vpi_printf("invalid file descriptor/MCD (0x%x) given "
"to %s.\n", fd_mcd, name); "to %s.\n", fd_mcd, name);
vpi_control(vpiFinish, 1); errno = EBADF;
vpi_free_object(argv); vpi_free_object(argv);
return 0; return 0;
} }

View File

@ -21,13 +21,13 @@
# include "sys_priv.h" # include "sys_priv.h"
# include <assert.h> # include <assert.h>
# include <ctype.h> # include <ctype.h>
# include <errno.h>
# include <string.h> # include <string.h>
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
#define IS_MCD(mcd) !((mcd)>>31&1) #define IS_MCD(mcd) !((mcd)>>31&1)
/* /*
* Implement the $fopen system function. * Implement the $fopen system function.
*/ */
@ -83,6 +83,8 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name)
vpiHandle fileh = vpi_scan(argv); vpiHandle fileh = vpi_scan(argv);
char *fname; char *fname;
vpiHandle mode = vpi_scan(argv); vpiHandle mode = vpi_scan(argv);
errno = 0;
/* Get the mode handle if it exists. */ /* Get the mode handle if it exists. */
if (mode) { if (mode) {
char *esc_md; char *esc_md;
@ -151,10 +153,13 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name)
} }
fname = get_filename(callh, name, fileh); fname = get_filename(callh, name, fileh);
if (fname == 0 && mode) free(mode_string);
/* If either the mode or file name are not valid just return. */ /* If either the mode or file name are not valid just return. */
if (fail || fname == 0) return 0; if (fail || fname == 0) {
free(fname);
if (mode) free(mode_string);
return 0;
}
val.format = vpiIntVal; val.format = vpiIntVal;
if (mode) { if (mode) {
@ -164,6 +169,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name)
val.value.integer = vpi_mcd_open(fname); val.value.integer = vpi_mcd_open(fname);
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
free(fname);
return 0; return 0;
} }
@ -179,7 +185,7 @@ static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name)
vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle argv = vpi_iterate(vpiArgument, callh);
s_vpi_value val; s_vpi_value val;
char *mode, *fname; char *mode, *fname;
errno = 0;
/* Get the mode. */ /* Get the mode. */
mode = name + strlen(name) - 1; mode = name + strlen(name) - 1;
@ -208,7 +214,7 @@ static PLI_INT32 sys_fclose_calltf(PLI_BYTE8*name)
vpiHandle fd = vpi_scan(argv); vpiHandle fd = vpi_scan(argv);
s_vpi_value val; s_vpi_value val;
PLI_UINT32 fd_mcd; PLI_UINT32 fd_mcd;
char *str = ""; /* This prevents the compiler from complaining. */ errno = 0;
vpi_free_object(argv); vpi_free_object(argv);
@ -218,15 +224,19 @@ static PLI_INT32 sys_fclose_calltf(PLI_BYTE8*name)
fd_mcd = val.value.integer; fd_mcd = val.value.integer;
if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) ||
( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF)) { ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, "%s", "") == EOF) ||
(! fd_mcd)) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor/MCD (0x%x) given to %s.\n", vpi_printf("invalid file descriptor/MCD (0x%x) given to %s.\n",
fd_mcd, name); fd_mcd, name);
errno = EBADF;
return 0; return 0;
} }
/* We need to cancel any active $fstrobe()'s for this FD/MCD. */ /* We need to cancel any active $fstrobe()'s for this FD/MCD.
* For now we check in the strobe callback and skip the output
* generation when needed. */
vpi_mcd_close(fd_mcd); vpi_mcd_close(fd_mcd);
return 0; return 0;
@ -243,7 +253,7 @@ static PLI_INT32 sys_fflush_calltf(PLI_BYTE8*name)
s_vpi_value val; s_vpi_value val;
PLI_UINT32 fd_mcd; PLI_UINT32 fd_mcd;
FILE *fp; FILE *fp;
char *str = ""; /* This prevents the compiler from complaining. */ errno = 0;
/* If we have no argument then flush all the streams. */ /* If we have no argument then flush all the streams. */
if (argv == 0) { if (argv == 0) {
@ -258,12 +268,17 @@ static PLI_INT32 sys_fflush_calltf(PLI_BYTE8*name)
vpi_get_value(arg, &val); vpi_get_value(arg, &val);
fd_mcd = val.value.integer; fd_mcd = val.value.integer;
/* If the MCD is zero we have nothing to do so just return. */
if (fd_mcd == 0) return 0;
if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) ||
( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF)) { ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, "%s", "") == EOF) ||
(! fd_mcd)) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor/MCD (0x%x) given to %s.\n", vpi_printf("invalid file descriptor/MCD (0x%x) given to %s.\n",
fd_mcd, name); fd_mcd, name);
errno = EBADF;
return 0; return 0;
} }
@ -287,7 +302,7 @@ static PLI_INT32 sys_fputc_calltf(PLI_BYTE8*name)
PLI_UINT32 fd_mcd; PLI_UINT32 fd_mcd;
FILE *fp; FILE *fp;
unsigned char chr; unsigned char chr;
(void) name; /* Not used! */ errno = 0;
/* Get the character. */ /* Get the character. */
arg = vpi_scan(argv); arg = vpi_scan(argv);
@ -311,9 +326,12 @@ static PLI_INT32 sys_fputc_calltf(PLI_BYTE8*name)
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
name); name);
errno = EBADF;
val.value.integer = EOF; val.value.integer = EOF;
} else } else {
val.value.integer = fputc(chr, fp); val.value.integer = fputc(chr, fp);
if (val.value.integer != EOF) val.value.integer = 0;
}
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
return 0; return 0;
@ -377,7 +395,7 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name)
FILE *fp; FILE *fp;
PLI_INT32 reg_size; PLI_INT32 reg_size;
char*text; char*text;
(void) name; /* Not used! */ errno = 0;
/* Get the register handle. */ /* Get the register handle. */
regh = vpi_scan(argv); regh = vpi_scan(argv);
@ -396,6 +414,7 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name)
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
name); name);
errno = EBADF;
val.format = vpiIntVal; val.format = vpiIntVal;
val.value.integer = 0; val.value.integer = 0;
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
@ -429,6 +448,263 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name)
return 0; return 0;
} }
static PLI_INT32 sys_fread_compiletf(PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
PLI_INT32 type;
/* We must have at least two arguments. */
if (argv == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires two arguments.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
/* Check that the first required argument is a register or memory. */
type = vpi_get(vpiType, vpi_scan(argv));
if (type != vpiReg && type != vpiMemory) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's first argument must be a reg or memory.\n", name);
vpi_control(vpiFinish, 1);
}
/* Check that the second required argument is numeric (a fd). */
arg = vpi_scan(argv);
if (! arg) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a second (file descriptor) argument.\n",
name);
vpi_control(vpiFinish, 1);
return 0;
}
if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/*
* If given check that the third argument is numeric (start).
*
* Technically you can give the fourth argument (count) with
* out a third argument (start), but Icarus does not currently
* support missing function arguments!
*/
arg = vpi_scan(argv);
if (arg) {
if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's third argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/* If given check that the fourth argument is numeric (count). */
arg = vpi_scan(argv);
if (arg) {
if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s:%d: ",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's fourth argument must be numeric.\n",
name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
check_for_extra_args(argv, callh, name, "four arguments", 1);
}
}
return 0;
}
/*
* The pattern here is get the current vector, load the new bits on
* top of the old ones and then put the modified vector. We need the
* "get" first so that if we run out of bits in the file we keep the
* original ones.
*/
static unsigned fread_word(FILE *fp, vpiHandle word,
unsigned words, unsigned bpe, s_vpi_vecval *vector)
{
unsigned rtn, clr_mask, bnum;
int bidx, byte;
s_vpi_value val;
struct t_vpi_vecval *cur = &vector[words-1];
rtn = 0;
/* Get the current bits from the register and copy them to
* my local vector. */
val.format = vpiVectorVal;
vpi_get_value(word, &val);
for (bidx = 0; bidx < words; bidx += 1) {
vector[bidx].aval = val.value.vector[bidx].aval;
vector[bidx].bval = val.value.vector[bidx].bval;
}
/* Copy the bytes to the local vector MSByte first. */
for (bidx = bpe-1; bidx >= 0; bidx -= 1) {
byte = fgetc(fp);
if (byte == EOF) break;
/* Clear the current byte and load the new value. */
bnum = bidx % 4;
clr_mask = ~(0xff << bnum*8);
cur->aval &= clr_mask;
cur->bval &= clr_mask;
cur->aval |= byte << bnum*8;
rtn += 1;
if (bnum == 0) cur -= 1;
}
/* Put the updated bits into the register. */
val.value.vector = vector;
vpi_put_value(word, &val, 0, vpiNoDelay);
return rtn;
}
static PLI_INT32 sys_fread_calltf(PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg, mem_reg;
s_vpi_value val;
PLI_UINT32 fd_mcd;
PLI_INT32 start, count, width, rtn;
unsigned is_mem, idx, bpe, words;
FILE *fp;
s_vpi_vecval *vector;
errno = 0;
/* Get the register/memory. */
mem_reg = vpi_scan(argv);
/* Get the file descriptor. */
arg = vpi_scan(argv);
val.format = vpiIntVal;
vpi_get_value(arg, &val);
fd_mcd = val.value.integer;
/* Return 0 if this is not a valid fd. */
fp = vpi_get_file(fd_mcd);
if (!fp) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
name);
errno = EBADF;
val.format = vpiIntVal;
val.value.integer = 0;
vpi_put_value(callh, &val, 0, vpiNoDelay);
vpi_free_object(argv);
return 0;
}
/* Are we reading into a memory? */
if (vpi_get(vpiType, mem_reg) == vpiReg) is_mem = 0;
else is_mem = 1;
/* We only need to get these for memories. */
if (is_mem) {
PLI_INT32 left, right, max, min;
/* Get the left and right memory address. */
val.format = vpiIntVal;
vpi_get_value(vpi_handle(vpiLeftRange, mem_reg), &val);
left = val.value.integer;
val.format = vpiIntVal;
vpi_get_value(vpi_handle(vpiRightRange, mem_reg), &val);
right = val.value.integer;
max = (left > right) ? left : right;
min = (left < right) ? left : right;
/* Get the starting address (optional). */
arg = vpi_scan(argv);
if (arg) {
val.format = vpiIntVal;
vpi_get_value(arg, &val);
start = val.value.integer;
if (start < min || start > max) {
vpi_printf("WARNING: %s:%d: ",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's start argument (%d) is outside "
"memory range [%d:%d].\n", name, start,
left, right);
val.format = vpiIntVal;
val.value.integer = 0;
vpi_put_value(callh, &val, 0, vpiNoDelay);
vpi_free_object(argv);
return 0;
}
/* Get the count (optional). */
arg = vpi_scan(argv);
if (arg) {
val.format = vpiIntVal;
vpi_get_value(arg, &val);
count = val.value.integer;
if (count > max-start) {
vpi_printf("WARNING: %s:%d: ",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's count argument (%d) is too "
"large for start (%d) and memory "
"range [%d:%d].\n", name, count,
start, left, right);
count = max - start + 1;
}
vpi_free_object(argv);
} else {
count = max - start + 1;
}
} else {
start = min;
count = max - min + 1;
}
width = vpi_get(vpiSize, vpi_handle_by_index(mem_reg, start));
} else {
start = 0;
count = 1;
width = vpi_get(vpiSize, mem_reg);
vpi_free_object(argv);
}
words = (width+31)/32;
vector = calloc(words, sizeof(s_vpi_vecval));
bpe = (width+7)/8;
if (is_mem) {
rtn = 0;
for (idx = 0; idx < count; idx += 1) {
vpiHandle word;
word = vpi_handle_by_index(mem_reg, start+(signed)idx);
rtn += fread_word(fp, word, words, bpe, vector);
if (feof(fp)) break;
}
} else {
rtn = fread_word(fp, mem_reg, words, bpe, vector);
}
free(vector);
/* Return the number of bytes read. */
val.format = vpiIntVal;
val.value.integer = rtn;
vpi_put_value(callh, &val, 0, vpiNoDelay);
return 0;
}
static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name) static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
{ {
vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
@ -437,8 +713,8 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
s_vpi_value val; s_vpi_value val;
PLI_UINT32 fd_mcd; PLI_UINT32 fd_mcd;
FILE *fp; FILE *fp;
unsigned char chr; int chr;
(void) name; /* Not used! */ errno = 0;
/* Get the character. */ /* Get the character. */
arg = vpi_scan(argv); arg = vpi_scan(argv);
@ -460,6 +736,7 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
name); name);
errno = EBADF;
val.format = vpiIntVal; val.format = vpiIntVal;
val.value.integer = EOF; val.value.integer = EOF;
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
@ -469,6 +746,7 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
/* ungetc the character and return the result. */ /* ungetc the character and return the result. */
val.format = vpiIntVal; val.format = vpiIntVal;
val.value.integer = ungetc(chr, fp); val.value.integer = ungetc(chr, fp);
if (val.value.integer != EOF) val.value.integer = 0;
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
return 0; return 0;
@ -507,7 +785,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name)
return 0; return 0;
} }
if (!arg || !is_numeric_obj(arg)) { if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must be numeric.\n", name); vpi_printf("%s's second argument must be numeric.\n", name);
@ -524,7 +802,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name)
return 0; return 0;
} }
if (!arg || !is_numeric_obj(arg)) { if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's third argument must be numeric.\n", name); vpi_printf("%s's third argument must be numeric.\n", name);
@ -546,7 +824,7 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name)
PLI_UINT32 fd_mcd; PLI_UINT32 fd_mcd;
PLI_INT32 offset, oper; PLI_INT32 offset, oper;
FILE *fp; FILE *fp;
errno = 0;
/* Get the file pointer. */ /* Get the file pointer. */
arg = vpi_scan(argv); arg = vpi_scan(argv);
@ -568,15 +846,22 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name)
oper = val.value.integer; oper = val.value.integer;
/* Check that the operation is in the valid range. */ /* Check that the operation is in the valid range. */
if ((oper < 0) || (oper > 2)) { switch (oper) {
case 0:
oper = SEEK_SET;
break;
case 1:
oper = SEEK_CUR;
break;
case 2:
oper = SEEK_END;
break;
default:
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's operation must be 0, 1 or 2 given %d.\n", vpi_printf("%s's operation must be 0, 1 or 2 given %d.\n",
name, oper); name, oper);
val.format = vpiIntVal; oper = -1; /* An invalid argument value. */
val.value.integer = EOF;
vpi_put_value(callh, &val, 0, vpiNoDelay);
return 0;
} }
/* Return EOF if this is not a valid fd. */ /* Return EOF if this is not a valid fd. */
@ -586,6 +871,7 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name)
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
name); name);
errno = EBADF;
val.format = vpiIntVal; val.format = vpiIntVal;
val.value.integer = EOF; val.value.integer = EOF;
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
@ -607,6 +893,7 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name)
s_vpi_value val; s_vpi_value val;
PLI_UINT32 fd_mcd; PLI_UINT32 fd_mcd;
FILE *fp; FILE *fp;
errno = 0;
/* Get the file pointer. */ /* Get the file pointer. */
arg = vpi_scan(argv); arg = vpi_scan(argv);
@ -622,6 +909,7 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name)
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
name); name);
errno = EBADF;
val.format = vpiIntVal; val.format = vpiIntVal;
val.value.integer = EOF; val.value.integer = EOF;
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
@ -654,6 +942,119 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name)
return 0; return 0;
} }
/*
* Implement the $ferror system function.
*/
static PLI_INT32 sys_ferror_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv;
vpiHandle arg;
argv = vpi_iterate(vpiArgument, callh);
/*
* Check that there are two arguments and that the first is
* numeric and that the second is a 640 bit or larger register.
*
* The parser requires that a function have at least one argument,
* so argv should always be defined with one argument.
*/
assert(argv);
if (! is_numeric_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's fd (first) argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/* Check that the second argument is given and that it is a 640 bit
* or larger register. */
arg = vpi_scan(argv);
if (! arg) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a second (register) argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (vpi_get(vpiType, arg) != vpiReg) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must be a reg (>=640 bits).\n",
name);
vpi_control(vpiFinish, 1);
} else if (vpi_get(vpiSize, arg) < 640) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must have 640 bit or more.\n",
name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
check_for_extra_args(argv, callh, name, "two arguments", 0);
return 0;
}
static PLI_INT32 sys_ferror_calltf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle reg;
s_vpi_value val;
char *msg;
PLI_INT32 size;
unsigned chars;
PLI_UINT32 fd_mcd;
/* Get the file pointer. */
val.format = vpiIntVal;
vpi_get_value(vpi_scan(argv), &val);
fd_mcd = val.value.integer;
/* Get the register to put the string result and figure out how many
* characters it will hold. */
reg = vpi_scan(argv);
size = vpi_get(vpiSize, reg);
chars = size / 8;
vpi_free_object(argv);
/* If we do not already have an error check that the fd is valid.
* The assumption is that the other routines have set errno to
* EBADF when they encounter a bad file descriptor, so we do not
* need to check here. We also need to special case this since
* $fopen() will return 0 (a bad file descriptor) when it has a
* problem (sets errno). */
if (!errno && !vpi_get_file(fd_mcd) ) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
name);
errno = EBADF;
}
/* Return the error code. */
val.format = vpiIntVal;
val.value.integer = errno;
vpi_put_value(callh, &val, 0, vpiNoDelay);
/* Only return the number of characters that will fit in the reg. */
msg = (char *) malloc(chars);
if (errno != 0) strncpy(msg, strerror(errno), chars-1);
else strncpy(msg, "", chars-1);
msg[chars-1] = '\0';
val.format = vpiStringVal;
val.value.str = msg;
vpi_put_value(reg, &val, 0, vpiNoDelay);
free(msg);
return 0;
}
void sys_fileio_register() void sys_fileio_register()
{ {
s_vpi_systf_data tf_data; s_vpi_systf_data tf_data;
@ -706,15 +1107,6 @@ void sys_fileio_register()
tf_data.user_data = "$fflush"; tf_data.user_data = "$fflush";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
/*============================== fputc */
tf_data.type = vpiSysTask;
tf_data.tfname = "$fputc";
tf_data.calltf = sys_fputc_calltf;
tf_data.compiletf = sys_two_numeric_args_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$fputc";
vpi_register_systf(&tf_data);
/*============================== fgetc */ /*============================== fgetc */
tf_data.type = vpiSysFunc; tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc; tf_data.sysfunctype = vpiIntFunc;
@ -735,6 +1127,16 @@ void sys_fileio_register()
tf_data.user_data = "$fgets"; tf_data.user_data = "$fgets";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
/*============================== fread */
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc;
tf_data.tfname = "$fread";
tf_data.calltf = sys_fread_calltf;
tf_data.compiletf = sys_fread_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$fread";
vpi_register_systf(&tf_data);
/*============================== ungetc */ /*============================== ungetc */
tf_data.type = vpiSysFunc; tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc; tf_data.sysfunctype = vpiIntFunc;
@ -775,7 +1177,17 @@ void sys_fileio_register()
tf_data.user_data = "$rewind"; tf_data.user_data = "$rewind";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
/* $feof() is from 1364-2005. */ /*============================== ferror */
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc;
tf_data.tfname = "$ferror";
tf_data.calltf = sys_ferror_calltf;
tf_data.compiletf = sys_ferror_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$ferror";
vpi_register_systf(&tf_data);
/* $feof() is from 1364-2005. */
/*============================== feof */ /*============================== feof */
tf_data.type = vpiSysFunc; tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc; tf_data.sysfunctype = vpiIntFunc;
@ -786,4 +1198,14 @@ void sys_fileio_register()
tf_data.user_data = "$feof"; tf_data.user_data = "$feof";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
/* Icarus specific. */
/*============================== fputc */
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc;
tf_data.tfname = "$fputc";
tf_data.calltf = sys_fputc_calltf;
tf_data.compiletf = sys_two_numeric_args_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$fputc";
vpi_register_systf(&tf_data);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2008 Cary R. (cygcary@yahoo.com) * Copyright (C) 2008-2009 Cary R. (cygcary@yahoo.com)
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -53,11 +53,15 @@ static PLI_INT32 task_not_implemented_compiletf(PLI_BYTE8* name)
return 0; return 0;
} }
static PLI_INT32 function_not_implemented_compiletf(PLI_BYTE8* name) /*
* This is used to warn the user that the specified optional system
* task/function is not available (from Annex C 1364-2005).
*/
static PLI_INT32 missing_optional_compiletf(PLI_BYTE8* name)
{ {
vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpi_printf("%s:%d: SORRY: function %s() is not currently implemented.\n", vpi_printf("%s:%d: SORRY: %s() is not available in Icarus verilog.\n",
vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh), vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh),
name); name);
vpi_control(vpiFinish, 1); vpi_control(vpiFinish, 1);
@ -185,16 +189,106 @@ void sys_special_register(void)
tf_data.user_data = "$q_exam"; tf_data.user_data = "$q_exam";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
/* These functions are not currently implemented. */ tf_data.tfname = "$dumpports";
tf_data.compiletf = function_not_implemented_compiletf; tf_data.user_data = "$dumpports";
vpi_register_systf(&tf_data);
tf_data.tfname = "$dumpportsoff";
tf_data.user_data = "$dumpportsoff";
vpi_register_systf(&tf_data);
tf_data.tfname = "$dumpportson";
tf_data.user_data = "$dumpportson";
vpi_register_systf(&tf_data);
tf_data.tfname = "$dumpportsall";
tf_data.user_data = "$dumpportsall";
vpi_register_systf(&tf_data);
tf_data.tfname = "$dumpportslimit";
tf_data.user_data = "$dumpportslimit";
vpi_register_systf(&tf_data);
tf_data.tfname = "$dumpportsflush";
tf_data.user_data = "$dumpportsflush";
vpi_register_systf(&tf_data);
/* The following optional system tasks/functions are not implemented
* in Icarus Verilog (from Annex C 1364-2005). */
tf_data.type = vpiSysTask;
tf_data.calltf = 0;
tf_data.sizetf = 0;
tf_data.compiletf = missing_optional_compiletf;
tf_data.tfname = "$input";
tf_data.user_data = "$input";
vpi_register_systf(&tf_data);
tf_data.tfname = "$key";
tf_data.user_data = "$key";
vpi_register_systf(&tf_data);
tf_data.tfname = "$nokey";
tf_data.user_data = "$nokey";
vpi_register_systf(&tf_data);
tf_data.tfname = "$list";
tf_data.user_data = "$list";
vpi_register_systf(&tf_data);
tf_data.tfname = "$log";
tf_data.user_data = "$log";
vpi_register_systf(&tf_data);
tf_data.tfname = "$nolog";
tf_data.user_data = "$nolog";
vpi_register_systf(&tf_data);
tf_data.tfname = "$save";
tf_data.user_data = "$save";
vpi_register_systf(&tf_data);
tf_data.tfname = "$restart";
tf_data.user_data = "$restart";
vpi_register_systf(&tf_data);
tf_data.tfname = "$incsave";
tf_data.user_data = "$incsave";
vpi_register_systf(&tf_data);
tf_data.tfname = "$scope";
tf_data.user_data = "$scope";
vpi_register_systf(&tf_data);
tf_data.tfname = "$showscopes";
tf_data.user_data = "$showscopes";
vpi_register_systf(&tf_data);
tf_data.tfname = "$showvars";
tf_data.user_data = "$showvars";
vpi_register_systf(&tf_data);
tf_data.tfname = "$sreadmemb";
tf_data.user_data = "$sreadmemb";
vpi_register_systf(&tf_data);
tf_data.tfname = "$sreadmemh";
tf_data.user_data = "$sreadmemh";
vpi_register_systf(&tf_data);
/* Optional functions. */
tf_data.type = vpiSysFunc; tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc; tf_data.sysfunctype = vpiIntFunc;
tf_data.tfname = "$ferror"; tf_data.tfname = "$countdrivers";
tf_data.user_data = "$ferror"; tf_data.user_data = "$countdrivers";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
tf_data.tfname = "$fread"; tf_data.tfname = "$getpattern";
tf_data.user_data = "$fread"; tf_data.user_data = "$getpattern";
vpi_register_systf(&tf_data);
tf_data.tfname = "$scale";
tf_data.user_data = "$scale";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
} }

View File

@ -17,10 +17,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
# include "sys_priv.h"
# include "lxt_write.h" # include "lxt_write.h"
# include "vcd_priv.h"
# include "sys_priv.h" # include "sys_priv.h"
# include "vcd_priv.h"
/* /*
* This file contains the implementations of the LXT related * This file contains the implementations of the LXT related
@ -39,6 +38,29 @@
# include "stringheap.h" # include "stringheap.h"
static char *dump_path = NULL;
static struct lt_trace *dump_file = NULL;
struct vcd_info {
vpiHandle item;
vpiHandle cb;
struct t_vpi_time time;
struct lt_symbol *sym;
struct vcd_info *next;
struct vcd_info *dmp_next;
int scheduled;
};
static struct vcd_info *vcd_list = NULL;
static struct vcd_info *vcd_dmp_list = NULL;
static PLI_UINT64 vcd_cur_time = 0;
static int dump_is_off = 0;
static long dump_limit = 0;
static int dump_is_full = 0;
static int finish_status = 0;
static enum lxm_optimum_mode_e { static enum lxm_optimum_mode_e {
LXM_NONE = 0, LXM_NONE = 0,
LXM_SPACE = 1, LXM_SPACE = 1,
@ -140,30 +162,6 @@ static char *create_full_name(const char *name)
return n; return n;
} }
static char *dump_path = 0;
static struct lt_trace *dump_file = 0;
struct vcd_info {
vpiHandle item;
vpiHandle cb;
struct t_vpi_time time;
struct lt_symbol *sym;
struct vcd_info *next;
struct vcd_info *dmp_next;
int scheduled;
};
static struct vcd_info*vcd_list = 0;
static struct vcd_info*vcd_dmp_list = 0;
static PLI_UINT64 vcd_cur_time = 0;
static int dump_is_off = 0;
static long dump_limit = 0;
static int dump_is_full = 0;
static int finish_status = 0;
static void show_this_item(struct vcd_info*info) static void show_this_item(struct vcd_info*info)
{ {
s_vpi_value value; s_vpi_value value;
@ -297,6 +295,8 @@ static PLI_INT32 dumpvars_cb(p_cb_data cause)
static PLI_INT32 finish_cb(p_cb_data cause) static PLI_INT32 finish_cb(p_cb_data cause)
{ {
struct vcd_info *cur, *next;
if (finish_status != 0) return 0; if (finish_status != 0) return 0;
finish_status = 1; finish_status = 1;
@ -306,6 +306,17 @@ static PLI_INT32 finish_cb(p_cb_data cause)
lt_set_time64(dump_file, dumpvars_time); lt_set_time64(dump_file, dumpvars_time);
} }
for (cur = vcd_list ; cur ; cur = next) {
next = cur->next;
free(cur);
}
vcd_list = 0;
vcd_names_delete(&lxt_tab);
nexus_ident_delete();
free(dump_path);
dump_path = 0;
return 0; return 0;
} }
@ -421,7 +432,8 @@ static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name)
static void *close_dumpfile(void) static void *close_dumpfile(void)
{ {
lt_close(dump_file); lt_close(dump_file);
return (dump_file = NULL); dump_file = NULL;
return NULL;
} }
static void open_dumpfile(vpiHandle callh) static void open_dumpfile(vpiHandle callh)
@ -538,11 +550,27 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
switch (vpi_get(vpiType, item)) { switch (vpi_get(vpiType, item)) {
case vpiNet: type = "wire"; if(0){ case vpiNet: type = "wire"; if(0){
case vpiIntegerVar:
case vpiMemoryWord: case vpiMemoryWord:
if (vpi_get(vpiConstantSelect, item) == 0) {
/* Turn a non-constant array word select into a
* constant word select. */
vpiHandle array = vpi_handle(vpiParent, item);
PLI_INT32 index = vpi_get(vpiIndex, item);
item = vpi_handle_by_index(array, index);
}
case vpiIntegerVar:
case vpiTimeVar: case vpiTimeVar:
case vpiReg: type = "reg"; } case vpiReg: type = "reg"; }
/* An array word is implicitly escaped so look for an
* escaped identifier that this could conflict with. */
if (vpi_get(vpiType, item) == vpiMemoryWord &&
vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) {
vpi_printf("LXT warning: dumping array word %s will "
"conflict with an escaped identifier.\n",
vpi_get_str(vpiFullName, item));
}
if (skip || vpi_get(vpiAutomatic, item)) break; if (skip || vpi_get(vpiAutomatic, item)) break;
name = vpi_get_str(vpiName, item); name = vpi_get_str(vpiName, item);
@ -563,12 +591,12 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
info = malloc(sizeof(*info)); info = malloc(sizeof(*info));
info->time.type = vpiSimTime; info->time.type = vpiSimTime;
info->item = item; info->item = item;
info->sym = lt_symbol_add(dump_file, ident, info->sym = lt_symbol_add(dump_file, ident,
0 /* array rows */, 0 /* array rows */,
vpi_get(vpiLeftRange, item), vpi_get(vpiLeftRange, item),
vpi_get(vpiRightRange, item), vpi_get(vpiRightRange, item),
LT_SYM_F_BITS); LT_SYM_F_BITS);
info->scheduled = 0; info->scheduled = 0;
cb.time = &info->time; cb.time = &info->time;

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