Merge branch 'master' into work4
Conflicts: vhdlpp/lexor.lex vhdlpp/parse.y vhdlpp/vhdlint.cc
This commit is contained in:
commit
9330b58a3a
6
BUGS.txt
6
BUGS.txt
|
|
@ -54,7 +54,7 @@ So, if your program doesn't compile, tell me so, tell me where the
|
|||
error occurs, and include a complete Perfectly Valid Test Program(tm).
|
||||
You tell me that it fails to compile for you, and I find that it
|
||||
compiles for me, then hooray I fixed it. It can happen, you
|
||||
know. What's on my disk is more recent then the latest snapshot.
|
||||
know. What's on my disk is more recent than the latest snapshot.
|
||||
|
||||
If your program does compile, but generates incorrect output, I need
|
||||
to know what it says and what you think it should say. From this I can
|
||||
|
|
@ -82,9 +82,9 @@ clarification.
|
|||
|
||||
If the output is strictly correct, but just not good enough for
|
||||
practical use, I would like to know. These sorts of problems are
|
||||
likely to be more subjective then a core dump, but are worthy of
|
||||
likely to be more subjective than a core dump, but are worthy of
|
||||
consideration. However, realize that outright errors will get more
|
||||
attention then missed optimizations.
|
||||
attention than missed optimizations.
|
||||
|
||||
THE MAKING OF A GOOD TEST PROGRAM
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,502 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
|
@ -106,7 +106,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
|
|||
netenum.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \
|
||||
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
|
||||
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
|
||||
pform_disciplines.o pform_dump.o pform_types.o set_width.o \
|
||||
pform_disciplines.o pform_dump.o pform_types.o \
|
||||
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \
|
||||
Attrib.o HName.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \
|
||||
PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \
|
||||
|
|
|
|||
2
Module.h
2
Module.h
|
|
@ -79,7 +79,7 @@ class Module : public PScope, public LineInfo {
|
|||
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
|
||||
UCDriveType uc_drive;
|
||||
|
||||
/* specparams are simpler then other params, in that they have
|
||||
/* specparams are simpler than other params, in that they have
|
||||
no type information. They are merely constant
|
||||
expressions. */
|
||||
map<perm_string,PExpr*>specparams;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -78,11 +78,7 @@ unsigned PDelays::delay_count() const
|
|||
|
||||
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);
|
||||
eval_expr(dex);
|
||||
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. */
|
||||
|
|
|
|||
30
PExpr.cc
30
PExpr.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2010 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2011 Stephen Williams <steve@icarus.com>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -31,8 +31,10 @@
|
|||
|
||||
PExpr::PExpr()
|
||||
{
|
||||
expr_width_ = 0;
|
||||
expr_type_ = IVL_VT_NO_TYPE;
|
||||
expr_type_ = IVL_VT_NO_TYPE;
|
||||
expr_width_ = 0;
|
||||
min_width_ = 0;
|
||||
signed_flag_ = false;
|
||||
}
|
||||
|
||||
PExpr::~PExpr()
|
||||
|
|
@ -69,6 +71,11 @@ NetNet* PExpr::elaborate_bi_net(Design*, NetScope*) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool PExpr::is_collapsible_net(Design*, NetScope*) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PEBinary::PEBinary(char op, PExpr*l, PExpr*r)
|
||||
: op_(op), left_(l), right_(r)
|
||||
{
|
||||
|
|
@ -94,8 +101,8 @@ bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
|
|||
PEBComp::PEBComp(char op, PExpr*l, PExpr*r)
|
||||
: PEBinary(op, l, r)
|
||||
{
|
||||
left_width_ = 0;
|
||||
right_width_ = 0;
|
||||
l_width_ = 0;
|
||||
r_width_ = 0;
|
||||
}
|
||||
|
||||
PEBComp::~PEBComp()
|
||||
|
|
@ -204,13 +211,16 @@ bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
|
|||
}
|
||||
|
||||
PEConcat::PEConcat(const list<PExpr*>&p, PExpr*r)
|
||||
: parms_(p.size()), tested_widths_(p.size()), repeat_(r)
|
||||
: parms_(p.size()), width_modes_(SIZED, p.size()), repeat_(r)
|
||||
{
|
||||
int tmp_idx = 0;
|
||||
assert(parms_.size() == p.size());
|
||||
for (list<PExpr*>::const_iterator idx = p.begin()
|
||||
; idx != p.end() ; ++idx)
|
||||
parms_[tmp_idx++] = *idx;
|
||||
|
||||
tested_scope_ = 0;
|
||||
repeat_count_ = 1;
|
||||
}
|
||||
|
||||
PEConcat::~PEConcat()
|
||||
|
|
@ -437,3 +447,11 @@ bool PEUnary::has_aa_term(Design*des, NetScope*scope) const
|
|||
assert(expr_);
|
||||
return expr_->has_aa_term(des, scope);
|
||||
}
|
||||
|
||||
PEVoid::PEVoid()
|
||||
{
|
||||
}
|
||||
|
||||
PEVoid::~PEVoid()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
267
PExpr.h
267
PExpr.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __PExpr_H
|
||||
#define __PExpr_H
|
||||
/*
|
||||
* Copyright (c) 1998-2010 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2011 Stephen Williams <steve@icarus.com>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -43,6 +43,8 @@ class NetScope;
|
|||
class PExpr : public LineInfo {
|
||||
|
||||
public:
|
||||
enum width_mode_t { SIZED, EXPAND, LOSSLESS, UNSIZED };
|
||||
|
||||
PExpr();
|
||||
virtual ~PExpr();
|
||||
|
||||
|
|
@ -62,53 +64,65 @@ class PExpr : public LineInfo {
|
|||
// references to automatically allocated variables.
|
||||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
// This method tests the width that the expression wants to
|
||||
// be. It is used by elaboration of assignments to figure out
|
||||
// the width of the expression.
|
||||
// This method tests the type and width that the expression wants
|
||||
// to be. It should be called before elaborating an expression to
|
||||
// figure out the type and width of the expression. It also figures
|
||||
// out the minimum width that can be used to evaluate the expression
|
||||
// without changing the result. This allows the expression width to
|
||||
// be pruned when not all bits of the result are used.
|
||||
//
|
||||
// The "min" is the width of the local context, so is the
|
||||
// minimum width that this function should return. Initially
|
||||
// this is the same as the lval width.
|
||||
// Normally mode should be initialised to SIZED before starting to
|
||||
// test the width of an expression. In SIZED mode the expression
|
||||
// width will be calculated strictly according to the IEEE standard
|
||||
// rules for expression width.
|
||||
// If the expression contains an unsized literal, mode will be
|
||||
// changed to LOSSLESS. In LOSSLESS mode the expression width will
|
||||
// be calculated as the minimum width necessary to avoid arithmetic
|
||||
// overflow or underflow.
|
||||
// If the expression both contains an unsized literal and contains
|
||||
// an operation that coerces a vector operand to a different type
|
||||
// (signed <-> unsigned), mode is changed to UNSIZED. UNSIZED mode
|
||||
// is the same as LOSSLESS, except that the final expression width
|
||||
// will be forced to be at least integer_width. This is necessary
|
||||
// to ensure compatibility with the IEEE standard, which requires
|
||||
// unsized literals to be treated as having the same width as an
|
||||
// integer. The lossless width calculation is inadequate in this
|
||||
// case because coercing an operand to a different type means that
|
||||
// the expression no longer obeys the normal rules of arithmetic.
|
||||
//
|
||||
// The "lval" is the width of the destination where this
|
||||
// result is going to go. This can be used to constrain the
|
||||
// amount that an expression can reasonably expand. For
|
||||
// example, there is no point expanding an addition to beyond
|
||||
// the lval. This extra bit of information allows the
|
||||
// expression to optimize itself a bit. If the lval==0, then
|
||||
// the subexpression should not make l-value related
|
||||
// optimizations.
|
||||
// If mode is initialised to EXPAND instead of SIZED, the expression
|
||||
// width will be calculated as the minimum width necessary to avoid
|
||||
// arithmetic overflow or underflow, even if it contains no unsized
|
||||
// literals. mode will be changed LOSSLESS or UNSIZED as described
|
||||
// above. This supports a non-standard mode of expression width
|
||||
// calculation.
|
||||
//
|
||||
// The expr_type is an output argument that gives the
|
||||
// calculated type for the expression.
|
||||
//
|
||||
// The unsized_flag is set to true if the expression is
|
||||
// unsized and therefore expandable. This happens if a
|
||||
// sub-expression is an unsized literal. Some expressions make
|
||||
// special use of that.
|
||||
// When the final value of mode is UNSIZED, the width returned by
|
||||
// this method is the calculated lossless width, but the width
|
||||
// returned by a subsequent call to the expr_width method will be
|
||||
// the final expression width.
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
// After the test_width method is complete, these methods
|
||||
// return valid results.
|
||||
ivl_variable_type_t expr_type() const { return expr_type_; }
|
||||
unsigned expr_width() const { return expr_width_; }
|
||||
unsigned min_width() const { return min_width_; }
|
||||
bool has_sign() const { return signed_flag_; }
|
||||
|
||||
// This method allows the expression type (signed/unsigned)
|
||||
// to be propagated down to any context-dependant operands.
|
||||
void cast_signed(bool flag) { signed_flag_ = flag; }
|
||||
|
||||
// Procedural elaboration of the expression. The expr_width is
|
||||
// the width of the context of the expression (i.e. the
|
||||
// l-value width of an assignment),
|
||||
//
|
||||
// ... or -1 if the expression is self-determined. or
|
||||
// ... or -2 if the expression is losslessly
|
||||
// self-determined. This can happen in situations where the
|
||||
// result is going to a pseudo-infinitely wide context.
|
||||
// the required width of the expression.
|
||||
//
|
||||
// The sys_task_arg flag is true if expressions are allowed to
|
||||
// be incomplete.
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
|
||||
// This method elaborates the expression as gates, but
|
||||
// restricted for use as l-values of continuous assignments.
|
||||
|
|
@ -134,15 +148,25 @@ class PExpr : public LineInfo {
|
|||
// evaluated, return 0.
|
||||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
|
||||
// This method returns true if the expression represents a
|
||||
// structural net that can have multiple drivers. This is
|
||||
// used to test whether an input port connection can be
|
||||
// collapsed to a single wire.
|
||||
virtual bool is_collapsible_net(Design*des, NetScope*scope) const;
|
||||
|
||||
// This method returns true if that expression is the same as
|
||||
// this expression. This method is used for comparing
|
||||
// expressions that must be structurally "identical".
|
||||
virtual bool is_the_same(const PExpr*that) const;
|
||||
|
||||
protected:
|
||||
unsigned fix_width_(width_mode_t mode);
|
||||
|
||||
// The derived class test_width methods should fill these in.
|
||||
ivl_variable_type_t expr_type_;
|
||||
unsigned expr_width_;
|
||||
unsigned min_width_;
|
||||
bool signed_flag_;
|
||||
|
||||
private: // not implemented
|
||||
PExpr(const PExpr&);
|
||||
|
|
@ -165,25 +189,27 @@ class PEConcat : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
virtual NetAssign_* elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
bool is_force) const;
|
||||
virtual bool is_collapsible_net(Design*des, NetScope*scope) const;
|
||||
private:
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool bidirectional_flag) const;
|
||||
private:
|
||||
vector<PExpr*>parms_;
|
||||
std::valarray<unsigned>tested_widths_;
|
||||
std::valarray<width_mode_t>width_modes_;
|
||||
|
||||
PExpr*repeat_;
|
||||
NetScope*tested_scope_;
|
||||
unsigned repeat_count_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -232,11 +258,10 @@ class PEFNumber : public PExpr {
|
|||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
|
|
@ -262,9 +287,7 @@ class PEIdent : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
// Identifiers are allowed (with restrictions) is assign l-values.
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
|
|
@ -277,7 +300,8 @@ class PEIdent : public PExpr {
|
|||
bool is_force) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
|
||||
// Elaborate the PEIdent as a port to a module. This method
|
||||
// only applies to Ident expressions.
|
||||
|
|
@ -285,6 +309,8 @@ class PEIdent : public PExpr {
|
|||
|
||||
verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
|
||||
virtual bool is_collapsible_net(Design*des, NetScope*scope) const;
|
||||
|
||||
const pform_name_t& path() const { return path_; }
|
||||
|
||||
private:
|
||||
|
|
@ -326,13 +352,14 @@ class PEIdent : public PExpr {
|
|||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb,
|
||||
int expr_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_param_part_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
const NetExpr*par_lsb,
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_param_idx_up_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
|
|
@ -349,28 +376,31 @@ class PEIdent : public PExpr {
|
|||
NetScope*scope,
|
||||
NetNet*net,
|
||||
NetScope*found,
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
NetExpr*elaborate_expr_net_word_(Design*des,
|
||||
NetScope*scope,
|
||||
NetNet*net,
|
||||
NetScope*found,
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
NetExpr*elaborate_expr_net_part_(Design*des,
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found,
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_net_idx_up_(Design*des,
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetExpr*elaborate_expr_net_idx_do_(Design*des,
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetExpr*elaborate_expr_net_bit_(Design*des,
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
|
||||
private:
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
|
|
@ -390,12 +420,10 @@ class PENumber : public PExpr {
|
|||
|
||||
virtual void dump(ostream&) const;
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool) const;
|
||||
unsigned expr_wid, bool) const;
|
||||
virtual NetAssign_* elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
bool is_force) const;
|
||||
|
|
@ -425,12 +453,10 @@ class PEString : public PExpr {
|
|||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool) const;
|
||||
unsigned expr_wid, bool) const;
|
||||
verinum* eval_const(Design*, NetScope*) const;
|
||||
|
||||
private:
|
||||
|
|
@ -450,16 +476,15 @@ class PEUnary : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
|
||||
private:
|
||||
NetExpr* elaborate_expr_bits_(NetExpr*operand, int expr_wid) const;
|
||||
NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const;
|
||||
|
||||
private:
|
||||
char op_;
|
||||
|
|
@ -479,12 +504,11 @@ class PEBinary : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
|
||||
protected:
|
||||
|
|
@ -493,22 +517,18 @@ class PEBinary : public PExpr {
|
|||
PExpr*right_;
|
||||
|
||||
NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
|
||||
NetExpr*elaborate_expr_base_bits_(Design*, NetExpr*lp, NetExpr*rp,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_base_div_(Design*, NetExpr*lp, NetExpr*rp,
|
||||
int use_wid) const;
|
||||
NetExpr*elaborate_expr_base_lshift_(Design*, NetExpr*lp, NetExpr*rp,
|
||||
int use_wid) const;
|
||||
NetExpr*elaborate_expr_base_rshift_(Design*, NetExpr*lp, NetExpr*rp,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_base_mult_(Design*, NetExpr*lp, NetExpr*rp,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_base_add_(Design*, NetExpr*lp, NetExpr*rp,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -523,16 +543,14 @@ class PEBComp : public PEBinary {
|
|||
~PEBComp();
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
NetExpr* elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid, bool sys_task_arg) const;
|
||||
|
||||
private:
|
||||
int left_width_;
|
||||
int right_width_;
|
||||
unsigned l_width_;
|
||||
unsigned r_width_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -545,12 +563,10 @@ class PEBLogic : public PEBinary {
|
|||
~PEBLogic();
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
NetExpr* elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid, bool sys_task_arg) const;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -565,17 +581,15 @@ class PEBLeftWidth : public PEBinary {
|
|||
~PEBLeftWidth() =0;
|
||||
|
||||
virtual NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const =0;
|
||||
unsigned expr_wid) const =0;
|
||||
|
||||
protected:
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
};
|
||||
|
||||
class PEBPower : public PEBLeftWidth {
|
||||
|
|
@ -585,7 +599,7 @@ class PEBPower : public PEBLeftWidth {
|
|||
~PEBPower();
|
||||
|
||||
NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
};
|
||||
|
||||
class PEBShift : public PEBLeftWidth {
|
||||
|
|
@ -595,7 +609,7 @@ class PEBShift : public PEBLeftWidth {
|
|||
~PEBShift();
|
||||
|
||||
NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -615,17 +629,16 @@ class PETernary : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
|
||||
private:
|
||||
NetExpr* elab_and_eval_alternative_(Design*des, NetScope*scope,
|
||||
PExpr*expr, int use_wid) const;
|
||||
PExpr*expr, unsigned expr_wid) const;
|
||||
|
||||
private:
|
||||
PExpr*expr_;
|
||||
|
|
@ -658,12 +671,11 @@ class PECallFunction : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_wid, bool sys_task_arg) const;
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
private:
|
||||
pform_name_t path_;
|
||||
|
|
@ -671,14 +683,29 @@ class PECallFunction : public PExpr {
|
|||
|
||||
bool check_call_matches_definition_(Design*des, NetScope*dscope) const;
|
||||
|
||||
NetExpr* cast_to_width_(NetExpr*expr, int wid, bool signed_flag) const;
|
||||
NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const;
|
||||
|
||||
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const;
|
||||
NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t) const;
|
||||
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid) const;
|
||||
NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t,
|
||||
unsigned expr_wid) const;
|
||||
unsigned test_width_sfunc_(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
};
|
||||
|
||||
/*
|
||||
* This class is used for error recovery. All methods do nothing and return
|
||||
* null or default values.
|
||||
*/
|
||||
class PEVoid : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PEVoid();
|
||||
~PEVoid();
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
2
PUdp.h
2
PUdp.h
|
|
@ -29,7 +29,7 @@ class PExpr;
|
|||
|
||||
/*
|
||||
* This class represents a parsed UDP. This is a much simpler object
|
||||
* then a module or macromodule.
|
||||
* than a module or macromodule.
|
||||
*
|
||||
* - all ports are scalar,
|
||||
* - pin 0 (the first port) is always output,
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ item. The syntax of the $attribute item is:
|
|||
$attribute (<identifier>, <key>, <value>);
|
||||
|
||||
The $attribute keyword looks like a system task invocation. The
|
||||
difference here is that the parameters are more restricted then those
|
||||
difference here is that the parameters are more restricted than those
|
||||
of a system task. The <identifier> must be an identifier. This will be
|
||||
the item to get an attribute. The <key> and <value> are strings, not
|
||||
expressions, that give the key and the value of the attribute to be
|
||||
|
|
|
|||
|
|
@ -1396,12 +1396,8 @@ void NetEBinary::dump(ostream&o) const
|
|||
|
||||
void NetEConcat::dump(ostream&o) const
|
||||
{
|
||||
if (repeat_calculated_) {
|
||||
if (repeat_value_ != 1)
|
||||
o << repeat_value_;
|
||||
} else if (repeat_) {
|
||||
o << "<" << *repeat_ << ">";
|
||||
}
|
||||
if (repeat_ != 1)
|
||||
o << repeat_;
|
||||
|
||||
if (parms_[0])
|
||||
o << "{" << *parms_[0];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.TH iverilog 1 "January 8th, 2011" "" "Version %M.%m.%n %E"
|
||||
.TH iverilog 1 "February 27th, 2011" "" "Version %M.%m.%n %E"
|
||||
.SH NAME
|
||||
iverilog - Icarus Verilog compiler
|
||||
|
||||
|
|
@ -258,7 +258,9 @@ checking the syntax of the Verilog source.
|
|||
.B vvp
|
||||
This is the default. The vvp target generates code for the vvp
|
||||
runtime. The output is a complete program that simulates the design
|
||||
but must be run by the \fBvvp\fP command.
|
||||
but must be run by the \fBvvp\fP command. The -pfileline=1 option
|
||||
can be used to add procedural statement debugging opcodes to the
|
||||
generated code.
|
||||
.TP 8
|
||||
.B fpga
|
||||
This is a synthesis target that supports a variety of fpga devices,
|
||||
|
|
|
|||
150
dup_expr.cc
150
dup_expr.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -32,19 +32,103 @@ NetEAccess* NetEAccess::dup_expr() const
|
|||
return tmp;
|
||||
}
|
||||
|
||||
NetEBComp* NetEBComp::dup_expr() const
|
||||
NetEBinary* NetEBinary::dup_expr() const
|
||||
{
|
||||
NetEBComp*tmp = new NetEBComp(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEBAdd* NetEBAdd::dup_expr() const
|
||||
{
|
||||
NetEBAdd*tmp = new NetEBAdd(op_, left_->dup_expr(), right_->dup_expr(),
|
||||
expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEBBits* NetEBBits::dup_expr() const
|
||||
{
|
||||
NetEBBits*tmp = new NetEBBits(op_, left_->dup_expr(), right_->dup_expr(),
|
||||
expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEBComp* NetEBComp::dup_expr() const
|
||||
{
|
||||
NetEBComp*tmp = new NetEBComp(op_, left_->dup_expr(), right_->dup_expr());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEBDiv* NetEBDiv::dup_expr() const
|
||||
{
|
||||
NetEBDiv*tmp = new NetEBDiv(op_, left_->dup_expr(), right_->dup_expr(),
|
||||
expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEBLogic* NetEBLogic::dup_expr() const
|
||||
{
|
||||
NetEBLogic*tmp = new NetEBLogic(op_, left_->dup_expr(), right_->dup_expr());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEBMult* NetEBMult::dup_expr() const
|
||||
{
|
||||
NetEBMult*tmp = new NetEBMult(op_, left_->dup_expr(), right_->dup_expr(),
|
||||
expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEBPow* NetEBPow::dup_expr() const
|
||||
{
|
||||
NetEBPow*tmp = new NetEBPow(op_, left_->dup_expr(), right_->dup_expr(),
|
||||
expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEBShift* NetEBShift::dup_expr() const
|
||||
{
|
||||
NetEBShift*tmp = new NetEBShift(op_, left_->dup_expr(), right_->dup_expr(),
|
||||
expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEConcat* NetEConcat::dup_expr() const
|
||||
{
|
||||
NetEConcat*dup = new NetEConcat(parms_.count(), repeat_);
|
||||
ivl_assert(*this, dup);
|
||||
dup->set_line(*this);
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
if (parms_[idx]) {
|
||||
NetExpr*tmp = parms_[idx]->dup_expr();
|
||||
ivl_assert(*this, tmp);
|
||||
dup->parms_[idx] = tmp;
|
||||
}
|
||||
|
||||
dup->expr_width(expr_width());
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
NetEConst* NetEConst::dup_expr() const
|
||||
{
|
||||
NetEConst*tmp = new NetEConst(value_);
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -52,7 +136,7 @@ NetEConst* NetEConst::dup_expr() const
|
|||
NetEConstEnum* NetEConstEnum::dup_expr() const
|
||||
{
|
||||
NetEConstEnum*tmp = new NetEConstEnum(scope_, name_, enum_set_, value());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -60,7 +144,15 @@ NetEConstEnum* NetEConstEnum::dup_expr() const
|
|||
NetEConstParam* NetEConstParam::dup_expr() const
|
||||
{
|
||||
NetEConstParam*tmp = new NetEConstParam(scope_, name_, value());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetECReal* NetECReal::dup_expr() const
|
||||
{
|
||||
NetECReal*tmp = new NetECReal(value_);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -68,26 +160,26 @@ NetEConstParam* NetEConstParam::dup_expr() const
|
|||
NetECRealParam* NetECRealParam::dup_expr() const
|
||||
{
|
||||
NetECRealParam*tmp = new NetECRealParam(scope_, name_, value());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEEvent* NetEEvent::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetENetenum* NetENetenum::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEScope* NetEScope::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -95,8 +187,8 @@ NetESelect* NetESelect::dup_expr() const
|
|||
{
|
||||
NetESelect*tmp = new NetESelect(expr_->dup_expr(),
|
||||
base_? base_->dup_expr() : 0,
|
||||
expr_width());
|
||||
assert(tmp);
|
||||
expr_width(), sel_type_);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -104,11 +196,11 @@ NetESelect* NetESelect::dup_expr() const
|
|||
NetESFunc* NetESFunc::dup_expr() const
|
||||
{
|
||||
NetESFunc*tmp = new NetESFunc(name_, type_, expr_width(), nparms());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
tmp->cast_signed(has_sign());
|
||||
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
||||
assert(parm(idx));
|
||||
ivl_assert(*this, parm(idx));
|
||||
tmp->parm(idx, parm(idx)->dup_expr());
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +211,7 @@ NetESFunc* NetESFunc::dup_expr() const
|
|||
NetESignal* NetESignal::dup_expr() const
|
||||
{
|
||||
NetESignal*tmp = new NetESignal(net_, word_);
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->expr_width(expr_width());
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
|
|
@ -129,8 +221,10 @@ NetETernary* NetETernary::dup_expr() const
|
|||
{
|
||||
NetETernary*tmp = new NetETernary(cond_->dup_expr(),
|
||||
true_val_->dup_expr(),
|
||||
false_val_->dup_expr());
|
||||
assert(tmp);
|
||||
false_val_->dup_expr(),
|
||||
expr_width(),
|
||||
has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -141,29 +235,29 @@ NetEUFunc* NetEUFunc::dup_expr() const
|
|||
svector<NetExpr*> tmp_parms (parms_.count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < tmp_parms.count() ; idx += 1) {
|
||||
assert(parms_[idx]);
|
||||
ivl_assert(*this, parms_[idx]);
|
||||
tmp_parms[idx] = parms_[idx]->dup_expr();
|
||||
}
|
||||
|
||||
tmp = new NetEUFunc(scope_, func_, result_sig_->dup_expr(), tmp_parms);
|
||||
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEUBits* NetEUBits::dup_expr() const
|
||||
{
|
||||
NetEUBits*tmp = new NetEUBits(op_, expr_->dup_expr());
|
||||
assert(tmp);
|
||||
NetEUBits*tmp = new NetEUBits(op_, expr_->dup_expr(), expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEUnary* NetEUnary::dup_expr() const
|
||||
{
|
||||
NetEUnary*tmp = new NetEUnary(op_, expr_->dup_expr());
|
||||
assert(tmp);
|
||||
NetEUnary*tmp = new NetEUnary(op_, expr_->dup_expr(), expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -171,15 +265,15 @@ NetEUnary* NetEUnary::dup_expr() const
|
|||
NetEUReduce* NetEUReduce::dup_expr() const
|
||||
{
|
||||
NetEUReduce*tmp = new NetEUReduce(op_, expr_->dup_expr());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetECast* NetECast::dup_expr() const
|
||||
{
|
||||
NetECast*tmp = new NetECast(op_, expr_->dup_expr());
|
||||
assert(tmp);
|
||||
NetECast*tmp = new NetECast(op_, expr_->dup_expr(), expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
|
|||
2109
elab_expr.cc
2109
elab_expr.cc
File diff suppressed because it is too large
Load Diff
27
elab_lval.cc
27
elab_lval.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
* l-value.
|
||||
*
|
||||
* This last case can turn up in statements like: {a, b[1]} = c;
|
||||
* rather then create a NetAssign_ for each item in the concatenation,
|
||||
* rather than create a NetAssign_ for each item in the concatenation,
|
||||
* elaboration makes a single NetAssign_ and connects it up properly.
|
||||
*/
|
||||
|
||||
|
|
@ -255,12 +255,6 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
|||
ivl_assert(*this, index_head.msb != 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;
|
||||
bool unsized_flag_tmp = false;
|
||||
index_head.msb->test_width(des, scope, integer_width, integer_width,
|
||||
expr_type_tmp, unsized_flag_tmp);
|
||||
|
||||
NetExpr*word = elab_and_eval(des, scope, index_head.msb, -1);
|
||||
|
||||
// If there is a non-zero base to the memory, then build an
|
||||
|
|
@ -335,12 +329,6 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|||
|
||||
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;
|
||||
bool unsized_flag_tmp = false;
|
||||
index_tail.msb->test_width(des, scope, integer_width, integer_width,
|
||||
expr_type_tmp, unsized_flag_tmp);
|
||||
|
||||
// Bit selects have a single select expression. Evaluate the
|
||||
// constant value and treat it as a part select with a bit
|
||||
// width of 1.
|
||||
|
|
@ -463,13 +451,8 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
|||
unsigned long 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;
|
||||
bool unsized_flag_tmp = false;
|
||||
index_tail.msb->test_width(des, scope, integer_width, integer_width,
|
||||
expr_type_tmp, unsized_flag_tmp);
|
||||
|
||||
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
ivl_select_type_t sel_type = IVL_SEL_OTHER;
|
||||
|
||||
// Handle the special case that the base is constant. For this
|
||||
// case we can reduce the expression.
|
||||
|
|
@ -532,10 +515,12 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
|||
if (use_sel == index_component_t::SEL_IDX_UP) {
|
||||
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
|
||||
wid, true);
|
||||
sel_type = IVL_SEL_IDX_UP;
|
||||
} else {
|
||||
// This is assumed to be a SEL_IDX_DO.
|
||||
base = normalize_variable_base(base, reg->msb(), reg->lsb(),
|
||||
wid, false);
|
||||
sel_type = IVL_SEL_IDX_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -543,7 +528,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
|||
cerr << get_fileline() << ": debug: Set part select width="
|
||||
<< wid << ", base=" << *base << endl;
|
||||
|
||||
lv->set_part(base, wid);
|
||||
lv->set_part(base, wid, sel_type);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
119
elab_net.cc
119
elab_net.cc
|
|
@ -73,23 +73,20 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
nets[idx] = parms_[idx]->elaborate_lnet(des, scope);
|
||||
}
|
||||
|
||||
if (nets[idx] == 0) errors += 1;
|
||||
else if (nets[idx]->data_type() == IVL_VT_REAL) {
|
||||
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;
|
||||
continue;
|
||||
} else width += nets[idx]->vector_width();
|
||||
|
||||
} else {
|
||||
width += nets[idx]->vector_width();
|
||||
}
|
||||
}
|
||||
|
||||
/* If any of the sub expressions failed to elaborate, then
|
||||
delete all those that did and abort myself. */
|
||||
if (errors) {
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
if (nets[idx]) delete nets[idx];
|
||||
}
|
||||
des->errors += errors;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -170,6 +167,28 @@ NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope) const
|
|||
return elaborate_lnet_common_(des, scope, true);
|
||||
}
|
||||
|
||||
bool PEConcat::is_collapsible_net(Design*des, NetScope*scope) const
|
||||
{
|
||||
assert(scope);
|
||||
|
||||
// Repeat concatenations are not currently supported.
|
||||
if (repeat_)
|
||||
return false;
|
||||
|
||||
// Test the operands of the concatenation.
|
||||
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
||||
|
||||
// Empty expressions are not allowed in concatenations
|
||||
if (parms_[idx] == 0)
|
||||
return false;
|
||||
|
||||
if (!parms_[idx]->is_collapsible_net(des, scope))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This private method evaluates the part selects (if any) for the
|
||||
* signal. The sig argument is the NetNet already located for the
|
||||
|
|
@ -203,12 +222,6 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
|||
|
||||
case index_component_t::SEL_IDX_DO:
|
||||
case index_component_t::SEL_IDX_UP: {
|
||||
// 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_tail.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_tail.msb, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -439,21 +452,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (sig->port_type() == NetNet::PINPUT) {
|
||||
sig->port_type(NetNet::PINOUT);
|
||||
// This map mask prevents an error message being
|
||||
// repeated endlessly.
|
||||
static map<string,bool> mask_map;
|
||||
bool&flag = mask_map[sig->get_fileline() + ":" + string(sig->name())];
|
||||
if (! flag) {
|
||||
cerr << get_fileline() << ": warning: L-value ``"
|
||||
<< sig->name() << "'' is also an input port." << endl;
|
||||
cerr << sig->get_fileline() << ": warning: input "
|
||||
<< sig->name() << "; is coerced to inout." << endl;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Default part select is the entire word.
|
||||
unsigned midx = sig->vector_width()-1, lidx = 0;
|
||||
// The default word select is the first.
|
||||
|
|
@ -482,12 +480,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
}
|
||||
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);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -582,10 +574,10 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
sig = tmp;
|
||||
}
|
||||
|
||||
/* If the desired l-value vector is narrower then the
|
||||
/* If the desired l-value vector is narrower than the
|
||||
signal itself, then use a NetPartSelect node to
|
||||
arrange for connection to the desired bits. All this
|
||||
can be skipped if the desired with matches the
|
||||
can be skipped if the desired width matches the
|
||||
original vector. */
|
||||
|
||||
if (subnet_wid != sig->vector_width()) {
|
||||
|
|
@ -655,6 +647,7 @@ NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const
|
|||
*/
|
||||
NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
|
||||
{
|
||||
assert(scope->type() == NetScope::MODULE);
|
||||
NetNet*sig = des->find_signal(scope, path_);
|
||||
if (sig == 0) {
|
||||
cerr << get_fileline() << ": error: no wire/reg " << path_
|
||||
|
|
@ -707,8 +700,10 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
|
|||
|
||||
/* If this is a part select of the entire signal (or no part
|
||||
select at all) then we're done. */
|
||||
if ((lidx == 0) && (midx == (long)sig->vector_width()-1))
|
||||
if ((lidx == 0) && (midx == (long)sig->vector_width()-1)) {
|
||||
scope->add_module_port(sig);
|
||||
return sig;
|
||||
}
|
||||
|
||||
unsigned swid = abs(midx - lidx) + 1;
|
||||
ivl_assert(*this, swid > 0 && swid < sig->vector_width());
|
||||
|
|
@ -718,26 +713,25 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
|
|||
tmp->port_type(sig->port_type());
|
||||
tmp->data_type(sig->data_type());
|
||||
tmp->set_line(*this);
|
||||
tmp->local_flag(true);
|
||||
NetNode*ps = 0;
|
||||
switch (sig->port_type()) {
|
||||
|
||||
case NetNet::PINPUT:
|
||||
ps = new NetPartSelect(sig, sig->sb_to_idx(lidx), swid,
|
||||
NetPartSelect::PV);
|
||||
ps = new NetPartSelect(sig, lidx, swid, NetPartSelect::PV);
|
||||
connect(tmp->pin(0), ps->pin(0));
|
||||
sig = tmp;
|
||||
break;
|
||||
|
||||
case NetNet::POUTPUT:
|
||||
ps = new NetPartSelect(sig, sig->sb_to_idx(lidx), swid,
|
||||
NetPartSelect::VP);
|
||||
ps = new NetPartSelect(sig, lidx, swid, NetPartSelect::VP);
|
||||
connect(tmp->pin(0), ps->pin(0));
|
||||
sig = tmp;
|
||||
break;
|
||||
|
||||
case NetNet::PINOUT:
|
||||
ps = new NetTran(scope, scope->local_symbol(), sig->vector_width(),
|
||||
swid, sig->sb_to_idx(lidx));
|
||||
swid, lidx);
|
||||
connect(sig->pin(0), ps->pin(0));
|
||||
connect(tmp->pin(0), ps->pin(1));
|
||||
sig = tmp;
|
||||
|
|
@ -751,5 +745,42 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
|
|||
ps->set_line(*this);
|
||||
des->add_node(ps);
|
||||
|
||||
scope->add_module_port(sig);
|
||||
return sig;
|
||||
}
|
||||
|
||||
bool PEIdent::is_collapsible_net(Design*des, NetScope*scope) const
|
||||
{
|
||||
assert(scope);
|
||||
|
||||
NetNet* sig = 0;
|
||||
const NetExpr*par = 0;
|
||||
NetEvent* eve = 0;
|
||||
|
||||
symbol_search(this, des, scope, path_, sig, par, eve);
|
||||
|
||||
if (eve != 0)
|
||||
return false;
|
||||
|
||||
if (sig == 0)
|
||||
return false;
|
||||
|
||||
assert(sig);
|
||||
|
||||
/* If this is SystemVerilog and the variable is not yet
|
||||
assigned by anything, then convert it to an unresolved
|
||||
wire. */
|
||||
if (gn_var_can_be_uwire()
|
||||
&& (sig->type() == NetNet::REG)
|
||||
&& (sig->peek_eref() == 0) ) {
|
||||
sig->type(NetNet::UNRESOLVED_WIRE);
|
||||
}
|
||||
|
||||
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->pin(0).is_linked())
|
||||
return false;
|
||||
|
||||
if (sig->type() == NetNet::REG)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
typedef map<perm_string,LexicalScope::param_expr_t>::const_iterator mparm_it_t;
|
||||
|
||||
static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
|
||||
static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
|
||||
const LexicalScope::param_expr_t&cur)
|
||||
{
|
||||
NetScope::range_t*range_list = 0;
|
||||
|
|
@ -61,7 +61,6 @@ static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
|
|||
tmp->high_open_flag = range->high_open_flag;
|
||||
|
||||
if (range->low_expr) {
|
||||
probe_expr_width(des, scope, range->low_expr);
|
||||
tmp->low_expr = elab_and_eval(des, scope, range->low_expr, -1);
|
||||
ivl_assert(*range->low_expr, tmp->low_expr);
|
||||
} else {
|
||||
|
|
@ -78,7 +77,6 @@ static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
|
|||
tmp->high_expr = tmp->low_expr;
|
||||
|
||||
} else if (range->high_expr) {
|
||||
probe_expr_width(des, scope, range->high_expr);
|
||||
tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1);
|
||||
ivl_assert(*range->high_expr, tmp->high_expr);
|
||||
} else {
|
||||
|
|
@ -136,8 +134,8 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
{
|
||||
bool rc_flag;
|
||||
assert(enum_type->range->size() == 2);
|
||||
NetExpr*msb_ex = enum_type->range->front()->elaborate_expr(des, scope, -2, false);
|
||||
NetExpr*lsb_ex = enum_type->range->back() ->elaborate_expr(des, scope, -2, false);
|
||||
NetExpr*msb_ex = elab_and_eval(des, scope, enum_type->range->front(), -1);
|
||||
NetExpr*lsb_ex = elab_and_eval(des, scope, enum_type->range->back(), -1);
|
||||
|
||||
long msb = 0;
|
||||
rc_flag = eval_as_long(msb, msb_ex);
|
||||
|
|
@ -162,7 +160,6 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
// There is an explicit value. elaborate/evaluate
|
||||
// the value and assign it to the enumeration name.
|
||||
NetExpr*val = elab_and_eval(des, scope, cur->parm,
|
||||
use_enum->base_width(),
|
||||
use_enum->base_width());
|
||||
NetEConst*val_const = dynamic_cast<NetEConst*> (val);
|
||||
if (val_const == 0) {
|
||||
|
|
@ -427,7 +424,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
|||
|
||||
// Run through the defparams for this module and save the result
|
||||
// in a table for later final override.
|
||||
|
||||
|
||||
typedef list<Module::named_expr_t>::const_iterator defparms_iter_t;
|
||||
for (defparms_iter_t cur = defparms.begin()
|
||||
; cur != defparms.end() ; ++ cur ) {
|
||||
|
|
@ -557,7 +554,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
// The initial value for the genvar does not need (nor can it
|
||||
// use) the genvar itself, so we can evaluate this expression
|
||||
// the same way any other parameter value is evaluated.
|
||||
probe_expr_width(des, container, loop_init);
|
||||
need_constant_expr = true;
|
||||
NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -624,7 +620,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
cerr << get_fileline() << ": debug: genvar init = " << genvar << endl;
|
||||
container->genvar_tmp = loop_index;
|
||||
container->genvar_tmp_val = genvar;
|
||||
probe_expr_width(des, container, loop_test);
|
||||
need_constant_expr = true;
|
||||
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -673,7 +668,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
elaborate_subscope_(des, scope);
|
||||
|
||||
// Calculate the step for the loop variable.
|
||||
probe_expr_width(des, container, loop_step);
|
||||
need_constant_expr = true;
|
||||
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -692,7 +686,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
container->genvar_tmp_val = genvar;
|
||||
delete step;
|
||||
delete test_ex;
|
||||
probe_expr_width(des, container, loop_test);
|
||||
test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
test = dynamic_cast<NetEConst*>(test_ex);
|
||||
assert(test);
|
||||
|
|
@ -707,7 +700,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
|
||||
bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else_flag)
|
||||
{
|
||||
probe_expr_width(des, container, loop_test);
|
||||
need_constant_expr = true;
|
||||
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -800,7 +792,6 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
|
|||
|
||||
bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
||||
{
|
||||
probe_expr_width(des, container, loop_test);
|
||||
need_constant_expr = true;
|
||||
NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -833,7 +824,6 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
|||
|
||||
bool match_flag = false;
|
||||
for (unsigned idx = 0 ; idx < item->item_test.size() && !match_flag ; idx +=1 ) {
|
||||
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);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -1206,8 +1196,6 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
|||
*/
|
||||
void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const
|
||||
{
|
||||
if (msb_) probe_expr_width(des, sc, msb_);
|
||||
if (lsb_) probe_expr_width(des, sc, lsb_);
|
||||
need_constant_expr = true;
|
||||
NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0;
|
||||
NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0;
|
||||
|
|
@ -1387,7 +1375,7 @@ void PFunction::elaborate_scope(Design*des, NetScope*scope) const
|
|||
assert(scope->type() == NetScope::FUNC);
|
||||
|
||||
// Scan the parameters in the function, and store the information
|
||||
// needed to evaluate the parameter expressions.
|
||||
// needed to evaluate the parameter expressions.
|
||||
|
||||
collect_scope_parameters_(des, scope, parameters);
|
||||
|
||||
|
|
@ -1405,7 +1393,7 @@ void PTask::elaborate_scope(Design*des, NetScope*scope) const
|
|||
assert(scope->type() == NetScope::TASK);
|
||||
|
||||
// Scan the parameters in the task, and store the information
|
||||
// needed to evaluate the parameter expressions.
|
||||
// needed to evaluate the parameter expressions.
|
||||
|
||||
collect_scope_parameters_(des, scope, parameters);
|
||||
|
||||
|
|
@ -1482,7 +1470,7 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
|
|||
my_scope->is_auto(scope->is_auto());
|
||||
|
||||
// Scan the parameters in the scope, and store the information
|
||||
// needed to evaluate the parameter expressions.
|
||||
// needed to evaluate the parameter expressions.
|
||||
|
||||
collect_scope_parameters_(des, my_scope, parameters);
|
||||
|
||||
|
|
|
|||
15
elab_sig.cc
15
elab_sig.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -471,8 +471,6 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
|||
case PTF_REG_S:
|
||||
if (return_type_.range) {
|
||||
ivl_assert(*this, return_type_.range->size() == 2);
|
||||
probe_expr_width(des, scope, return_type_.range->at(0));
|
||||
probe_expr_width(des, scope, return_type_.range->at(1));
|
||||
|
||||
need_constant_expr = true;
|
||||
NetExpr*me = elab_and_eval(des, scope,
|
||||
|
|
@ -545,8 +543,6 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
|
|||
case PTF_ATOM2:
|
||||
case PTF_ATOM2_S:
|
||||
ivl_assert(*this, return_type_.range != 0);
|
||||
probe_expr_width(des, scope, (*return_type_.range)[0]);
|
||||
probe_expr_width(des, scope, (*return_type_.range)[1]);
|
||||
long use_wid;
|
||||
{
|
||||
need_constant_expr = true;
|
||||
|
|
@ -852,7 +848,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
bool bad_lsb = false, bad_msb = false;
|
||||
/* If they exist get the port definition MSB and LSB */
|
||||
if (port_set_ && port_msb_ != 0) {
|
||||
probe_expr_width(des, scope, port_msb_);
|
||||
/* We do not currently support constant user function. */
|
||||
need_constant_expr = true;
|
||||
NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1);
|
||||
|
|
@ -870,7 +865,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
|
||||
delete texpr;
|
||||
|
||||
probe_expr_width(des, scope, port_lsb_);
|
||||
/* We do not currently support constant user function. */
|
||||
need_constant_expr = true;
|
||||
texpr = elab_and_eval(des, scope, port_lsb_, -1);
|
||||
|
|
@ -898,7 +892,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
|
||||
/* If they exist get the net/etc. definition MSB and LSB */
|
||||
if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) {
|
||||
probe_expr_width(des, scope, net_msb_);
|
||||
/* We do not currently support constant user function. */
|
||||
need_constant_expr = true;
|
||||
NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1);
|
||||
|
|
@ -916,7 +909,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
|
||||
delete texpr;
|
||||
|
||||
probe_expr_width(des, scope, net_lsb_);
|
||||
/* We do not currently support constant user function. */
|
||||
need_constant_expr = true;
|
||||
texpr = elab_and_eval(des, scope, net_lsb_, -1);
|
||||
|
|
@ -1011,9 +1003,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
if (lidx_ || ridx_) {
|
||||
assert(lidx_ && ridx_);
|
||||
|
||||
probe_expr_width(des, scope, lidx_);
|
||||
probe_expr_width(des, scope, ridx_);
|
||||
|
||||
need_constant_expr = true;
|
||||
NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1);
|
||||
NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1);
|
||||
|
|
@ -1053,7 +1042,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
cerr << get_fileline() << ": error: real ";
|
||||
if (wtype == NetNet::REG) cerr << "variable";
|
||||
else cerr << "net";
|
||||
cerr << " '" << name_
|
||||
cerr << " '" << name_
|
||||
<< "' cannot be declared as a vector, found a range ["
|
||||
<< msb << ":" << lsb << "]." << endl;
|
||||
des->errors += 1;
|
||||
|
|
|
|||
208
elaborate.cc
208
elaborate.cc
|
|
@ -115,6 +115,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
cerr << get_fileline() << ": debug: PGAssign: elaborated r-value"
|
||||
<< " width="<< rval->vector_width()
|
||||
<< ", type="<< rval->data_type()
|
||||
<< ", signed="<< rval->get_signed()
|
||||
<< ", expr=" << *rval_expr << endl;
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +144,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
need_driver_flag = false;
|
||||
}
|
||||
|
||||
/* If the r-value insists on being smaller then the l-value
|
||||
/* If the r-value insists on being smaller than the l-value
|
||||
(perhaps it is explicitly sized) the pad it out to be the
|
||||
right width so that something is connected to all the bits
|
||||
of the l-value. */
|
||||
|
|
@ -156,7 +157,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
}
|
||||
|
||||
/* If, on the other hand, the r-value insists on being
|
||||
LARGER then the l-value, use a part select to chop it down
|
||||
LARGER than the l-value, use a part select to chop it down
|
||||
down to size. */
|
||||
if (lval->vector_width() < rval->vector_width()) {
|
||||
NetPartSelect*tmp = new NetPartSelect(rval, 0,lval->vector_width(),
|
||||
|
|
@ -227,11 +228,6 @@ unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
|
|||
gate. Figure out how many are desired. */
|
||||
if (msb_) {
|
||||
need_constant_expr = true;
|
||||
ivl_variable_type_t use_type;
|
||||
bool flag = false;
|
||||
msb_->test_width(des, scope, 0, 0, use_type, flag);
|
||||
flag = false;
|
||||
lsb_->test_width(des, scope, 0, 0, use_type, flag);
|
||||
NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1);
|
||||
NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -820,12 +816,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
|||
sig = lval_sigs[idx];
|
||||
|
||||
} else {
|
||||
unsigned use_width = array_count * instance_width;
|
||||
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE;
|
||||
bool flag = false;
|
||||
ex->test_width(des, scope, 0, use_width, tmp_type, flag);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, ex,
|
||||
use_width, use_width);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, ex, -1);
|
||||
sig = tmp->synthesize(des, scope, tmp);
|
||||
delete tmp;
|
||||
}
|
||||
|
|
@ -1315,6 +1306,15 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
if (instance.size() != 1)
|
||||
desired_vector_width = 0;
|
||||
|
||||
if (!prts.empty() && (prts[0]->port_type() == NetNet::PINPUT)
|
||||
&& prts[0]->pin(0).nexus()->drivers_present()
|
||||
&& pins[idx]->is_collapsible_net(des, scope)) {
|
||||
prts[0]->port_type(NetNet::PINOUT);
|
||||
|
||||
cerr << pins[idx]->get_fileline() << ": warning: input port "
|
||||
<< prts[0]->name() << " is coerced to inout." << endl;
|
||||
}
|
||||
|
||||
// Elaborate the expression that connects to the
|
||||
// module[s] port. sig is the thing outside the module
|
||||
// that connects to the port.
|
||||
|
|
@ -1332,13 +1332,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
port is actually empty on the inside. We assume
|
||||
in that case that the port is input. */
|
||||
|
||||
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE;
|
||||
bool flag = false;
|
||||
pins[idx]->test_width(des, scope, 0, desired_vector_width,
|
||||
tmp_type, flag);
|
||||
NetExpr*tmp_expr = elab_and_eval(des, scope, pins[idx],
|
||||
desired_vector_width,
|
||||
desired_vector_width);
|
||||
NetExpr*tmp_expr = elab_and_eval(des, scope, pins[idx], -1);
|
||||
if (tmp_expr == 0) {
|
||||
cerr << pins[idx]->get_fileline()
|
||||
<< ": internal error: Port expression "
|
||||
|
|
@ -1411,8 +1405,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
<< "Inout port expression must support "
|
||||
<< "continuous assignment." << endl;
|
||||
cerr << pins[idx]->get_fileline() << ": : "
|
||||
<< "Port of " << rmod->mod_name()
|
||||
<< " is " << rmod->ports[idx]->name << endl;
|
||||
<< "Port " << rmod->ports[idx]->name << " of "
|
||||
<< rmod->mod_name() << " is connected to "
|
||||
<< *pins[idx] << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1457,8 +1452,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
<< "Output port expression must support "
|
||||
<< "continuous assignment." << endl;
|
||||
cerr << pins[idx]->get_fileline() << ": : "
|
||||
<< "Port of " << rmod->mod_name()
|
||||
<< " is " << rmod->ports[idx]->name << endl;
|
||||
<< "Port " << rmod->ports[idx]->name << " of "
|
||||
<< rmod->mod_name() << " is connected to "
|
||||
<< *pins[idx] << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1608,7 +1604,11 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
<< " high bits of the port."
|
||||
<< endl;
|
||||
} else {
|
||||
cerr << get_fileline() << ": : Padding ";
|
||||
if (prts[0]->port_type() == NetNet::PINPUT) {
|
||||
cerr << get_fileline() << ": : Pruning ";
|
||||
} else {
|
||||
cerr << get_fileline() << ": : Padding ";
|
||||
}
|
||||
if (as_signed) cerr << "(signed) ";
|
||||
cerr << (sig->vector_width()-prts_vector_width)
|
||||
<< " high bits of the expression."
|
||||
|
|
@ -1889,7 +1889,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
|
|||
if (pins[idx] == 0)
|
||||
continue;
|
||||
|
||||
NetExpr*expr_tmp = elab_and_eval(des, scope, pins[idx], 1, 1);
|
||||
NetExpr*expr_tmp = elab_and_eval(des, scope, pins[idx], 1);
|
||||
if (expr_tmp == 0) {
|
||||
cerr << "internal error: Expression too complicated "
|
||||
"for elaboration:" << *pins[idx] << endl;
|
||||
|
|
@ -2044,7 +2044,6 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
|
|||
*/
|
||||
static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
|
||||
{
|
||||
probe_expr_width(des, scope, expr);
|
||||
NetExpr*dex = elab_and_eval(des, scope, expr, -1);
|
||||
|
||||
/* Print a warning if we find default and `timescale based
|
||||
|
|
@ -2099,12 +2098,11 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
|
|||
|
||||
NetExpr*scal_val = new NetECReal(verireal(round));
|
||||
scal_val->set_line(*expr);
|
||||
dex = new NetEBMult('*', dex, scal_val);
|
||||
dex = new NetEBMult('*', dex, scal_val, 1, true);
|
||||
dex->set_line(*expr);
|
||||
|
||||
// Cast this part of the expression to an integer.
|
||||
dex = new NetECast('i', dex);
|
||||
dex->set_width(64);
|
||||
dex = new NetECast('i', dex, 64, false);
|
||||
dex->set_line(*expr);
|
||||
|
||||
// Now scale the integer value.
|
||||
|
|
@ -2115,8 +2113,7 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
|
|||
|
||||
scal_val = new NetEConst(verinum(scale, 64));
|
||||
scal_val->set_line(*expr);
|
||||
dex = new NetEBMult('*', dex, scal_val);
|
||||
dex->set_width(64);
|
||||
dex = new NetEBMult('*', dex, scal_val, 64, false);
|
||||
dex->set_line(*expr);
|
||||
} else {
|
||||
int shift = scope->time_unit() - des->get_precision();
|
||||
|
|
@ -2126,7 +2123,7 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
|
|||
|
||||
NetExpr*scal_val = new NetEConst(verinum(scale, 64));
|
||||
scal_val->set_line(*expr);
|
||||
dex = new NetEBMult('*', dex, scal_val);
|
||||
dex = new NetEBMult('*', dex, scal_val, 64, false);
|
||||
dex->set_line(*expr);
|
||||
}
|
||||
|
||||
|
|
@ -2174,17 +2171,6 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
if (delay || event_) {
|
||||
unsigned wid = count_lval_width(lv);
|
||||
|
||||
rv->set_width(wid);
|
||||
rv = pad_to_width(rv, wid, *this);
|
||||
|
||||
if (wid > rv->expr_width()) {
|
||||
cerr << get_fileline() << ": error: Unable to match "
|
||||
"expression width of " << rv->expr_width() <<
|
||||
" to l-value width of " << wid << "." << endl;
|
||||
//XXXX delete rv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::REG, wid);
|
||||
tmp->local_flag(true);
|
||||
|
|
@ -2219,6 +2205,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
return 0;
|
||||
}
|
||||
st = event_->elaborate(des, scope);
|
||||
st->set_line(*this);
|
||||
if (st == 0) {
|
||||
cerr << event_->get_fileline() << ": error: "
|
||||
"unable to elaborate event expression."
|
||||
|
|
@ -2244,12 +2231,15 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
// We need a repeat statement.
|
||||
} else {
|
||||
st = new NetRepeat(count, st);
|
||||
st->set_line(*this);
|
||||
}
|
||||
} else {
|
||||
st = new NetRepeat(count, st);
|
||||
st->set_line(*this);
|
||||
}
|
||||
} else {
|
||||
st = event_->elaborate_st(des, scope, a2);
|
||||
st->set_line(*this);
|
||||
if (st == 0) {
|
||||
cerr << event_->get_fileline() << ": error: "
|
||||
"unable to elaborate event expression."
|
||||
|
|
@ -2274,22 +2264,6 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
return bl;
|
||||
}
|
||||
|
||||
/* Based on the specific type of the l-value, do cleanup
|
||||
processing on the r-value. */
|
||||
if (rv->expr_type() == IVL_VT_REAL) {
|
||||
|
||||
// The r-value is a real. Casting will happen in the
|
||||
// code generator, so leave it.
|
||||
|
||||
} else {
|
||||
unsigned wid = count_lval_width(lv);
|
||||
if (wid > rv->expr_width()) {
|
||||
rv->set_width(wid);
|
||||
rv = pad_to_width(rv, wid, *this);
|
||||
}
|
||||
ivl_assert(*this, rv->expr_width() >= wid);
|
||||
}
|
||||
|
||||
if (lv->expr_type() == IVL_VT_BOOL && rv->expr_type() != IVL_VT_BOOL) {
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: Cast expression to int2" << endl;
|
||||
|
|
@ -2301,7 +2275,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
<< "Enumeration type mismatch in assignment." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
|
||||
NetAssign*cur = new NetAssign(lv, rv);
|
||||
cur->set_line(*this);
|
||||
|
||||
|
|
@ -2340,20 +2314,6 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
|
|||
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
|
||||
if (rv == 0) return 0;
|
||||
|
||||
/* Handle the (common) case that the r-value is a vector. This
|
||||
includes just about everything but reals. In this case, we
|
||||
need to pad the r-value to match the width of the l-value.
|
||||
|
||||
If in this case the l-val is a variable (i.e., real) then
|
||||
the width to pad to will be 0, so this code is harmless. */
|
||||
if (rv->expr_type() == IVL_VT_REAL) {
|
||||
|
||||
} else {
|
||||
unsigned wid = count_lval_width(lv);
|
||||
rv->set_width(wid);
|
||||
rv = pad_to_width(rv, wid, *this);
|
||||
}
|
||||
|
||||
NetExpr*delay = 0;
|
||||
if (delay_ != 0) {
|
||||
assert(count_ == 0 && event_ == 0);
|
||||
|
|
@ -2505,7 +2465,6 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
|||
{
|
||||
assert(scope);
|
||||
|
||||
probe_expr_width(des, scope, expr_);
|
||||
NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
|
||||
if (expr == 0) {
|
||||
cerr << get_fileline() << ": error: Unable to elaborate this case"
|
||||
|
|
@ -2560,7 +2519,6 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
|||
NetExpr*gu = 0;
|
||||
NetProc*st = 0;
|
||||
assert(cur_expr);
|
||||
probe_expr_width(des, scope, cur_expr);
|
||||
gu = elab_and_eval(des, scope, cur_expr, -1);
|
||||
|
||||
if (cur->stat)
|
||||
|
|
@ -2583,7 +2541,6 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
|
|||
<< " with conditional: " << *expr_ << endl;
|
||||
|
||||
// Elaborate and try to evaluate the conditional expression.
|
||||
probe_expr_width(des, scope, expr_);
|
||||
NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
|
||||
if (expr == 0) {
|
||||
cerr << get_fileline() << ": error: Unable to elaborate"
|
||||
|
|
@ -2699,29 +2656,12 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
|
|||
|
||||
svector<NetExpr*>eparms (parm_count);
|
||||
|
||||
perm_string name = peek_tail_name(path_);
|
||||
|
||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
PExpr*ex = parm(idx);
|
||||
if (ex != 0) {
|
||||
ivl_variable_type_t use_type;
|
||||
bool flag = false;
|
||||
int use_wid = ex->test_width(des,scope,0,0, use_type, flag);
|
||||
if (debug_elaborate)
|
||||
cerr << ex->get_fileline() << ": debug: "
|
||||
<< "Argument " << (idx+1)
|
||||
<< " of system task tests its width as " << use_wid
|
||||
<< ", type=" << use_type
|
||||
<< ", unsized_flag=" << flag << endl;
|
||||
|
||||
// If the argument expression is unsized, then
|
||||
// elaborate as self-determined *lossless* instead
|
||||
// of sized.
|
||||
if (flag==true)
|
||||
use_wid = -2;
|
||||
|
||||
eparms[idx] = ex->elaborate_expr(des, scope, use_wid, true);
|
||||
if (eparms[idx])
|
||||
eval_expr(eparms[idx]);
|
||||
|
||||
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
|
||||
} else {
|
||||
eparms[idx] = 0;
|
||||
}
|
||||
|
|
@ -2731,8 +2671,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
|
|||
// $sdf_annotate system task. There will be nothing for $sdf
|
||||
// to annotate, and the user is intending to turn the behavior
|
||||
// off anyhow, so replace the system task invocation with a no-op.
|
||||
if (gn_specify_blocks_flag == false
|
||||
&& peek_tail_name(path_) == "$sdf_annotate") {
|
||||
if (gn_specify_blocks_flag == false && name == "$sdf_annotate") {
|
||||
|
||||
cerr << get_fileline() << ": warning: Omitting $sdf_annotate() "
|
||||
<< "since specify blocks are being omitted." << endl;
|
||||
|
|
@ -2741,8 +2680,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
|
|||
return noop;
|
||||
}
|
||||
|
||||
NetSTask*cur = new NetSTask(peek_tail_name(path_), def_sfunc_as_task,
|
||||
eparms);
|
||||
NetSTask*cur = new NetSTask(name, def_sfunc_as_task, eparms);
|
||||
cur->set_line(*this);
|
||||
return cur;
|
||||
}
|
||||
|
|
@ -2869,11 +2807,6 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
|||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
if (wid > rv->expr_width()) {
|
||||
rv->set_width(wid);
|
||||
rv = pad_to_width(rv, wid, *this);
|
||||
}
|
||||
ivl_assert(*this, rv->expr_width() >= wid);
|
||||
|
||||
NetAssign*pr = new NetAssign(lv, rv);
|
||||
pr->set_line(*this);
|
||||
|
|
@ -2986,9 +2919,6 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
|
|||
if (rexp == 0)
|
||||
return 0;
|
||||
|
||||
rexp->set_width(lwid);
|
||||
rexp = pad_to_width(rexp, lwid, *this);
|
||||
|
||||
dev = new NetCAssign(lval, rexp);
|
||||
|
||||
if (debug_elaborate) {
|
||||
|
|
@ -3304,8 +3234,7 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
|
|||
}
|
||||
}
|
||||
|
||||
probe_expr_width(des, scope, expr_[idx]->expr());
|
||||
NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), 0);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), -1);
|
||||
if (tmp == 0) {
|
||||
expr_[idx]->dump(cerr);
|
||||
cerr << endl;
|
||||
|
|
@ -3407,8 +3336,9 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
|
|||
/* Elaborate wait expression. Don't eval yet, we will do that
|
||||
shortly, after we apply a reduction or. */
|
||||
|
||||
probe_expr_width(des, scope, pe);
|
||||
NetExpr*expr = pe->elaborate_expr(des, scope, -1, false);
|
||||
PExpr::width_mode_t mode;
|
||||
pe->test_width(des, scope, mode);
|
||||
NetExpr*expr = pe->elaborate_expr(des, scope, pe->expr_width(), false);
|
||||
if (expr == 0) {
|
||||
cerr << get_fileline() << ": error: Unable to elaborate"
|
||||
" wait condition expression." << endl;
|
||||
|
|
@ -3570,7 +3500,7 @@ NetProc* PForever::elaborate(Design*des, NetScope*scope) const
|
|||
* force <lval> = <rval>
|
||||
*
|
||||
* The <lval> can be anything that a normal behavioral assignment can
|
||||
* take, plus net signals. This is a little bit more lax then the
|
||||
* take, plus net signals. This is a little bit more lax than the
|
||||
* other procedural assignments.
|
||||
*/
|
||||
NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
||||
|
|
@ -3605,9 +3535,6 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
|||
if (rexp == 0)
|
||||
return 0;
|
||||
|
||||
rexp->set_width(lwid, true);
|
||||
rexp = pad_to_width(rexp, lwid, *this);
|
||||
|
||||
if (ltype==IVL_VT_BOOL && rexp->expr_type()!=IVL_VT_BOOL) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
|
|
@ -3668,32 +3595,14 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
|||
assert(sig);
|
||||
NetAssign_*lv = new NetAssign_(sig);
|
||||
|
||||
/* Calculate the width of the initialization as if this were
|
||||
any other assignment statement. */
|
||||
unsigned use_width = lv->lwidth();
|
||||
bool unsized_flag = false;
|
||||
ivl_variable_type_t expr1_type = IVL_VT_NO_TYPE;
|
||||
use_width = expr1_->test_width(des, scope, use_width, use_width, expr1_type, unsized_flag);
|
||||
|
||||
/* Make the r-value of the initial assignment, and size it
|
||||
properly. Then use it to build the assignment statement. */
|
||||
etmp = elab_and_eval(des, scope, expr1_, use_width);
|
||||
etmp->set_width(use_width);
|
||||
etmp = pad_to_width(etmp, use_width, *this);
|
||||
etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(),
|
||||
expr1_);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: FOR initial assign: "
|
||||
<< sig->name() << " = " << *etmp << endl;
|
||||
assert(etmp->expr_width() >= lv->lwidth());
|
||||
}
|
||||
|
||||
/* Based on the specific type of the l-value, do cleanup
|
||||
processing on the r-value. */
|
||||
if (etmp->expr_type() != IVL_VT_REAL) {
|
||||
unsigned wid = count_lval_width(lv);
|
||||
etmp->set_width(wid);
|
||||
etmp = pad_to_width(etmp, wid, *this);
|
||||
assert(etmp->expr_width() >= wid);
|
||||
}
|
||||
|
||||
NetAssign*init = new NetAssign(lv, etmp);
|
||||
|
|
@ -3727,9 +3636,16 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
|||
assert(sig);
|
||||
lv = new NetAssign_(sig);
|
||||
|
||||
/* Make the rvalue of the increment expression, and size it
|
||||
for the lvalue. */
|
||||
etmp = elab_and_eval(des, scope, expr2_, lv->lwidth());
|
||||
/* Make the r-value of the increment assignment, and size it
|
||||
properly. Then use it to build the assignment statement. */
|
||||
etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(),
|
||||
expr2_);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: FOR increment assign: "
|
||||
<< sig->name() << " = " << *etmp << endl;
|
||||
}
|
||||
|
||||
NetAssign*step = new NetAssign(lv, etmp);
|
||||
step->set_line(*this);
|
||||
|
||||
|
|
@ -3739,7 +3655,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
|||
/* Elaborate the condition expression. Try to evaluate it too,
|
||||
in case it is a constant. This is an interesting case
|
||||
worthy of a warning. */
|
||||
probe_expr_width(des, scope, cond_);
|
||||
NetExpr*ce = elab_and_eval(des, scope, cond_, -1);
|
||||
if (ce == 0) {
|
||||
delete top;
|
||||
|
|
@ -3830,7 +3745,6 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const
|
|||
{
|
||||
assert(scope);
|
||||
|
||||
probe_expr_width(des, scope, expr_);
|
||||
NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
|
||||
if (expr == 0) {
|
||||
cerr << get_fileline() << ": Unable to elaborate"
|
||||
|
|
@ -3954,9 +3868,10 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const
|
|||
*/
|
||||
NetProc* PWhile::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
probe_expr_width(des, scope, cond_);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, cond_, -1);
|
||||
tmp->set_line(*this);
|
||||
NetWhile*loop = new NetWhile(tmp, statement_->elaborate(des, scope));
|
||||
loop->set_line(*this);
|
||||
return loop;
|
||||
}
|
||||
|
||||
|
|
@ -4057,8 +3972,7 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
|||
them for the timescale/precision of the scope. */
|
||||
for (unsigned idx = 0 ; idx < ndelays ; idx += 1) {
|
||||
PExpr*exp = delays[idx];
|
||||
probe_expr_width(des, scope, exp);
|
||||
NetExpr*cur = elab_and_eval(des, scope, exp, 0);
|
||||
NetExpr*cur = elab_and_eval(des, scope, exp, -1);
|
||||
|
||||
if (NetEConst*con = dynamic_cast<NetEConst*> (cur)) {
|
||||
verinum fn = con->value();
|
||||
|
|
@ -4096,7 +4010,6 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
|||
NetNet*condit_sig = 0;
|
||||
if (conditional && condition) {
|
||||
|
||||
probe_expr_width(des, scope, condition);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, condition, -1);
|
||||
ivl_assert(*condition, tmp);
|
||||
|
||||
|
|
@ -4253,7 +4166,6 @@ bool Module::elaborate(Design*des, NetScope*scope) const
|
|||
for (specparam_it_t cur = specparams.begin()
|
||||
; cur != specparams.end() ; ++ cur ) {
|
||||
|
||||
probe_expr_width(des, scope, (*cur).second);
|
||||
need_constant_expr = true;
|
||||
NetExpr*val = elab_and_eval(des, scope, (*cur).second, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2008,2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -28,8 +28,6 @@
|
|||
|
||||
NetProc* AContrib::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
probe_expr_width(des, scope, lval_);
|
||||
probe_expr_width(des, scope, rval_);
|
||||
NetExpr*lval = elab_and_eval(des, scope, lval_, -1);
|
||||
NetExpr*rval = elab_and_eval(des, scope, rval_, -1);
|
||||
|
||||
|
|
|
|||
1
emit.cc
1
emit.cc
|
|
@ -409,6 +409,7 @@ void NetScope::emit_scope(struct target_t*tgt) const
|
|||
tgt->signal_paths(cur->second);
|
||||
}
|
||||
|
||||
if (type_ == MODULE) tgt->convert_module_ports(this);
|
||||
}
|
||||
|
||||
bool NetScope::emit_defs(struct target_t*tgt) const
|
||||
|
|
|
|||
326
eval_tree.cc
326
eval_tree.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
# include "ivl_assert.h"
|
||||
# include "netmisc.h"
|
||||
|
||||
NetExpr* NetExpr::eval_tree(int)
|
||||
NetExpr* NetExpr::eval_tree()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -114,12 +114,12 @@ NetECReal* NetEBAdd::eval_tree_real_()
|
|||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
||||
NetExpr* NetEBAdd::eval_tree()
|
||||
{
|
||||
eval_expr(left_, prune_to_width);
|
||||
eval_expr(right_, prune_to_width);
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
||||
if (left_->expr_type() == IVL_VT_REAL || right_->expr_type()==IVL_VT_REAL)
|
||||
if (expr_type() == IVL_VT_REAL)
|
||||
return eval_tree_real_();
|
||||
|
||||
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
|
||||
|
|
@ -131,33 +131,23 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
unsigned wid = expr_width();
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lval.len() == wid);
|
||||
ivl_assert(*this, rval.len() == wid);
|
||||
|
||||
verinum val;
|
||||
switch (op_) {
|
||||
case '+':
|
||||
val = lval + rval;
|
||||
val = verinum(lval + rval, wid);
|
||||
break;
|
||||
case '-':
|
||||
val = lval - rval;
|
||||
val = verinum(lval - rval, wid);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Result might have known width. */
|
||||
if (has_width()) {
|
||||
unsigned lwid = lc->expr_width();
|
||||
unsigned rwid = rc->expr_width();
|
||||
unsigned wid = (rwid > lwid) ? rwid : lwid;
|
||||
if (prune_to_width < 0)
|
||||
wid += 1;
|
||||
verinum val2=verinum(val,wid);
|
||||
val=val2;
|
||||
} else {
|
||||
/* No fixed width, so trim the bits losslessly. */
|
||||
verinum val2 = trim_vnum(val);
|
||||
val = val2;
|
||||
}
|
||||
|
||||
NetEConst *res = new NetEConst(val);
|
||||
ivl_assert(*this, res);
|
||||
res->set_line(*this);
|
||||
|
|
@ -188,37 +178,20 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
if (lval.len() < expr_width())
|
||||
lval = pad_to_width(lval, expr_width());
|
||||
if (rval.len() < expr_width())
|
||||
rval = pad_to_width(rval, expr_width());
|
||||
|
||||
if (se->expr_width() > this->expr_width()) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "expr_width()=" << expr_width()
|
||||
<< ", sub expr_width()=" << se->expr_width()
|
||||
<< ", sub expression=" << *se << endl;
|
||||
}
|
||||
ivl_assert(*this, se->expr_width() <= this->expr_width());
|
||||
unsigned wid = expr_width();
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lval.len() == wid);
|
||||
ivl_assert(*this, rval.len() == wid);
|
||||
|
||||
verinum val;
|
||||
if (op_ == se->op_) {
|
||||
/* (a + lval) + rval --> a + (rval+lval) */
|
||||
/* (a - lval) - rval --> a - (rval+lval) */
|
||||
val = rval + lval;
|
||||
val = verinum(rval + lval, wid);
|
||||
} else {
|
||||
/* (a - lval) + rval --> a + (rval-lval) */
|
||||
/* (a + lval) - rval --> a - (rval-lval) */
|
||||
val = rval - lval;
|
||||
}
|
||||
|
||||
// Since we padded the operands above to be the minimum
|
||||
// width, the val should also be at least expr_width().
|
||||
ivl_assert(*this, val.len() >= expr_width());
|
||||
if (val.len() > expr_width()) {
|
||||
verinum tmp (val, expr_width());
|
||||
tmp.has_sign(val.has_sign());
|
||||
val = tmp;
|
||||
val = verinum(rval - lval, wid);
|
||||
}
|
||||
|
||||
NetEConst*tmp = new NetEConst(val);
|
||||
|
|
@ -236,15 +209,15 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetEConst* NetEBBits::eval_tree(int prune_to_width)
|
||||
NetEConst* NetEBBits::eval_tree()
|
||||
{
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluating expression:"
|
||||
<< *this << ", prune_to_width=" << prune_to_width << endl;
|
||||
<< *this << endl;
|
||||
}
|
||||
|
||||
eval_expr(left_, prune_to_width);
|
||||
eval_expr(right_, prune_to_width);
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
||||
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
|
||||
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
|
||||
|
|
@ -266,79 +239,33 @@ NetEConst* NetEBBits::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
unsigned lwid = lc->expr_width();
|
||||
if (lwid == 0) lwid = lval.len();
|
||||
|
||||
unsigned rwid = rc->expr_width();
|
||||
if (rwid == 0) rwid = rval.len();
|
||||
|
||||
unsigned wid = expr_width();
|
||||
if (wid == 0)
|
||||
wid = (rwid > lwid)? rwid : lwid;
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lval.len() == wid);
|
||||
ivl_assert(*this, rval.len() == wid);
|
||||
|
||||
verinum res (verinum::V0, wid);
|
||||
|
||||
if (lwid > wid)
|
||||
lwid = wid;
|
||||
if (rwid > wid)
|
||||
rwid = wid;
|
||||
|
||||
// Sub-expressions of bitwise operators need to be the same
|
||||
// width. Pad them out if necessary.
|
||||
if (lwid < wid) {
|
||||
lval = pad_to_width(lval, wid);
|
||||
lwid = wid;
|
||||
}
|
||||
if (rwid < wid) {
|
||||
rval = pad_to_width(rval, wid);
|
||||
rwid = wid;
|
||||
}
|
||||
|
||||
switch (op()) {
|
||||
|
||||
case '|': {
|
||||
unsigned cnt = lwid;
|
||||
if (cnt > wid) cnt = wid;
|
||||
if (cnt > rwid) cnt = rwid;
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
res.set(idx, lval.get(idx) | rval.get(idx));
|
||||
|
||||
if (lwid < rwid)
|
||||
for (unsigned idx = lwid ; idx < rwid ; idx += 1)
|
||||
res.set(idx, rval.get(idx));
|
||||
|
||||
if (rwid < lwid)
|
||||
for (unsigned idx = rwid ; idx < lwid ; idx += 1)
|
||||
res.set(idx, lval.get(idx));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case '&': {
|
||||
unsigned cnt = lwid;
|
||||
if (cnt > wid) cnt = wid;
|
||||
if (cnt > rwid) cnt = rwid;
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
res.set(idx, lval.get(idx) & rval.get(idx));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case '^': {
|
||||
unsigned cnt = lwid;
|
||||
if (cnt > wid) cnt = wid;
|
||||
if (cnt > rwid) cnt = rwid;
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
res.set(idx, lval.get(idx) ^ rval.get(idx));
|
||||
|
||||
if (lwid < rwid)
|
||||
for (unsigned idx = lwid ; idx < rwid ; idx += 1)
|
||||
res.set(idx, rval.get(idx));
|
||||
|
||||
if (rwid < lwid)
|
||||
for (unsigned idx = rwid ; idx < lwid ; idx += 1)
|
||||
res.set(idx, lval.get(idx));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -761,7 +688,7 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag)
|
|||
return result;
|
||||
}
|
||||
|
||||
NetEConst* NetEBComp::eval_tree(int)
|
||||
NetEConst* NetEBComp::eval_tree()
|
||||
{
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
|
@ -850,11 +777,8 @@ NetExpr* NetEBDiv::eval_tree_real_()
|
|||
* The NetEBDiv operator includes the / and % operators. First evaluate
|
||||
* the sub-expressions, then perform the required operation.
|
||||
*/
|
||||
NetExpr* NetEBDiv::eval_tree(int prune_to_width)
|
||||
NetExpr* NetEBDiv::eval_tree()
|
||||
{
|
||||
// assert(prune_to_width <= 0);
|
||||
// HERE
|
||||
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
||||
|
|
@ -865,20 +789,26 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
|
|||
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
|
||||
if (lc == 0 || rc == 0) return 0;
|
||||
|
||||
// Make sure the expression is evaluated at the
|
||||
// expression width.
|
||||
verinum lval = pad_to_width(lc->value(), expr_width());
|
||||
verinum rval = pad_to_width(rc->value(), expr_width());
|
||||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
NetExpr*tmp = 0;
|
||||
unsigned wid = expr_width();
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lval.len() == wid);
|
||||
ivl_assert(*this, rval.len() == wid);
|
||||
|
||||
verinum val;
|
||||
switch (op_) {
|
||||
case '/':
|
||||
tmp = new NetEConst(lval / rval);
|
||||
val = verinum(lval / rval, wid);
|
||||
break;
|
||||
case '%':
|
||||
tmp = new NetEConst(lval % rval);
|
||||
val = verinum(lval % rval, wid);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
NetExpr*tmp = new NetEConst(val);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
|
||||
|
|
@ -928,7 +858,7 @@ NetEConst* NetEBLogic::eval_tree_real_()
|
|||
return tmp;
|
||||
}
|
||||
|
||||
NetEConst* NetEBLogic::eval_tree(int)
|
||||
NetEConst* NetEBLogic::eval_tree()
|
||||
{
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
|
@ -1024,11 +954,8 @@ NetExpr* NetEBMult::eval_tree_real_()
|
|||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEBMult::eval_tree(int prune_to_width)
|
||||
NetExpr* NetEBMult::eval_tree()
|
||||
{
|
||||
// assert(prune_to_width <= 0);
|
||||
// HERE
|
||||
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
||||
|
|
@ -1042,7 +969,13 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
NetEConst*tmp = new NetEConst(lval * rval);
|
||||
unsigned wid = expr_width();
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lval.len() == wid);
|
||||
ivl_assert(*this, rval.len() == wid);
|
||||
|
||||
verinum val(lval * rval, wid);
|
||||
NetEConst*tmp = new NetEConst(val);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
|
||||
|
|
@ -1072,11 +1005,8 @@ NetExpr* NetEBPow::eval_tree_real_()
|
|||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEBPow::eval_tree(int prune_to_width)
|
||||
NetExpr* NetEBPow::eval_tree()
|
||||
{
|
||||
// assert(prune_to_width <= 0);
|
||||
// HERE
|
||||
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
||||
|
|
@ -1090,7 +1020,12 @@ NetExpr* NetEBPow::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
NetEConst*res = new NetEConst( pow(lval,rval) );
|
||||
unsigned wid = expr_width();
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lval.len() == wid);
|
||||
|
||||
verinum val(pow(lval, rval), wid);
|
||||
NetEConst*res = new NetEConst(val);
|
||||
ivl_assert(*this, res);
|
||||
res->set_line(*this);
|
||||
|
||||
|
|
@ -1105,7 +1040,7 @@ NetExpr* NetEBPow::eval_tree(int prune_to_width)
|
|||
* Evaluate the shift operator if possible. For this to work, both
|
||||
* operands must be constant.
|
||||
*/
|
||||
NetEConst* NetEBShift::eval_tree(int prune_to_width)
|
||||
NetEConst* NetEBShift::eval_tree()
|
||||
{
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
|
@ -1116,87 +1051,44 @@ NetEConst* NetEBShift::eval_tree(int prune_to_width)
|
|||
|
||||
NetEConst*res;
|
||||
|
||||
verinum rv = re->value();
|
||||
verinum lv = le->value();
|
||||
verinum rv = re->value();
|
||||
|
||||
/* Make an early estimate of the expression width. */
|
||||
unsigned wid = expr_width();
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lv.len() == wid);
|
||||
|
||||
verinum val;
|
||||
if (rv.is_defined()) {
|
||||
|
||||
unsigned shift = rv.as_ulong();
|
||||
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Evaluate " << lv << "<<" << op() << ">> "
|
||||
<< rv << ", wid=" << wid << ", shift=" << shift
|
||||
<< ", lv.has_len()=" << lv.has_len() << endl;
|
||||
switch (op_) {
|
||||
case 'l':
|
||||
val = verinum(lv << shift, wid);
|
||||
break;
|
||||
case 'r':
|
||||
lv.has_sign(false);
|
||||
case 'R':
|
||||
val = verinum(lv >> shift, wid);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((wid == 0) || ! lv.has_len()) {
|
||||
/* If the caller doesn't care what the width is,
|
||||
then calculate a width from the trimmed left
|
||||
expression, plus the shift. This avoids
|
||||
data loss. */
|
||||
lv = trim_vnum(lv);
|
||||
wid = lv.len();
|
||||
if (op() == 'l')
|
||||
wid = lv.len() + shift;
|
||||
}
|
||||
|
||||
if (prune_to_width > 0 && wid > (unsigned)prune_to_width)
|
||||
wid = prune_to_width;
|
||||
|
||||
assert(wid > 0);
|
||||
verinum::V pad = verinum::V0;
|
||||
if (op() == 'R' && has_sign()) {
|
||||
pad = lv[lv.len()-1];
|
||||
}
|
||||
verinum nv (pad, wid, lv.has_len());
|
||||
|
||||
if (op() == 'r' || op() == 'R') {
|
||||
unsigned cnt = wid;
|
||||
if (cnt > nv.len())
|
||||
cnt = nv.len();
|
||||
if (shift >= lv.len())
|
||||
cnt = 0;
|
||||
else if (cnt > (lv.len()-shift))
|
||||
cnt = (lv.len()-shift);
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
||||
nv.set(idx, lv[idx+shift]);
|
||||
|
||||
} else {
|
||||
unsigned cnt = wid;
|
||||
if (cnt > lv.len())
|
||||
cnt = lv.len();
|
||||
if (shift >= nv.len())
|
||||
cnt = 0;
|
||||
else if (cnt > (nv.len()-shift))
|
||||
cnt = nv.len() - shift;
|
||||
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
||||
nv.set(idx+shift, lv[idx]);
|
||||
}
|
||||
|
||||
res = new NetEConst(nv);
|
||||
|
||||
} else {
|
||||
if (wid == 0) wid = left_->expr_width();
|
||||
|
||||
if (prune_to_width > 0 && wid > (unsigned)prune_to_width)
|
||||
wid = prune_to_width;
|
||||
|
||||
assert(wid > 0);
|
||||
verinum nv (verinum::Vx, wid);
|
||||
res = new NetEConst(nv);
|
||||
val = verinum(verinum::Vx, wid);
|
||||
}
|
||||
|
||||
val.has_sign(has_sign());
|
||||
res = new NetEConst(val);
|
||||
res->set_line(*this);
|
||||
|
||||
if (debug_eval_tree)
|
||||
cerr << get_fileline() << ": debug: Evaluated: " << *this
|
||||
<< " --> " << *res << endl;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetEConcat::eval_tree(int prune_to_width)
|
||||
NetEConst* NetEConcat::eval_tree()
|
||||
{
|
||||
// HERE
|
||||
unsigned repeat_val = repeat();
|
||||
|
|
@ -1204,7 +1096,7 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
|
|||
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluating expression:"
|
||||
<< *this << ", prune_to_width=" << prune_to_width << endl;
|
||||
<< *this << endl;
|
||||
}
|
||||
|
||||
unsigned gap = 0;
|
||||
|
|
@ -1225,7 +1117,7 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
|
|||
// that is here. If I succeed, reset the parameter to
|
||||
// the evaluated value.
|
||||
assert(parms_[idx]);
|
||||
NetExpr*expr = parms_[idx]->eval_tree(0);
|
||||
NetExpr*expr = parms_[idx]->eval_tree();
|
||||
if (expr) {
|
||||
expr->set_line(*parms_[idx]);
|
||||
delete parms_[idx];
|
||||
|
|
@ -1285,16 +1177,15 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
|
|||
val.has_sign( this->has_sign() );
|
||||
|
||||
NetEConst*res = new NetEConst(val);
|
||||
res->set_width(val.len());
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESelect::eval_tree(int prune_to_width)
|
||||
NetEConst* NetESelect::eval_tree()
|
||||
{
|
||||
// HERE
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluating expression:"
|
||||
<< *this << ", prune_to_width=" << prune_to_width << endl;
|
||||
<< *this << endl;
|
||||
}
|
||||
|
||||
eval_expr(expr_);
|
||||
|
|
@ -1318,14 +1209,12 @@ NetEConst* NetESelect::eval_tree(int prune_to_width)
|
|||
verinum::V pad_bit = verinum::Vx;
|
||||
if (base_ == 0) {
|
||||
|
||||
/* If the base is NULL (different from 0) the this
|
||||
select is here for sign extension. So calculate a
|
||||
proper pad bit. Extend x or z or 0, and sign extend 1
|
||||
if this is signed. */
|
||||
unsigned top = expr->expr_width()-1;
|
||||
|
||||
pad_bit = eval.get(top);
|
||||
if (pad_bit==verinum::V1 && !has_sign())
|
||||
/* If the base is NULL (different from 0) then this
|
||||
select is here for zero or sign extension. So
|
||||
calculate a proper pad bit. */
|
||||
if (has_sign())
|
||||
pad_bit = eval.get(expr->expr_width()-1);
|
||||
else
|
||||
pad_bit = verinum::V0;
|
||||
}
|
||||
|
||||
|
|
@ -1365,12 +1254,12 @@ static void print_ternary_cond(NetExpr*expr)
|
|||
* evaluates to x or z, then merge the constant bits of the true and
|
||||
* false expressions.
|
||||
*/
|
||||
NetExpr* NetETernary::eval_tree(int prune_to_width)
|
||||
NetExpr* NetETernary::eval_tree()
|
||||
{
|
||||
eval_expr(cond_);
|
||||
switch (const_logical(cond_)) {
|
||||
case C_0:
|
||||
eval_expr(false_val_, prune_to_width);
|
||||
eval_expr(false_val_);
|
||||
if (debug_eval_tree) {
|
||||
|
||||
cerr << get_fileline() << ": debug: Evaluate ternary with "
|
||||
|
|
@ -1393,7 +1282,7 @@ NetExpr* NetETernary::eval_tree(int prune_to_width)
|
|||
return false_val_->dup_expr();
|
||||
|
||||
case C_1:
|
||||
eval_expr(true_val_, prune_to_width);
|
||||
eval_expr(true_val_);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluate ternary with "
|
||||
<< "constant condition value: ";
|
||||
|
|
@ -1425,8 +1314,8 @@ NetExpr* NetETernary::eval_tree(int prune_to_width)
|
|||
expressions down to constants then compare the values to
|
||||
build up a constant result. */
|
||||
|
||||
eval_expr(true_val_, prune_to_width);
|
||||
eval_expr(false_val_, prune_to_width);
|
||||
eval_expr(true_val_);
|
||||
eval_expr(false_val_);
|
||||
|
||||
NetEConst*t = dynamic_cast<NetEConst*>(true_val_);
|
||||
NetEConst*f = dynamic_cast<NetEConst*>(false_val_);
|
||||
|
|
@ -1509,7 +1398,7 @@ NetExpr* NetEUnary::eval_tree_real_()
|
|||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEUnary::eval_tree(int prune_to_width)
|
||||
NetExpr* NetEUnary::eval_tree()
|
||||
{
|
||||
eval_expr(expr_);
|
||||
if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
|
||||
|
|
@ -1529,7 +1418,7 @@ NetExpr* NetEUnary::eval_tree(int prune_to_width)
|
|||
if (val.is_defined()) {
|
||||
verinum tmp (verinum::V0, val.len());
|
||||
tmp.has_sign(val.has_sign());
|
||||
val = tmp - val;
|
||||
val = verinum(tmp - val, val.len());
|
||||
} else {
|
||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
||||
val.set(idx, verinum::Vx);
|
||||
|
|
@ -1537,7 +1426,7 @@ NetExpr* NetEUnary::eval_tree(int prune_to_width)
|
|||
break;
|
||||
|
||||
case '~':
|
||||
/* Bitwise not is even simpler then logical
|
||||
/* Bitwise not is even simpler than logical
|
||||
not. Just invert all the bits of the operand and
|
||||
make the new value with the same dimensions. */
|
||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
||||
|
|
@ -1572,9 +1461,9 @@ NetExpr* NetEUnary::eval_tree(int prune_to_width)
|
|||
}
|
||||
|
||||
|
||||
NetExpr* NetEUBits::eval_tree(int prune_to_width)
|
||||
NetExpr* NetEUBits::eval_tree()
|
||||
{
|
||||
return NetEUnary::eval_tree(prune_to_width);
|
||||
return NetEUnary::eval_tree();
|
||||
}
|
||||
|
||||
NetEConst* NetEUReduce::eval_tree_real_()
|
||||
|
|
@ -1598,7 +1487,7 @@ NetEConst* NetEUReduce::eval_tree_real_()
|
|||
return tmp;
|
||||
}
|
||||
|
||||
NetEConst* NetEUReduce::eval_tree(int)
|
||||
NetEConst* NetEUReduce::eval_tree()
|
||||
{
|
||||
eval_expr(expr_);
|
||||
if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
|
||||
|
|
@ -1955,9 +1844,8 @@ static NetExpr* evaluate_min_max(NetExpr*&arg0_, NetExpr*&arg1_,
|
|||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
||||
NetExpr* NetESFunc::eval_tree()
|
||||
{
|
||||
// assert(prune_to_width <= 0);
|
||||
// HERE
|
||||
/* If we are not targeting at least Verilog-2005, Verilog-AMS
|
||||
* or using the Icarus misc flag then we do not support these
|
||||
|
|
@ -2056,7 +1944,7 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
|||
return rtn;
|
||||
}
|
||||
|
||||
NetExpr* NetEUFunc::eval_tree(int)
|
||||
NetExpr* NetEUFunc::eval_tree()
|
||||
{
|
||||
if (need_constant_expr) {
|
||||
cerr << get_fileline() << ": sorry: constant user "
|
||||
|
|
|
|||
|
|
@ -285,12 +285,12 @@ One might note that the quote from section 4.1.14 says "Unsized
|
|||
expressions...", so arguably accepting (15+1) or even (16+0) as an
|
||||
operand to a concatenation is not a violation of the letter of the
|
||||
law. However, the very next sentence of the quote expresses the
|
||||
intent, and accepting (15+1) as having a more defined size then (16)
|
||||
intent, and accepting (15+1) as having a more defined size taen (16)
|
||||
seems to be a violation of that intent.
|
||||
|
||||
Whatever a compiler decides the size is, the user has no way to
|
||||
predict it, and the compiler should not have the right to treat (15+1)
|
||||
any differently then (16). Therefore, Icarus Verilog takes the
|
||||
any differently than (16). Therefore, Icarus Verilog takes the
|
||||
position that such expressions are *unsized* and are not allowed as
|
||||
operands to concatenations. Icarus Verilog will in general assume that
|
||||
operations on unsized numbers produce unsized results. There are
|
||||
|
|
|
|||
4
ivl.def
4
ivl.def
|
|
@ -68,6 +68,7 @@ ivl_expr_parm
|
|||
ivl_expr_parms
|
||||
ivl_expr_repeat
|
||||
ivl_expr_scope
|
||||
ivl_expr_sel_type
|
||||
ivl_expr_signal
|
||||
ivl_expr_signed
|
||||
ivl_expr_sized
|
||||
|
|
@ -134,6 +135,7 @@ ivl_lpm_width
|
|||
ivl_lval_idx
|
||||
ivl_lval_mux
|
||||
ivl_lval_part_off
|
||||
ivl_lval_sel_type
|
||||
ivl_lval_sig
|
||||
ivl_lval_width
|
||||
|
||||
|
|
@ -187,6 +189,7 @@ ivl_scope_logs
|
|||
ivl_scope_log
|
||||
ivl_scope_lpms
|
||||
ivl_scope_lpm
|
||||
ivl_scope_mod_port
|
||||
ivl_scope_name
|
||||
ivl_scope_param
|
||||
ivl_scope_params
|
||||
|
|
@ -288,6 +291,7 @@ ivl_udp_file
|
|||
ivl_udp_lineno
|
||||
ivl_udp_name
|
||||
ivl_udp_nin
|
||||
ivl_udp_port
|
||||
ivl_udp_row
|
||||
ivl_udp_rows
|
||||
ivl_udp_sequ
|
||||
|
|
|
|||
11
ivl_target.h
11
ivl_target.h
|
|
@ -229,6 +229,12 @@ typedef enum ivl_expr_type_e {
|
|||
IVL_EX_UNARY = 14
|
||||
} ivl_expr_type_t;
|
||||
|
||||
typedef enum ivl_select_type_e {
|
||||
IVL_SEL_OTHER = 0,
|
||||
IVL_SEL_IDX_UP = 1,
|
||||
IVL_SEL_IDX_DOWN = 2
|
||||
} ivl_select_type_t;
|
||||
|
||||
/* This is the type code for an ivl_net_logic_t object. */
|
||||
typedef enum ivl_logic_e {
|
||||
IVL_LO_NONE = 0,
|
||||
|
|
@ -844,6 +850,8 @@ extern ivl_expr_t ivl_expr_parm(ivl_expr_t net, unsigned idx);
|
|||
extern unsigned ivl_expr_parms(ivl_expr_t net);
|
||||
/* IVL_EX_CONCAT */
|
||||
extern unsigned ivl_expr_repeat(ivl_expr_t net);
|
||||
/* IVL_EX_SELECT */
|
||||
extern ivl_select_type_t ivl_expr_sel_type(ivl_expr_t net);
|
||||
/* IVL_EX_EVENT */
|
||||
extern ivl_event_t ivl_expr_event(ivl_expr_t net);
|
||||
/* IVL_EX_SCOPE */
|
||||
|
|
@ -1040,6 +1048,7 @@ extern unsigned ivl_udp_rows(ivl_udp_t net);
|
|||
extern const char* ivl_udp_name(ivl_udp_t net);
|
||||
extern const char* ivl_udp_file(ivl_udp_t net);
|
||||
extern unsigned ivl_udp_lineno(ivl_udp_t net);
|
||||
extern const char* ivl_udp_port(ivl_udp_t net, unsigned idx);
|
||||
|
||||
extern const char* ivl_lpm_file(ivl_lpm_t net);
|
||||
extern unsigned ivl_lpm_lineno(ivl_lpm_t net);
|
||||
|
|
@ -1408,6 +1417,7 @@ extern unsigned ivl_lval_width(ivl_lval_t net);
|
|||
extern ivl_expr_t ivl_lval_mux(ivl_lval_t net); /* XXXX Obsolete? */
|
||||
extern ivl_expr_t ivl_lval_idx(ivl_lval_t net);
|
||||
extern ivl_expr_t ivl_lval_part_off(ivl_lval_t net);
|
||||
extern ivl_select_type_t ivl_lval_sel_type(ivl_lval_t net);
|
||||
extern ivl_signal_t ivl_lval_sig(ivl_lval_t net);
|
||||
|
||||
|
||||
|
|
@ -1702,6 +1712,7 @@ extern ivl_parameter_t ivl_scope_param(ivl_scope_t net, unsigned idx);
|
|||
extern ivl_scope_t ivl_scope_parent(ivl_scope_t net);
|
||||
extern unsigned ivl_scope_ports(ivl_scope_t net);
|
||||
extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx);
|
||||
extern ivl_nexus_t ivl_scope_mod_port(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_sigs(ivl_scope_t net);
|
||||
extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_switches(ivl_scope_t net);
|
||||
|
|
|
|||
|
|
@ -979,9 +979,9 @@ verinum* make_undef_highz_dec(const char* ptr)
|
|||
}
|
||||
|
||||
/*
|
||||
* Making a decimal number is much easier then the other base numbers
|
||||
* Making a decimal number is much easier than the other base numbers
|
||||
* because there are no z or x values to worry about. It is much
|
||||
* harder then other base numbers because the width needed in bits is
|
||||
* harder than other base numbers because the width needed in bits is
|
||||
* hard to calculate.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ quite similar.
|
|||
|
||||
Snapshots of Icarus Verilog source now come with the
|
||||
lexor_keyword.cc file pre-made, so if you have trouble with gperf,
|
||||
then just make sure the distributed lexor_keyword.cc is newer then
|
||||
then just make sure the distributed lexor_keyword.cc is newer than
|
||||
lexor_keyword.gperf, and use that.
|
||||
|
||||
3) If working with a CVS snapshot, you must run autoconf in several
|
||||
|
|
|
|||
|
|
@ -77,6 +77,11 @@ const NetExpr* NetAssign_::get_base() const
|
|||
return base_;
|
||||
}
|
||||
|
||||
ivl_select_type_t NetAssign_::select_type() const
|
||||
{
|
||||
return sel_type_;
|
||||
}
|
||||
|
||||
unsigned NetAssign_::lwidth() const
|
||||
{
|
||||
return lwid_;
|
||||
|
|
@ -120,10 +125,12 @@ NetNet* NetAssign_::sig() const
|
|||
return sig_;
|
||||
}
|
||||
|
||||
void NetAssign_::set_part(NetExpr*base, unsigned wid)
|
||||
void NetAssign_::set_part(NetExpr*base, unsigned wid,
|
||||
ivl_select_type_t sel_type)
|
||||
{
|
||||
base_ = base;
|
||||
lwid_ = wid;
|
||||
sel_type_ = sel_type;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ void NetScope::run_defparams_later(Design*des)
|
|||
(*cur)->evaluate_parameters(des);
|
||||
|
||||
// If there are some scopes that still have missing scopes,
|
||||
// then sav them back into the defparams_later list for a
|
||||
// then save them back into the defparams_later list for a
|
||||
// later pass.
|
||||
defparams_later = defparams_even_later;
|
||||
if (! defparams_later.empty())
|
||||
|
|
@ -332,8 +332,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
|||
/* Evaluate the msb expression, if it is present. */
|
||||
PExpr*msb_expr = (*cur).second.msb_expr;
|
||||
if (msb_expr) {
|
||||
probe_expr_width(des, this, msb_expr);
|
||||
(*cur).second.msb = elab_and_eval(des, this, msb_expr, -2);
|
||||
(*cur).second.msb = elab_and_eval(des, this, msb_expr, -1);
|
||||
if (! eval_as_long(msb, (*cur).second.msb)) {
|
||||
cerr << (*cur).second.val->get_fileline()
|
||||
<< ": error: Unable to evaluate msb expression "
|
||||
|
|
@ -349,8 +348,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
|||
/* Evaluate the lsb expression, if it is present. */
|
||||
PExpr*lsb_expr = (*cur).second.lsb_expr;
|
||||
if (lsb_expr) {
|
||||
probe_expr_width(des, this, lsb_expr);
|
||||
(*cur).second.lsb = elab_and_eval(des, this, lsb_expr, -2);
|
||||
(*cur).second.lsb = elab_and_eval(des, this, lsb_expr, -1);
|
||||
if (! eval_as_long(lsb, (*cur).second.lsb)) {
|
||||
cerr << (*cur).second.val->get_fileline()
|
||||
<< ": error: Unable to evaluate lsb expression "
|
||||
|
|
@ -367,26 +365,12 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
|||
PExpr*val_expr = (*cur).second.val_expr;
|
||||
NetScope*val_scope = (*cur).second.val_scope;
|
||||
|
||||
unsigned lval_wid = 0;
|
||||
int lv_width = -2;
|
||||
if (range_flag)
|
||||
lval_wid = (msb >= lsb) ? 1 + msb - lsb : 1 + lsb - msb;
|
||||
lv_width = (msb >= lsb) ? 1 + msb - lsb : 1 + lsb - msb;
|
||||
|
||||
bool unsized_flag = false;
|
||||
ivl_variable_type_t rval_type = IVL_VT_NO_TYPE;
|
||||
int expr_wid = val_expr->test_width(des, val_scope, lval_wid, lval_wid,
|
||||
rval_type, unsized_flag);
|
||||
|
||||
if (unsized_flag && !range_flag)
|
||||
expr_wid = -1;
|
||||
|
||||
int prune_wid = -1;
|
||||
if (gn_strict_expr_width_flag)
|
||||
prune_wid = 0;
|
||||
if (range_flag)
|
||||
prune_wid = lval_wid;
|
||||
|
||||
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, expr_wid, prune_wid);
|
||||
if (! expr)
|
||||
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width);
|
||||
if (! expr)
|
||||
return;
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
|
|
@ -427,7 +411,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
|||
if (range_flag) {
|
||||
/* If we have a real value convert it to an integer. */
|
||||
if(NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
||||
verinum nval(tmp->value().as_long64(), lval_wid);
|
||||
verinum nval(tmp->value().as_long64(), (unsigned)lv_width);
|
||||
expr = new NetEConst(nval);
|
||||
expr->set_line(*((*cur).second.val));
|
||||
(*cur).second.val = expr;
|
||||
|
|
@ -504,19 +488,8 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
|
|||
PExpr*val_expr = (*cur).second.val_expr;
|
||||
NetScope*val_scope = (*cur).second.val_scope;
|
||||
|
||||
bool unsized_flag = false;
|
||||
ivl_variable_type_t rval_type = IVL_VT_NO_TYPE;
|
||||
int expr_wid = val_expr->test_width(des, val_scope, 0, 0,
|
||||
rval_type, unsized_flag);
|
||||
if (unsized_flag)
|
||||
expr_wid = -1;
|
||||
|
||||
int prune_wid = -1;
|
||||
if (gn_strict_expr_width_flag)
|
||||
prune_wid = 0;
|
||||
|
||||
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, expr_wid, prune_wid);
|
||||
if (! expr)
|
||||
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, -1);
|
||||
if (! expr)
|
||||
return;
|
||||
|
||||
NetECReal*res = 0;
|
||||
|
|
|
|||
286
net_expr.cc
286
net_expr.cc
|
|
@ -38,92 +38,17 @@ netenum_t*NetExpr::enumeration() const
|
|||
}
|
||||
|
||||
/*
|
||||
* Create an add/sub node from the two operands. Make a best guess of
|
||||
* the
|
||||
* Create an add/sub node from the two operands.
|
||||
*/
|
||||
NetEBAdd::NetEBAdd(char op__, NetExpr*l, NetExpr*r, bool lossless_flag)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBAdd::NetEBAdd(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: NetEBinary(op__, l, r, wid, signed_flag)
|
||||
{
|
||||
NetEConst* tmp;
|
||||
|
||||
/* Catch the special case that one of the operands is an
|
||||
unsized constant number. If so, then we should set the
|
||||
width of that number to the size of the other operand, plus
|
||||
one. This expands the expression to account for the largest
|
||||
possible result.
|
||||
|
||||
Remember to handle the special case of an unsized constant,
|
||||
which we define to be at least "integer_width" bits.
|
||||
|
||||
The set_width applied to a constant value will only
|
||||
truncate the constant so far as it can still hold its
|
||||
logical value, so this is safe to do. */
|
||||
if ( (tmp = dynamic_cast<NetEConst*>(r))
|
||||
&& (! tmp->has_width())
|
||||
&& (tmp->expr_width() > l->expr_width() || integer_width > l->expr_width()) ) {
|
||||
|
||||
verinum tmp_v = trim_vnum(tmp->value());
|
||||
unsigned target_width = l->expr_width();
|
||||
if (target_width < tmp_v.len())
|
||||
target_width = tmp_v.len();
|
||||
if (lossless_flag)
|
||||
target_width += 1;
|
||||
if (target_width < integer_width)
|
||||
target_width = integer_width;
|
||||
|
||||
r->set_width(target_width);
|
||||
|
||||
/* Note: This constant value will not gain a defined
|
||||
width from this. Make sure. */
|
||||
assert(! r->has_width() );
|
||||
|
||||
expr_width(target_width);
|
||||
|
||||
} else if ( (tmp = dynamic_cast<NetEConst*>(l))
|
||||
&& (! tmp->has_width())
|
||||
&& (tmp->expr_width() > r->expr_width() || integer_width > r->expr_width()) ) {
|
||||
|
||||
verinum tmp_v = trim_vnum(tmp->value());
|
||||
unsigned target_width = r->expr_width();
|
||||
if (target_width < tmp_v.len())
|
||||
target_width = tmp_v.len();
|
||||
if (lossless_flag)
|
||||
target_width += 1;
|
||||
if (target_width < integer_width)
|
||||
target_width = integer_width;
|
||||
|
||||
l->set_width(target_width);
|
||||
|
||||
/* Note: This constant value will not gain a defined
|
||||
width from this. Make sure. */
|
||||
assert(! l->has_width() );
|
||||
|
||||
expr_width(target_width);
|
||||
|
||||
} else if (r->expr_width() > l->expr_width()) {
|
||||
unsigned loss_pad = lossless_flag? 1 : 0;
|
||||
expr_width(r->expr_width() + loss_pad);
|
||||
|
||||
} else {
|
||||
unsigned loss_pad = lossless_flag? 1 : 0;
|
||||
expr_width(l->expr_width() + loss_pad);
|
||||
}
|
||||
|
||||
cast_signed(l->has_sign() && r->has_sign());
|
||||
}
|
||||
|
||||
NetEBAdd::~NetEBAdd()
|
||||
{
|
||||
}
|
||||
|
||||
NetEBAdd* NetEBAdd::dup_expr() const
|
||||
{
|
||||
NetEBAdd*result = new NetEBAdd(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
result->set_line(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEBAdd::expr_type() const
|
||||
{
|
||||
if (left_->expr_type() == IVL_VT_REAL)
|
||||
|
|
@ -137,50 +62,10 @@ ivl_variable_type_t NetEBAdd::expr_type() const
|
|||
|
||||
/*
|
||||
* Create a comparison operator with two sub-expressions.
|
||||
*
|
||||
* Handle the special case of an unsized constant on the left or right
|
||||
* side by resizing the number to match the other
|
||||
* expression. Otherwise, the netlist will have to allow the
|
||||
* expressions to have different widths.
|
||||
*/
|
||||
NetEBComp::NetEBComp(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
: NetEBinary(op__, l, r, 1, false)
|
||||
{
|
||||
// The output of compare is always unsigned.
|
||||
cast_signed_base_(false);
|
||||
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(r)) do {
|
||||
|
||||
if (tmp->has_width())
|
||||
break;
|
||||
|
||||
if (l->expr_width() == 0)
|
||||
break;
|
||||
|
||||
if (tmp->expr_width() == l->expr_width())
|
||||
break;
|
||||
|
||||
tmp->set_width(l->expr_width());
|
||||
|
||||
} while (0);
|
||||
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(l)) do {
|
||||
|
||||
if (tmp->has_width())
|
||||
break;
|
||||
|
||||
if (r->expr_width() == 0)
|
||||
break;
|
||||
|
||||
if (tmp->expr_width() == r->expr_width())
|
||||
break;
|
||||
|
||||
tmp->set_width(r->expr_width());
|
||||
|
||||
} while (0);
|
||||
|
||||
|
||||
expr_width(1);
|
||||
}
|
||||
|
||||
NetEBComp::~NetEBComp()
|
||||
|
|
@ -207,29 +92,15 @@ ivl_variable_type_t NetEBComp::expr_type() const
|
|||
return IVL_VT_BOOL;
|
||||
}
|
||||
|
||||
NetEBDiv::NetEBDiv(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBDiv::NetEBDiv(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: NetEBinary(op__, l, r, wid, signed_flag)
|
||||
{
|
||||
unsigned w = l->expr_width();
|
||||
if (r->expr_width() > w)
|
||||
w = r->expr_width();
|
||||
|
||||
expr_width(w);
|
||||
cast_signed(l->has_sign() && r->has_sign());
|
||||
}
|
||||
|
||||
NetEBDiv::~NetEBDiv()
|
||||
{
|
||||
}
|
||||
|
||||
NetEBDiv* NetEBDiv::dup_expr() const
|
||||
{
|
||||
NetEBDiv*result = new NetEBDiv(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
result->set_line(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEBDiv::expr_type() const
|
||||
{
|
||||
if (left_->expr_type() == IVL_VT_REAL)
|
||||
|
|
@ -241,11 +112,9 @@ ivl_variable_type_t NetEBDiv::expr_type() const
|
|||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBMinMax::NetEBMinMax(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBMinMax::NetEBMinMax(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: NetEBinary(op__, l, r, wid, signed_flag)
|
||||
{
|
||||
expr_width( max(l->expr_width(), r->expr_width()) );
|
||||
cast_signed(l->has_sign() || r->has_sign());
|
||||
}
|
||||
|
||||
NetEBMinMax::~NetEBMinMax()
|
||||
|
|
@ -262,30 +131,15 @@ ivl_variable_type_t NetEBMinMax::expr_type() const
|
|||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: NetEBinary(op__, l, r, wid, signed_flag)
|
||||
{
|
||||
if (expr_type() == IVL_VT_REAL) {
|
||||
expr_width(1);
|
||||
cast_signed(true);
|
||||
} else {
|
||||
expr_width(l->expr_width() + r->expr_width());
|
||||
cast_signed(l->has_sign() && r->has_sign());
|
||||
}
|
||||
}
|
||||
|
||||
NetEBMult::~NetEBMult()
|
||||
{
|
||||
}
|
||||
|
||||
NetEBMult* NetEBMult::dup_expr() const
|
||||
{
|
||||
NetEBMult*result = new NetEBMult(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
result->set_line(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEBMult::expr_type() const
|
||||
{
|
||||
if (left_->expr_type() == IVL_VT_REAL)
|
||||
|
|
@ -297,27 +151,15 @@ ivl_variable_type_t NetEBMult::expr_type() const
|
|||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: NetEBinary(op__, l, r, wid, signed_flag)
|
||||
{
|
||||
assert(op__ == 'p');
|
||||
/* You could need up to a * (2^b - 1) bits. */
|
||||
expr_width(l->expr_width());
|
||||
cast_signed(l->has_sign() || r->has_sign());
|
||||
}
|
||||
|
||||
NetEBPow::~NetEBPow()
|
||||
{
|
||||
}
|
||||
|
||||
NetEBPow* NetEBPow::dup_expr() const
|
||||
{
|
||||
NetEBPow*result = new NetEBPow(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
result->set_line(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEBPow::expr_type() const
|
||||
{
|
||||
if (right_->expr_type() == IVL_VT_REAL)
|
||||
|
|
@ -328,13 +170,9 @@ ivl_variable_type_t NetEBPow::expr_type() const
|
|||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBShift::NetEBShift(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBShift::NetEBShift(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: NetEBinary(op__, l, r, wid, signed_flag)
|
||||
{
|
||||
expr_width(l->expr_width());
|
||||
|
||||
// The >>> is signed if the left operand is signed.
|
||||
if (op__ == 'R') cast_signed(l->has_sign());
|
||||
}
|
||||
|
||||
NetEBShift::~NetEBShift()
|
||||
|
|
@ -346,24 +184,9 @@ bool NetEBShift::has_width() const
|
|||
return left_->has_width();
|
||||
}
|
||||
|
||||
NetEBShift* NetEBShift::dup_expr() const
|
||||
{
|
||||
NetEBShift*result = new NetEBShift(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
result->set_line(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
NetEConcat::NetEConcat(unsigned cnt, NetExpr* r)
|
||||
NetEConcat::NetEConcat(unsigned cnt, unsigned r)
|
||||
: parms_(cnt), repeat_(r)
|
||||
{
|
||||
if (repeat_ == 0) {
|
||||
repeat_calculated_ = true;
|
||||
repeat_value_ = 1;
|
||||
} else {
|
||||
repeat_calculated_ = false;
|
||||
}
|
||||
|
||||
expr_width(0);
|
||||
}
|
||||
|
||||
|
|
@ -383,63 +206,7 @@ void NetEConcat::set(unsigned idx, NetExpr*e)
|
|||
assert(idx < parms_.count());
|
||||
assert(parms_[idx] == 0);
|
||||
parms_[idx] = e;
|
||||
expr_width( expr_width() + e->expr_width() );
|
||||
}
|
||||
|
||||
NetEConcat* NetEConcat::dup_expr() const
|
||||
{
|
||||
NetEConcat*dup = new NetEConcat(parms_.count(), 0);
|
||||
dup->set_line(*this);
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
if (parms_[idx]) {
|
||||
NetExpr*tmp = parms_[idx]->dup_expr();
|
||||
assert(tmp);
|
||||
dup->parms_[idx] = tmp;
|
||||
}
|
||||
|
||||
|
||||
dup->repeat_ = repeat_? repeat_->dup_expr() : 0;
|
||||
dup->repeat_value_ = repeat_value_;
|
||||
dup->repeat_calculated_ = repeat_calculated_;
|
||||
dup->expr_width(expr_width());
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
unsigned NetEConcat::repeat()
|
||||
{
|
||||
if (repeat_calculated_)
|
||||
return repeat_value_;
|
||||
|
||||
eval_expr(repeat_);
|
||||
|
||||
NetEConst*repeat_const = dynamic_cast<NetEConst*>(repeat_);
|
||||
|
||||
/* This should not be possible, as it was checked earlier to
|
||||
assure that this is a constant expression. */
|
||||
if (repeat_const == 0) {
|
||||
cerr << get_fileline() << ": internal error: repeat expression "
|
||||
<< "is not a compile time constant." << endl;
|
||||
cerr << get_fileline() << ": : Expression is: "
|
||||
<< *repeat_ << endl;
|
||||
repeat_calculated_ = true;
|
||||
repeat_value_ = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
repeat_calculated_ = true;
|
||||
repeat_value_ = repeat_const->value().as_ulong();
|
||||
|
||||
delete repeat_;
|
||||
repeat_ = 0;
|
||||
|
||||
return repeat_value_;
|
||||
}
|
||||
|
||||
unsigned NetEConcat::repeat() const
|
||||
{
|
||||
assert(repeat_calculated_);
|
||||
return repeat_value_;
|
||||
expr_width( expr_width() + repeat_ * e->expr_width() );
|
||||
}
|
||||
|
||||
NetEConstEnum::NetEConstEnum(NetScope*s, perm_string n, netenum_t*eset, const verinum&v)
|
||||
|
|
@ -461,7 +228,7 @@ NetECReal::NetECReal(const verireal&val)
|
|||
: value_(val)
|
||||
{
|
||||
expr_width(1);
|
||||
cast_signed(true);
|
||||
cast_signed_base_(true);
|
||||
}
|
||||
|
||||
NetECReal::~NetECReal()
|
||||
|
|
@ -475,14 +242,7 @@ const verireal& NetECReal::value() const
|
|||
|
||||
bool NetECReal::has_width() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NetECReal* NetECReal::dup_expr() const
|
||||
{
|
||||
NetECReal*tmp = new NetECReal(value_);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetECReal::expr_type() const
|
||||
|
|
@ -524,8 +284,9 @@ netenum_t* NetENetenum::netenum() const
|
|||
return netenum_;
|
||||
}
|
||||
|
||||
NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid)
|
||||
: expr_(exp), base_(base)
|
||||
NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid,
|
||||
ivl_select_type_t sel_type)
|
||||
: expr_(exp), base_(base), sel_type_(sel_type)
|
||||
{
|
||||
expr_width(wid);
|
||||
}
|
||||
|
|
@ -546,6 +307,11 @@ const NetExpr*NetESelect::select() const
|
|||
return base_;
|
||||
}
|
||||
|
||||
ivl_select_type_t NetESelect::select_type() const
|
||||
{
|
||||
return sel_type_;
|
||||
}
|
||||
|
||||
bool NetESelect::has_width() const
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -100,8 +100,6 @@ void NetCase::set_case(unsigned idx, NetExpr*e, NetProc*p)
|
|||
assert(idx < nitems_);
|
||||
items_[idx].guard = e;
|
||||
items_[idx].statement = p;
|
||||
if (items_[idx].guard)
|
||||
items_[idx].guard->set_width(expr_->expr_width());
|
||||
}
|
||||
|
||||
NetDisable::NetDisable(NetScope*tgt)
|
||||
|
|
@ -169,4 +167,3 @@ const NetExpr* NetRepeat::expr() const
|
|||
{
|
||||
return expr_;
|
||||
}
|
||||
|
||||
|
|
|
|||
21
net_scope.cc
21
net_scope.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -359,6 +359,25 @@ perm_string NetScope::module_name() const
|
|||
return module_name_;
|
||||
}
|
||||
|
||||
void NetScope::add_module_port(NetNet*port)
|
||||
{
|
||||
assert(type_ == MODULE);
|
||||
ports_.push_back(port);
|
||||
}
|
||||
|
||||
unsigned NetScope::module_ports() const
|
||||
{
|
||||
assert(type_ == MODULE);
|
||||
return ports_.size();
|
||||
}
|
||||
|
||||
NetNet* NetScope::module_port(unsigned idx) const
|
||||
{
|
||||
assert(type_ == MODULE);
|
||||
assert(idx < ports_.size());
|
||||
return ports_[idx];
|
||||
}
|
||||
|
||||
void NetScope::time_unit(int val)
|
||||
{
|
||||
time_unit_ = val;
|
||||
|
|
|
|||
11
net_udp.cc
11
net_udp.cc
|
|
@ -79,3 +79,14 @@ char NetUDP::get_initial() const
|
|||
assert(0);
|
||||
return 'x';
|
||||
}
|
||||
|
||||
unsigned NetUDP::port_count() const
|
||||
{
|
||||
return udp->ports.count();
|
||||
}
|
||||
|
||||
string NetUDP::port_name(unsigned idx) const
|
||||
{
|
||||
assert(idx < udp->ports.count());
|
||||
return udp->ports[idx];
|
||||
}
|
||||
|
|
|
|||
124
netlist.cc
124
netlist.cc
|
|
@ -2095,21 +2095,9 @@ NetExpr::~NetExpr()
|
|||
{
|
||||
}
|
||||
|
||||
bool NetExpr::has_sign() const
|
||||
{
|
||||
return signed_flag_;
|
||||
}
|
||||
|
||||
void NetExpr::cast_signed(bool flag)
|
||||
{
|
||||
signed_flag_ = flag;
|
||||
}
|
||||
|
||||
void NetExpr::expr_width(unsigned w)
|
||||
{
|
||||
// Catch underflow wrap errors.
|
||||
ivl_assert(*this, w < (UINT_MAX - 256));
|
||||
width_ = w;
|
||||
cast_signed_base_(flag);
|
||||
}
|
||||
|
||||
bool NetExpr::has_width() const
|
||||
|
|
@ -2119,37 +2107,22 @@ bool NetExpr::has_width() const
|
|||
|
||||
/*
|
||||
* Create a bitwise operator node from the opcode and the left and
|
||||
* right expressions. Don't worry about the width of the expression
|
||||
* yet, we'll get that from the l-value, whatever that turns out to
|
||||
* be. However, if we don't, our default will be the width of the
|
||||
* largest operand.
|
||||
* right expressions.
|
||||
*/
|
||||
NetEBBits::NetEBBits(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBBits::NetEBBits(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: NetEBinary(op__, l, r, wid, signed_flag)
|
||||
{
|
||||
if (r->expr_width() > l->expr_width())
|
||||
expr_width(r->expr_width());
|
||||
else
|
||||
expr_width(l->expr_width());
|
||||
}
|
||||
|
||||
NetEBBits::~NetEBBits()
|
||||
{
|
||||
}
|
||||
|
||||
NetEBBits* NetEBBits::dup_expr() const
|
||||
{
|
||||
NetEBBits*result = new NetEBBits(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
return result;
|
||||
}
|
||||
|
||||
NetEBinary::NetEBinary(char op__, NetExpr*l, NetExpr*r)
|
||||
NetEBinary::NetEBinary(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: op_(op__), left_(l), right_(r)
|
||||
{
|
||||
// Binary expressions of all sorts are signed if both the
|
||||
// arguments are signed.
|
||||
cast_signed_base_( left_->has_sign() && right_->has_sign());
|
||||
expr_width(wid);
|
||||
cast_signed_base_(signed_flag);
|
||||
}
|
||||
|
||||
NetEBinary::~NetEBinary()
|
||||
|
|
@ -2163,29 +2136,15 @@ bool NetEBinary::has_width() const
|
|||
return left_->has_width() && right_->has_width();
|
||||
}
|
||||
|
||||
NetEBinary* NetEBinary::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEBLogic::NetEBLogic(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
: NetEBinary(op__, l, r, 1, false)
|
||||
{
|
||||
expr_width(1);
|
||||
}
|
||||
|
||||
NetEBLogic::~NetEBLogic()
|
||||
{
|
||||
}
|
||||
|
||||
NetEBLogic* NetEBLogic::dup_expr() const
|
||||
{
|
||||
NetEBLogic*result = new NetEBLogic(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
return result;
|
||||
}
|
||||
|
||||
NetEConst::NetEConst(const verinum&val)
|
||||
: NetExpr(val.len()), value_(val)
|
||||
{
|
||||
|
|
@ -2196,6 +2155,12 @@ NetEConst::~NetEConst()
|
|||
{
|
||||
}
|
||||
|
||||
void NetEConst::cast_signed(bool flag)
|
||||
{
|
||||
cast_signed_base_(flag);
|
||||
value_.has_sign(flag);
|
||||
}
|
||||
|
||||
const verinum& NetEConst::value() const
|
||||
{
|
||||
return value_;
|
||||
|
|
@ -2218,6 +2183,17 @@ ivl_variable_type_t NetEConst::expr_type() const
|
|||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
void NetEConst::trim()
|
||||
|
||||
{
|
||||
if (value_.is_string())
|
||||
return;
|
||||
|
||||
value_.has_len(false);
|
||||
value_ = trim_vnum(value_);
|
||||
expr_width(value_.len());
|
||||
}
|
||||
|
||||
NetEConstParam::NetEConstParam(NetScope*s, perm_string n, const verinum&v)
|
||||
: NetEConst(v), scope_(s), name_(n)
|
||||
{
|
||||
|
|
@ -2272,7 +2248,7 @@ NetESignal::NetESignal(NetNet*n)
|
|||
{
|
||||
net_->incr_eref();
|
||||
set_line(*n);
|
||||
cast_signed(net_->get_signed());
|
||||
cast_signed_base_(net_->get_signed());
|
||||
}
|
||||
|
||||
NetESignal::NetESignal(NetNet*n, NetExpr*w)
|
||||
|
|
@ -2280,7 +2256,7 @@ NetESignal::NetESignal(NetNet*n, NetExpr*w)
|
|||
{
|
||||
net_->incr_eref();
|
||||
set_line(*n);
|
||||
cast_signed(net_->get_signed());
|
||||
cast_signed_base_(net_->get_signed());
|
||||
}
|
||||
|
||||
NetESignal::~NetESignal()
|
||||
|
|
@ -2334,20 +2310,12 @@ ivl_variable_type_t NetESignal::expr_type() const
|
|||
* should have the same width. NOTE: This matching of the widths really
|
||||
* has to be done in elaboration.
|
||||
*/
|
||||
NetETernary::NetETernary(NetExpr*c, NetExpr*t, NetExpr*f)
|
||||
NetETernary::NetETernary(NetExpr*c, NetExpr*t, NetExpr*f,
|
||||
unsigned wid, bool signed_flag)
|
||||
: cond_(c), true_val_(t), false_val_(f)
|
||||
{
|
||||
if (type_is_vectorable(expr_type())) {
|
||||
// use widest result
|
||||
if (true_val_->expr_width() > false_val_->expr_width())
|
||||
expr_width(true_val_->expr_width());
|
||||
else
|
||||
expr_width(false_val_->expr_width());
|
||||
} else {
|
||||
expr_width(1);
|
||||
}
|
||||
|
||||
cast_signed(c->has_sign() && t->has_sign() && f->has_sign());
|
||||
expr_width(wid);
|
||||
cast_signed_base_(signed_flag);
|
||||
}
|
||||
|
||||
NetETernary::~NetETernary()
|
||||
|
|
@ -2399,23 +2367,10 @@ ivl_variable_type_t NetETernary::expr_type() const
|
|||
return tru;
|
||||
}
|
||||
|
||||
NetEUnary::NetEUnary(char op__, NetExpr*ex)
|
||||
: NetExpr(ex->expr_width()), op_(op__), expr_(ex)
|
||||
NetEUnary::NetEUnary(char op__, NetExpr*ex, unsigned wid, bool signed_flag)
|
||||
: NetExpr(wid), op_(op__), expr_(ex)
|
||||
{
|
||||
switch (op_) {
|
||||
case '!':
|
||||
expr_width(1);
|
||||
break;
|
||||
}
|
||||
switch (op_) {
|
||||
case '-':
|
||||
case '+':
|
||||
case 'm': // abs()
|
||||
cast_signed(ex->has_sign());
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
cast_signed_base_(signed_flag);
|
||||
}
|
||||
|
||||
NetEUnary::~NetEUnary()
|
||||
|
|
@ -2428,8 +2383,8 @@ ivl_variable_type_t NetEUnary::expr_type() const
|
|||
return expr_->expr_type();
|
||||
}
|
||||
|
||||
NetEUBits::NetEUBits(char op__, NetExpr*ex)
|
||||
: NetEUnary(op__, ex)
|
||||
NetEUBits::NetEUBits(char op__, NetExpr*ex, unsigned wid, bool signed_flag)
|
||||
: NetEUnary(op__, ex, wid, signed_flag)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -2443,9 +2398,8 @@ ivl_variable_type_t NetEUBits::expr_type() const
|
|||
}
|
||||
|
||||
NetEUReduce::NetEUReduce(char op__, NetExpr*ex)
|
||||
: NetEUnary(op__, ex)
|
||||
: NetEUnary(op__, ex, 1, false)
|
||||
{
|
||||
expr_width(1);
|
||||
}
|
||||
|
||||
NetEUReduce::~NetEUReduce()
|
||||
|
|
@ -2457,8 +2411,8 @@ ivl_variable_type_t NetEUReduce::expr_type() const
|
|||
return expr_->expr_type();
|
||||
}
|
||||
|
||||
NetECast::NetECast(char op__, NetExpr*ex)
|
||||
: NetEUnary(op__, ex)
|
||||
NetECast::NetECast(char op__, NetExpr*ex, unsigned wid, bool signed_flag)
|
||||
: NetEUnary(op__, ex, wid, signed_flag)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
169
netlist.h
169
netlist.h
|
|
@ -42,6 +42,7 @@
|
|||
# include "LineInfo.h"
|
||||
# include "svector.h"
|
||||
# include "Attrib.h"
|
||||
# include "PUdp.h"
|
||||
|
||||
#ifdef HAVE_IOSFWD
|
||||
# include <iosfwd>
|
||||
|
|
@ -803,6 +804,11 @@ class NetScope : public Attrib {
|
|||
/* If the scope represents a module instance, the module_name
|
||||
is the name of the module itself. */
|
||||
perm_string module_name() const;
|
||||
/* If the scope is a module then it may have ports that we need
|
||||
* to keep track of. */
|
||||
void add_module_port(NetNet*port);
|
||||
unsigned module_ports() const;
|
||||
NetNet*module_port(unsigned idx) const;
|
||||
|
||||
/* Scopes have their own time units and time precision. The
|
||||
unit and precision are given as power of 10, i.e., -3 is
|
||||
|
|
@ -943,6 +949,7 @@ class NetScope : public Attrib {
|
|||
typedef std::map<perm_string,NetNet*>::const_iterator signals_map_iter_t;
|
||||
std::map <perm_string,NetNet*> signals_map_;
|
||||
perm_string module_name_;
|
||||
vector<NetNet*>ports_;
|
||||
union {
|
||||
NetTaskDef*task_;
|
||||
NetFuncDef*func_;
|
||||
|
|
@ -1137,7 +1144,7 @@ class NetCLShift : public NetNode {
|
|||
* This class supports the LPM_COMPARE device.
|
||||
*
|
||||
* The width of the device is the width of the inputs. If one of the
|
||||
* inputs is narrower then the other, it is up to the generator to
|
||||
* inputs is narrower than the other, it is up to the generator to
|
||||
* make sure all the data pins are properly driven.
|
||||
*
|
||||
* The signed() property is true if the comparison is to be done to
|
||||
|
|
@ -1600,12 +1607,8 @@ class NetTran : public NetNode, public IslandBranch {
|
|||
* There are cases where expressions need to be represented. The
|
||||
* NetExpr class is the root of a hierarchy that serves that purpose.
|
||||
*
|
||||
* The expr_width() is the width of the expression, that accounts
|
||||
* for the widths of the sub-expressions I might have. It is up to the
|
||||
* derived classes to properly set the expr width, if need be. The
|
||||
* set_width() method is used to compel an expression to have a
|
||||
* certain width, and is used particularly when the expression is an
|
||||
* rvalue in an assignment statement.
|
||||
* The expr_width() is the width of the expression, which is calculated
|
||||
* before the expression is elaborated.
|
||||
*/
|
||||
class NetExpr : public LineInfo {
|
||||
public:
|
||||
|
|
@ -1621,27 +1624,9 @@ class NetExpr : public LineInfo {
|
|||
// How wide am I?
|
||||
unsigned expr_width() const { return width_; }
|
||||
|
||||
// Coerce the expression to have a specific width. If the
|
||||
// coercion works, then return true. Otherwise, return false.
|
||||
// A coercion will work or not depending on the implementation
|
||||
// in the derived class. Normally, the width will be set if
|
||||
// the expression is:
|
||||
// - already the requested size, OR
|
||||
// - otherwise unsized.
|
||||
// Normally, the resize will not allow a width size that loses
|
||||
// data. For example, it will not reduce a constant expression
|
||||
// to the point where significant bits are lost. But if the
|
||||
// last_chance flag is true, then the method assumes that high
|
||||
// bits will be lost anyhow, so try harder. Loss will be
|
||||
// allowed, but it still won't resize fixed size expressions
|
||||
// such as vector signals. This flag is meant to be used by
|
||||
// elaboration of procedural assignment to set the expression
|
||||
// width to the l-value width, if possible.
|
||||
virtual bool set_width(unsigned wid, bool last_chance =false);
|
||||
|
||||
// This method returns true if the expression is
|
||||
// signed. Unsigned expressions return false.
|
||||
bool has_sign() const;
|
||||
bool has_sign() const { return signed_flag_; }
|
||||
virtual void cast_signed(bool flag);
|
||||
|
||||
// This returns true if the expression has a definite
|
||||
|
|
@ -1663,14 +1648,7 @@ class NetExpr : public LineInfo {
|
|||
// equivalent expression that is reduced as far as compile
|
||||
// time knows how. Essentially, this is designed to fold
|
||||
// constants.
|
||||
//
|
||||
// The prune_to_width is the maximum width that the result
|
||||
// should be. If it is 0 or -1, then do not prune the
|
||||
// result. If it is -1, go through special efforts to preserve
|
||||
// values that may expand. A width of 0 corresponds to a
|
||||
// self-determined context, and a width of -1 corresponds to
|
||||
// an infinitely wide context.
|
||||
virtual NetExpr*eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr*eval_tree();
|
||||
|
||||
// Make a duplicate of myself, and subexpressions if I have
|
||||
// any. This is a deep copy operation.
|
||||
|
|
@ -1695,10 +1673,9 @@ class NetExpr : public LineInfo {
|
|||
// the expression output.
|
||||
virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root);
|
||||
|
||||
|
||||
protected:
|
||||
void expr_width(unsigned w);
|
||||
void cast_signed_base_(bool flag) {signed_flag_ = flag; }
|
||||
void expr_width(unsigned wid) { width_ = wid; }
|
||||
void cast_signed_base_(bool flag) { signed_flag_ = flag; }
|
||||
|
||||
private:
|
||||
unsigned width_;
|
||||
|
|
@ -1722,11 +1699,15 @@ class NetEConst : public NetExpr {
|
|||
|
||||
const verinum&value() const;
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
virtual void cast_signed(bool sign_flag);
|
||||
virtual void cast_signed(bool flag);
|
||||
virtual bool has_width() const;
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
/* This method allows the constant value to be converted
|
||||
to an unsized value. This is used after evaluating a
|
||||
unsized constant expression. */
|
||||
virtual void trim();
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
|
|
@ -1749,7 +1730,6 @@ class NetEConstEnum : public NetEConst {
|
|||
const NetScope*scope() const;
|
||||
netenum_t*enumeration() const;
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
|
|
@ -1771,7 +1751,6 @@ class NetEConstParam : public NetEConst {
|
|||
perm_string name() const;
|
||||
const NetScope*scope() const;
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
|
|
@ -1793,10 +1772,6 @@ class NetECReal : public NetExpr {
|
|||
|
||||
const verireal&value() const;
|
||||
|
||||
// Reals can be used in vector expressions. Conversions will
|
||||
// be done at the right time.
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
|
||||
// This type has no self-determined width. This is false.
|
||||
virtual bool has_width() const;
|
||||
|
||||
|
|
@ -2144,7 +2119,6 @@ class NetUReduce : public NetNode {
|
|||
* 1 are listed.
|
||||
*
|
||||
*/
|
||||
#include "PUdp.h"
|
||||
|
||||
class NetUDP : public NetNode {
|
||||
|
||||
|
|
@ -2169,6 +2143,9 @@ class NetUDP : public NetNode {
|
|||
unsigned udp_lineno() const { return udp->get_lineno(); }
|
||||
char get_initial() const;
|
||||
|
||||
unsigned port_count() const;
|
||||
string port_name(unsigned idx) const;
|
||||
|
||||
private:
|
||||
mutable unsigned table_idx;
|
||||
PUdp *udp;
|
||||
|
|
@ -2298,9 +2275,11 @@ class NetAssign_ {
|
|||
// Get the base index of the part select, or 0 if there is no
|
||||
// part select.
|
||||
const NetExpr* get_base() const;
|
||||
ivl_select_type_t select_type() const;
|
||||
|
||||
void set_word(NetExpr*);
|
||||
void set_part(NetExpr* loff, unsigned wid);
|
||||
void set_part(NetExpr* loff, unsigned wid,
|
||||
ivl_select_type_t = IVL_SEL_OTHER);
|
||||
|
||||
// Get the width of the r-value that this node expects. This
|
||||
// method accounts for the presence of the mux, so it is not
|
||||
|
|
@ -2342,6 +2321,7 @@ class NetAssign_ {
|
|||
// indexed part select base
|
||||
NetExpr*base_;
|
||||
unsigned lwid_;
|
||||
ivl_select_type_t sel_type_;
|
||||
};
|
||||
|
||||
class NetAssignBase : public NetProc {
|
||||
|
|
@ -3123,14 +3103,13 @@ class NetEUFunc : public NetExpr {
|
|||
|
||||
const NetScope* func() const;
|
||||
|
||||
virtual bool set_width(unsigned, bool last_chance);
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual NetEUFunc*dup_expr() const;
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
|
|
@ -3326,7 +3305,7 @@ class NetAnalogTop : public LineInfo, public Attrib {
|
|||
class NetEBinary : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEBinary(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBinary(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBinary();
|
||||
|
||||
const NetExpr*left() const { return left_; }
|
||||
|
|
@ -3334,8 +3313,6 @@ class NetEBinary : public NetExpr {
|
|||
|
||||
char op() const { return op_; }
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
|
||||
// A binary expression node only has a definite
|
||||
// self-determinable width if the operands both have definite
|
||||
// widths.
|
||||
|
|
@ -3365,15 +3342,13 @@ class NetEBinary : public NetExpr {
|
|||
class NetEBAdd : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBAdd(char op, NetExpr*l, NetExpr*r, bool lossless_flag =false);
|
||||
NetEBAdd(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBAdd();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual void cast_signed(bool sign_flag);
|
||||
virtual NetEBAdd* dup_expr() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
|
|
@ -3388,15 +3363,13 @@ class NetEBAdd : public NetEBinary {
|
|||
class NetEBDiv : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBDiv(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBDiv(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBDiv();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual void cast_signed(bool sign_flag);
|
||||
virtual NetEBDiv* dup_expr() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
|
|
@ -3420,12 +3393,11 @@ class NetEBDiv : public NetEBinary {
|
|||
class NetEBBits : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBBits(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBBits(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBBits();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual NetEBBits* dup_expr() const;
|
||||
virtual NetEConst* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEConst* eval_tree();
|
||||
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
};
|
||||
|
|
@ -3450,13 +3422,11 @@ class NetEBComp : public NetEBinary {
|
|||
NetEBComp(char op, NetExpr*l, NetExpr*r);
|
||||
~NetEBComp();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
|
||||
/* A compare expression has a definite width. */
|
||||
virtual bool has_width() const;
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NetEBComp* dup_expr() const;
|
||||
virtual NetEConst* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEConst* eval_tree();
|
||||
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
|
|
@ -3486,9 +3456,8 @@ class NetEBLogic : public NetEBinary {
|
|||
NetEBLogic(char op, NetExpr*l, NetExpr*r);
|
||||
~NetEBLogic();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
virtual NetEBLogic* dup_expr() const;
|
||||
virtual NetEConst* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEConst* eval_tree();
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
|
|
@ -3505,7 +3474,7 @@ class NetEBLogic : public NetEBinary {
|
|||
class NetEBMinMax : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBMinMax(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBMinMax(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBMinMax();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
|
@ -3519,15 +3488,13 @@ class NetEBMinMax : public NetEBinary {
|
|||
class NetEBMult : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBMult(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBMult(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBMult();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual void cast_signed(bool sign_flag);
|
||||
virtual NetEBMult* dup_expr() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
|
|
@ -3540,14 +3507,13 @@ class NetEBMult : public NetEBinary {
|
|||
class NetEBPow : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBPow(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBPow(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBPow();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual NetEBPow* dup_expr() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
|
|
@ -3566,17 +3532,15 @@ class NetEBPow : public NetEBinary {
|
|||
class NetEBShift : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBShift(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBShift(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBShift();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
|
||||
// A shift expression only needs the left expression to have a
|
||||
// definite width to give the expression a definite width.
|
||||
virtual bool has_width() const;
|
||||
|
||||
virtual NetEBShift* dup_expr() const;
|
||||
virtual NetEConst* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEConst* eval_tree();
|
||||
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
|
|
@ -3596,31 +3560,27 @@ class NetEBShift : public NetEBinary {
|
|||
class NetEConcat : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEConcat(unsigned cnt, NetExpr* repeat =0);
|
||||
NetEConcat(unsigned cnt, unsigned repeat =1);
|
||||
~NetEConcat();
|
||||
|
||||
// Manipulate the parameters.
|
||||
void set(unsigned idx, NetExpr*e);
|
||||
|
||||
unsigned repeat();
|
||||
unsigned repeat() const;
|
||||
unsigned repeat() const { return repeat_; }
|
||||
unsigned nparms() const { return parms_.count() ; }
|
||||
NetExpr* parm(unsigned idx) const { return parms_[idx]; }
|
||||
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool has_width() const;
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
virtual NetEConcat* dup_expr() const;
|
||||
virtual NetEConst* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEConst* eval_tree();
|
||||
virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
svector<NetExpr*>parms_;
|
||||
NetExpr* repeat_;
|
||||
unsigned repeat_value_;
|
||||
bool repeat_calculated_;
|
||||
unsigned repeat_;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -3641,17 +3601,18 @@ class NetEConcat : public NetExpr {
|
|||
class NetESelect : public NetExpr {
|
||||
|
||||
public:
|
||||
NetESelect(NetExpr*exp, NetExpr*base, unsigned wid);
|
||||
NetESelect(NetExpr*exp, NetExpr*base, unsigned wid,
|
||||
ivl_select_type_t sel_type = IVL_SEL_OTHER);
|
||||
~NetESelect();
|
||||
|
||||
const NetExpr*sub_expr() const;
|
||||
const NetExpr*select() const;
|
||||
ivl_select_type_t select_type() const;
|
||||
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
virtual bool has_width() const;
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual NetEConst* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEConst* eval_tree();
|
||||
virtual NetESelect* dup_expr() const;
|
||||
virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root);
|
||||
virtual void dump(ostream&) const;
|
||||
|
|
@ -3659,6 +3620,7 @@ class NetESelect : public NetExpr {
|
|||
private:
|
||||
NetExpr*expr_;
|
||||
NetExpr*base_;
|
||||
ivl_select_type_t sel_type_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -3748,11 +3710,10 @@ class NetESFunc : public NetExpr {
|
|||
NetExpr* parm(unsigned idx);
|
||||
const NetExpr* parm(unsigned idx) const;
|
||||
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool set_width(unsigned, bool last_chance);
|
||||
virtual netenum_t* enumeration() const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
|
|
@ -3779,17 +3740,15 @@ class NetESFunc : public NetExpr {
|
|||
class NetETernary : public NetExpr {
|
||||
|
||||
public:
|
||||
NetETernary(NetExpr*c, NetExpr*t, NetExpr*f);
|
||||
NetETernary(NetExpr*c, NetExpr*t, NetExpr*f, unsigned wid, bool signed_flag);
|
||||
~NetETernary();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
|
||||
const NetExpr*cond_expr() const;
|
||||
const NetExpr*true_expr() const;
|
||||
const NetExpr*false_expr() const;
|
||||
|
||||
virtual NetETernary* dup_expr() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
|
|
@ -3828,16 +3787,14 @@ class NetETernary : public NetExpr {
|
|||
class NetEUnary : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEUnary(char op, NetExpr*ex);
|
||||
NetEUnary(char op, NetExpr*ex, unsigned wid, bool signed_flag);
|
||||
~NetEUnary();
|
||||
|
||||
char op() const { return op_; }
|
||||
const NetExpr* expr() const { return expr_; }
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
|
||||
virtual NetEUnary* dup_expr() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
|
@ -3856,13 +3813,13 @@ class NetEUnary : public NetExpr {
|
|||
class NetEUBits : public NetEUnary {
|
||||
|
||||
public:
|
||||
NetEUBits(char op, NetExpr*ex);
|
||||
NetEUBits(char op, NetExpr*ex, unsigned wid, bool signed_flag);
|
||||
~NetEUBits();
|
||||
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
virtual NetEUBits* dup_expr() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
};
|
||||
|
||||
|
|
@ -3872,10 +3829,9 @@ class NetEUReduce : public NetEUnary {
|
|||
NetEUReduce(char op, NetExpr*ex);
|
||||
~NetEUReduce();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
virtual NetEUReduce* dup_expr() const;
|
||||
virtual NetEConst* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEConst* eval_tree();
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
private:
|
||||
|
|
@ -3885,7 +3841,7 @@ class NetEUReduce : public NetEUnary {
|
|||
class NetECast : public NetEUnary {
|
||||
|
||||
public:
|
||||
NetECast(char op, NetExpr*ex);
|
||||
NetECast(char op, NetExpr*ex, unsigned wid, bool signed_flag);
|
||||
~NetECast();
|
||||
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
|
@ -3911,7 +3867,6 @@ class NetESignal : public NetExpr {
|
|||
~NetESignal();
|
||||
|
||||
perm_string name() const;
|
||||
virtual bool set_width(unsigned, bool last_chance);
|
||||
|
||||
virtual NetESignal* dup_expr() const;
|
||||
NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root);
|
||||
|
|
|
|||
145
netmisc.cc
145
netmisc.cc
|
|
@ -184,9 +184,9 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
|
|||
|
||||
NetExpr* cast_to_int2(NetExpr*expr)
|
||||
{
|
||||
NetECast*cast = new NetECast('2', expr);
|
||||
NetECast*cast = new NetECast('2', expr, expr->expr_width(),
|
||||
expr->has_sign());
|
||||
cast->set_line(*expr);
|
||||
cast->cast_signed(expr->has_sign());
|
||||
return cast;
|
||||
}
|
||||
|
||||
|
|
@ -208,17 +208,14 @@ static NetExpr* make_add_expr(NetExpr*expr, long val)
|
|||
val = -val;
|
||||
}
|
||||
|
||||
verinum val_v (val);
|
||||
verinum val_v (val, expr->expr_width());
|
||||
val_v.has_sign(true);
|
||||
|
||||
if (expr->has_width()) {
|
||||
val_v = verinum(val_v, expr->expr_width());
|
||||
}
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
||||
NetEBAdd*res = new NetEBAdd(add_op, expr, val_c);
|
||||
NetEBAdd*res = new NetEBAdd(add_op, expr, val_c, expr->expr_width(),
|
||||
expr->has_sign());
|
||||
res->set_line(*expr);
|
||||
|
||||
return res;
|
||||
|
|
@ -235,7 +232,8 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
|
|||
NetEConst*val_c = new NetEConst(val_v);
|
||||
val_c->set_line(*expr);
|
||||
|
||||
NetEBAdd*res = new NetEBAdd('-', val_c, expr);
|
||||
NetEBAdd*res = new NetEBAdd('-', val_c, expr, expr->expr_width(),
|
||||
expr->has_sign());
|
||||
res->set_line(*expr);
|
||||
|
||||
return res;
|
||||
|
|
@ -444,11 +442,10 @@ NetExpr* condition_reduce(NetExpr*expr)
|
|||
return expr;
|
||||
|
||||
verinum zero (verinum::V0, expr->expr_width());
|
||||
zero.has_sign(expr->has_sign());
|
||||
|
||||
NetEConst*ezero = new NetEConst(zero);
|
||||
ezero->set_line(*expr);
|
||||
ezero->cast_signed(expr->has_sign());
|
||||
ezero->set_width(expr->expr_width());
|
||||
|
||||
NetEBComp*cmp = new NetEBComp('n', expr, ezero);
|
||||
cmp->set_line(*expr);
|
||||
|
|
@ -457,43 +454,132 @@ NetExpr* condition_reduce(NetExpr*expr)
|
|||
return cmp;
|
||||
}
|
||||
|
||||
void probe_expr_width(Design*des, NetScope*scope, PExpr*pe)
|
||||
static const char*width_mode_name(PExpr::width_mode_t mode)
|
||||
{
|
||||
ivl_variable_type_t expr_type = IVL_VT_NO_TYPE;
|
||||
bool flag = false;
|
||||
pe->test_width(des, scope, 0, 0, expr_type, flag);
|
||||
switch (mode) {
|
||||
case PExpr::SIZED:
|
||||
return "sized";
|
||||
case PExpr::EXPAND:
|
||||
return "expand";
|
||||
case PExpr::LOSSLESS:
|
||||
return "lossless";
|
||||
case PExpr::UNSIZED:
|
||||
return "unsized";
|
||||
default:
|
||||
return "??";
|
||||
}
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope,
|
||||
const PExpr*pe, int expr_wid, int prune_width)
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width)
|
||||
{
|
||||
NetExpr*tmp = pe->elaborate_expr(des, scope, expr_wid, false);
|
||||
PExpr::width_mode_t mode = PExpr::SIZED;
|
||||
if ((context_width == -2) && !gn_strict_expr_width_flag)
|
||||
mode = PExpr::EXPAND;
|
||||
|
||||
pe->test_width(des, scope, mode);
|
||||
|
||||
// Get the final expression width. If the expression is unsized,
|
||||
// this may be different from the value returned by test_width().
|
||||
unsigned expr_width = pe->expr_width();
|
||||
|
||||
// If context_width is positive, this is the RHS of an assignment,
|
||||
// so the LHS width must also be included in the width calculation.
|
||||
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL)
|
||||
&& (expr_width < (unsigned)context_width))
|
||||
expr_width = context_width;
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << pe->get_fileline() << ": debug: test_width of "
|
||||
<< *pe << endl;
|
||||
cerr << pe->get_fileline() << ": "
|
||||
<< "returns type=" << pe->expr_type()
|
||||
<< ", width=" << expr_width
|
||||
<< ", signed=" << pe->has_sign()
|
||||
<< ", mode=" << width_mode_name(mode) << endl;
|
||||
}
|
||||
|
||||
// If we can get the same result using a smaller expression
|
||||
// width, do so.
|
||||
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL)
|
||||
&& (expr_width > (unsigned)context_width)) {
|
||||
expr_width = max(pe->min_width(), (unsigned)context_width);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << pe->get_fileline() << ": "
|
||||
<< "pruned to width=" << expr_width << endl;
|
||||
}
|
||||
}
|
||||
|
||||
NetExpr*tmp = pe->elaborate_expr(des, scope, expr_width, false);
|
||||
if (tmp == 0) return 0;
|
||||
|
||||
eval_expr(tmp, prune_width);
|
||||
eval_expr(tmp, context_width);
|
||||
|
||||
if (NetEConst*ce = dynamic_cast<NetEConst*>(tmp)) {
|
||||
if ((mode >= PExpr::LOSSLESS) && (context_width < 0))
|
||||
ce->trim();
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void eval_expr(NetExpr*&expr, int prune_width)
|
||||
NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
|
||||
unsigned arg_idx, PExpr*pe)
|
||||
{
|
||||
PExpr::width_mode_t mode = PExpr::SIZED;
|
||||
pe->test_width(des, scope, mode);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << pe->get_fileline() << ": debug: test_width of "
|
||||
<< name << " argument " << (arg_idx+1) << " " << *pe << endl;
|
||||
cerr << pe->get_fileline() << ": "
|
||||
<< "returns type=" << pe->expr_type()
|
||||
<< ", width=" << pe->expr_width()
|
||||
<< ", signed=" << pe->has_sign()
|
||||
<< ", mode=" << width_mode_name(mode) << endl;
|
||||
}
|
||||
|
||||
NetExpr*tmp = pe->elaborate_expr(des, scope, pe->expr_width(), true);
|
||||
if (tmp == 0) return 0;
|
||||
|
||||
eval_expr(tmp, -1);
|
||||
|
||||
if (NetEConst*ce = dynamic_cast<NetEConst*>(tmp)) {
|
||||
if (mode != PExpr::SIZED)
|
||||
ce->trim();
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void eval_expr(NetExpr*&expr, int context_width)
|
||||
{
|
||||
assert(expr);
|
||||
if (dynamic_cast<NetECReal*>(expr)) return;
|
||||
/* Resize a constant if allowed and needed. */
|
||||
if (NetEConst *tmp = dynamic_cast<NetEConst*>(expr)) {
|
||||
if (prune_width <= 0) return;
|
||||
if (tmp->has_width()) return;
|
||||
if ((unsigned)prune_width <= tmp->expr_width()) return;
|
||||
expr = pad_to_width(expr, (unsigned)prune_width, *expr);
|
||||
return;
|
||||
}
|
||||
|
||||
NetExpr*tmp = expr->eval_tree(prune_width);
|
||||
NetExpr*tmp = expr->eval_tree();
|
||||
if (tmp != 0) {
|
||||
tmp->set_line(*expr);
|
||||
delete expr;
|
||||
expr = tmp;
|
||||
}
|
||||
|
||||
if (context_width <= 0) return;
|
||||
|
||||
NetEConst *ce = dynamic_cast<NetEConst*>(expr);
|
||||
if (ce == 0) return;
|
||||
|
||||
// The expression is a constant, so resize it if needed.
|
||||
if (ce->expr_width() < (unsigned)context_width) {
|
||||
expr = pad_to_width(expr, context_width, *expr);
|
||||
}
|
||||
if (ce->expr_width() > (unsigned)context_width) {
|
||||
verinum value(ce->value(), context_width);
|
||||
ce = new NetEConst(value);
|
||||
ce->set_line(*expr);
|
||||
delete expr;
|
||||
expr = ce;
|
||||
}
|
||||
}
|
||||
|
||||
bool eval_as_long(long&value, NetExpr*expr)
|
||||
|
|
@ -560,7 +646,6 @@ hname_t eval_path_component(Design*des, NetScope*scope,
|
|||
assert(index.sel == index_component_t::SEL_BIT);
|
||||
|
||||
// Evaluate the bit select to get a number.
|
||||
probe_expr_width(des, scope, index.msb);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1);
|
||||
ivl_assert(*index.msb, tmp);
|
||||
|
||||
|
|
|
|||
47
netmisc.h
47
netmisc.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __netmisc_H
|
||||
#define __netmisc_H
|
||||
/*
|
||||
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -151,45 +151,38 @@ extern bool is_param_expr;
|
|||
* constant expression. If it cannot be evaluated, it returns whatever
|
||||
* it can. If the expression cannot be elaborated, return 0.
|
||||
*
|
||||
* The expr_width is the width of the context where the expression is
|
||||
* being elaborated, or -1 if the expression is self-determined width.
|
||||
*
|
||||
* The prune_width is the maximum width of the result, and is passed
|
||||
* to the eval_tree method of the expression to limit constant
|
||||
* results. The evaluation will prune any constant result down to the
|
||||
* prune_width (if >0) so should only be used at the point where it is
|
||||
* bound to the destination.
|
||||
* The context_width is the width of the context where the expression is
|
||||
* being elaborated, or -1 if the expression is self-determined, or -2
|
||||
* if the expression is lossless self-determined (this last option is
|
||||
* treated as standard self-determined if the gn_strict_expr_width flag
|
||||
* is set).
|
||||
*/
|
||||
class PExpr;
|
||||
|
||||
extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
|
||||
const PExpr*pe, int expr_wid,
|
||||
int prune_width =-1);
|
||||
|
||||
void probe_expr_width(Design*des, NetScope*scope, PExpr*pe);
|
||||
PExpr*pe, int context_width);
|
||||
|
||||
/*
|
||||
* This function is a variant of elab_and_eval that elaborates and
|
||||
* evaluates the arguments of a system task.
|
||||
*/
|
||||
extern NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
|
||||
unsigned arg_idx, PExpr*pe);
|
||||
/*
|
||||
* This function elaborates an expression as if it is for the r-value
|
||||
* of an assignment, The data_type_lv and expr_wid_lv are the type and
|
||||
* with of the l-value, and the expr is the expression to
|
||||
* elaborate. The result is the NetExpr elaborated and evaluated.
|
||||
* (See elab_expr.cc)
|
||||
* of an assignment, The lv_type and lv_width are the type and width
|
||||
* of the l-value, and the expr is the expression to elaborate. The
|
||||
* result is the NetExpr elaborated and evaluated. (See elab_expr.cc)
|
||||
*/
|
||||
extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
|
||||
ivl_variable_type_t data_type_lv,
|
||||
int expr_wid_lv, PExpr*expr);
|
||||
ivl_variable_type_t lv_type,
|
||||
unsigned lv_width, PExpr*expr);
|
||||
|
||||
/*
|
||||
* Used by elaboration to suppress the sign of an operand if the other
|
||||
* is unsigned.
|
||||
*/
|
||||
extern void suppress_binary_operand_sign_if_needed(NetExpr*lp, NetExpr*rp);
|
||||
|
||||
/*
|
||||
* This procedure elaborates an expression and if the elaboration is
|
||||
* This procedure evaluates an expression and if the evaluation is
|
||||
* successful the original expression is replaced with the new one.
|
||||
*/
|
||||
void eval_expr(NetExpr*&expr, int prune_width =-1);
|
||||
void eval_expr(NetExpr*&expr, int context_width =-1);
|
||||
|
||||
/*
|
||||
* Get the long integer value for the passed in expression, if
|
||||
|
|
|
|||
25
parse.y
25
parse.y
|
|
@ -426,7 +426,7 @@ static list<named_pexpr_t>* make_named_number(perm_string name, PExpr*val =0)
|
|||
%type <named_pexprs> port_name_list parameter_value_byname_list
|
||||
|
||||
%type <named_pexpr> attribute
|
||||
%type <named_pexprs> attribute_list attribute_list_opt
|
||||
%type <named_pexprs> attribute_list attribute_instance_list attribute_list_opt
|
||||
|
||||
%type <citem> case_item
|
||||
%type <citems> case_items
|
||||
|
|
@ -522,11 +522,24 @@ real_or_realtime
|
|||
variety of different objects. The syntax inside the (* *) is a
|
||||
comma separated list of names or names with assigned values. */
|
||||
attribute_list_opt
|
||||
: K_PSTAR attribute_list K_STARP { $$ = $2; }
|
||||
| K_PSTAR K_STARP { $$ = 0; }
|
||||
: attribute_instance_list
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
attribute_instance_list
|
||||
: K_PSTAR K_STARP { $$ = 0; }
|
||||
| K_PSTAR attribute_list K_STARP { $$ = $2; }
|
||||
| attribute_instance_list K_PSTAR K_STARP { $$ = $1; }
|
||||
| attribute_instance_list K_PSTAR attribute_list K_STARP
|
||||
{ list<named_pexpr_t>*tmp = $1;
|
||||
if (tmp) {
|
||||
tmp->splice(tmp->end(), *$3);
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
} else $$ = $3;
|
||||
}
|
||||
;
|
||||
|
||||
attribute_list
|
||||
: attribute_list ',' attribute
|
||||
{ list<named_pexpr_t>*tmp = $1;
|
||||
|
|
@ -2254,7 +2267,7 @@ atom2_type
|
|||
|
||||
/* An lpvalue is the expression that can go on the left side of a
|
||||
procedural assignment. This rule handles only procedural
|
||||
assignments. It is more limited then the general expr_primary
|
||||
assignments. It is more limited than the general expr_primary
|
||||
rule to reflect the rules for assignment l-values. */
|
||||
lpvalue
|
||||
: hierarchy_identifier
|
||||
|
|
@ -3924,7 +3937,7 @@ statement
|
|||
|
||||
/* assign and deassign statements are procedural code to do
|
||||
structural assignments, and to turn that structural assignment
|
||||
off. This stronger then any other assign, but weaker then the
|
||||
off. This is stronger than any other assign, but weaker than the
|
||||
force assignments. */
|
||||
|
||||
: K_assign lpvalue '=' expression ';'
|
||||
|
|
@ -3957,7 +3970,7 @@ statement
|
|||
/* begin-end blocks come in a variety of forms, including named and
|
||||
anonymous. The named blocks can also carry their own reg
|
||||
variables, which are placed in the scope created by the block
|
||||
name. These are handled by pushing the scope name then matching
|
||||
name. These are handled by pushing the scope name, then matching
|
||||
the declarations. The scope is popped at the end of the block. */
|
||||
|
||||
| K_begin statement_list K_end
|
||||
|
|
|
|||
486
set_width.cc
486
set_width.cc
|
|
@ -1,486 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
|
||||
/*
|
||||
* This file contains set_width methods for the various NetExpr
|
||||
* classes. The set_width method is used by elaboration to ask the
|
||||
* expression to resize itself. If the expression can't, then the
|
||||
* set_width method will return false and the caller will arrange for
|
||||
* whatever is needed to deal with the size mismatch.
|
||||
*/
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include "compiler.h"
|
||||
# include <typeinfo>
|
||||
|
||||
|
||||
bool NetExpr::set_width(unsigned w, bool)
|
||||
{
|
||||
cerr << get_fileline() << ": internal warning: "
|
||||
<<typeid(*this).name() << ": set_width(unsigned) "
|
||||
<< "not implemented." << endl;
|
||||
expr_width(w);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetEBinary::set_width(unsigned w, bool)
|
||||
{
|
||||
bool flag = true;
|
||||
switch (op_) {
|
||||
|
||||
case 'l': // left shift (<<)
|
||||
case 'r': // right shift (>>)
|
||||
/* these operators are handled in the derived class. */
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
/* The default rule is that the operands of the binary
|
||||
operator might as well use the same width as the
|
||||
output from the binary operation. */
|
||||
default:
|
||||
expr_width(left_->expr_width() > right_->expr_width()
|
||||
? left_->expr_width() : right_->expr_width());
|
||||
cerr << "NetEBinary::set_width(): Using default for " <<
|
||||
op_ << "." << endl;
|
||||
flag = false;
|
||||
|
||||
case '%':
|
||||
case '/':
|
||||
flag = left_->set_width(w) && flag;
|
||||
flag = right_->set_width(w) && flag;
|
||||
expr_width(w);
|
||||
break;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitwise logical operators have operands the same size as the
|
||||
* result. Anything else is a mess.
|
||||
*/
|
||||
bool NetEBAdd::set_width(unsigned w, bool)
|
||||
{
|
||||
|
||||
unsigned wid = w;
|
||||
if (left_->expr_width() > wid)
|
||||
wid = left_->expr_width();
|
||||
if (right_->expr_width() > wid)
|
||||
wid = right_->expr_width();
|
||||
|
||||
left_->set_width(wid);
|
||||
right_->set_width(wid);
|
||||
|
||||
if (left_->expr_width() < wid) {
|
||||
NetExpr*tmp = new NetESelect(left_, 0, wid);
|
||||
tmp->cast_signed(left_->has_sign());
|
||||
left_ = tmp;
|
||||
}
|
||||
|
||||
if (right_->expr_width() < wid) {
|
||||
NetExpr*tmp = new NetESelect(right_, 0, wid);
|
||||
tmp->cast_signed(right_->has_sign());
|
||||
right_ = tmp;
|
||||
}
|
||||
|
||||
expr_width(wid);
|
||||
return w == wid;
|
||||
}
|
||||
|
||||
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
|
||||
* result. Anything else is a mess. I first try to get the operands to
|
||||
* shrink to the desired size. I then expand operands that are too small.
|
||||
*/
|
||||
bool NetEBBits::set_width(unsigned w, bool)
|
||||
{
|
||||
/* First, give the operands a chance to adjust themselves to
|
||||
the requested width. */
|
||||
left_->set_width(w);
|
||||
right_->set_width(w);
|
||||
|
||||
|
||||
/* */
|
||||
|
||||
unsigned use_width = w;
|
||||
if (left_->expr_width() > use_width)
|
||||
use_width = left_->expr_width();
|
||||
if (right_->expr_width() > use_width)
|
||||
use_width = right_->expr_width();
|
||||
|
||||
/* If the operands end up too small, then pad them to suit. */
|
||||
|
||||
if (left_->expr_width() < use_width) {
|
||||
NetExpr*tmp = pad_to_width(left_, use_width, *this);
|
||||
assert(tmp);
|
||||
left_ = tmp;
|
||||
}
|
||||
|
||||
if (right_->expr_width() < w) {
|
||||
NetExpr*tmp = pad_to_width(right_, use_width, *this);
|
||||
assert(tmp);
|
||||
right_ = tmp;
|
||||
}
|
||||
|
||||
|
||||
/* And here is the final width. If this is not the size the
|
||||
caller requested, then return false. Otherwise, return
|
||||
true. */
|
||||
expr_width(use_width);
|
||||
return w == use_width;
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparison operators allow the subexpressions to have
|
||||
* their own natural width, but the comparison operator result has a
|
||||
* fixed width of 1.
|
||||
*/
|
||||
bool NetEBComp::set_width(unsigned w, bool)
|
||||
{
|
||||
return w == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is nothing we can do to the operands of a division to make it
|
||||
* confirm to the requested width. Force the context to pad or truncate.
|
||||
*/
|
||||
bool NetEBDiv::set_width(unsigned w, bool)
|
||||
{
|
||||
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 flag;
|
||||
flag = left_->set_width(right_->expr_width());
|
||||
if (!flag)
|
||||
flag = right_->set_width(left_->expr_width());
|
||||
return w == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is nothing we can do to the operands of a multiply to make it
|
||||
* confirm to the requested width. Force the context to pad or truncate.
|
||||
*/
|
||||
bool NetEBMult::set_width(unsigned w, bool)
|
||||
{
|
||||
if (w < left_->expr_width())
|
||||
left_->set_width(w);
|
||||
if (w < right_->expr_width())
|
||||
right_->expr_width();
|
||||
|
||||
expr_width(w);
|
||||
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)
|
||||
{
|
||||
return w == expr_width();
|
||||
}
|
||||
|
||||
/*
|
||||
* The shift operator allows the shift amount to have its own
|
||||
* natural width. The width of the operator result is the width of the
|
||||
* left operand, the value that is to be shifted.
|
||||
*/
|
||||
bool NetEBShift::set_width(unsigned w, bool)
|
||||
{
|
||||
switch (op()) {
|
||||
|
||||
case 'l':
|
||||
left_->set_width(w);
|
||||
if (left_->expr_width() < w)
|
||||
left_ = pad_to_width(left_, w, *this);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
if (left_->expr_width() < w)
|
||||
left_ = pad_to_width(left_, w, *this);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
expr_width(left_->expr_width());
|
||||
|
||||
return w == expr_width();
|
||||
}
|
||||
|
||||
/*
|
||||
* Add up the widths from all the expressions that are concatenated
|
||||
* together. This is the width of the expression, tough luck if you
|
||||
* want it otherwise.
|
||||
*
|
||||
* If during the course of elaboration one of the sub-expressions is
|
||||
* broken, then don't count it in the width. This doesn't really
|
||||
* matter because the null expression is indication of an error and
|
||||
* the compiler will not go beyond elaboration.
|
||||
*/
|
||||
bool NetEConcat::set_width(unsigned w, bool)
|
||||
{
|
||||
unsigned sum = 0;
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
if (parms_[idx] != 0)
|
||||
sum += parms_[idx]->expr_width();
|
||||
|
||||
sum *= repeat();
|
||||
expr_width(sum);
|
||||
return w == sum;
|
||||
}
|
||||
|
||||
bool NetEConst::set_width(unsigned w, bool last_chance)
|
||||
{
|
||||
/* Make the value signed if the NetEConst is signed.
|
||||
* This happens when $signed() is called, so this
|
||||
* sign information needs to be propagated. */
|
||||
value_.has_sign(has_sign());
|
||||
|
||||
if (w == value_.len()) {
|
||||
expr_width(w);
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(w != 0);
|
||||
|
||||
if (w > value_.len()) {
|
||||
verinum::V pad = verinum::V0;
|
||||
if (value_.has_sign()) {
|
||||
pad = value_.get(value_.len()-1);
|
||||
|
||||
/* It appears that you always have a defined length here,
|
||||
* so this logic may be in error. */
|
||||
} else if (value_.len() != 0 && !value_.has_len())
|
||||
switch (value_.get(value_.len()-1)) {
|
||||
case verinum::V1:
|
||||
case verinum::V0:
|
||||
break;
|
||||
case verinum::Vx:
|
||||
pad = verinum::Vx;
|
||||
break;
|
||||
case verinum::Vz:
|
||||
pad = verinum::Vz;
|
||||
break;
|
||||
}
|
||||
|
||||
verinum tmp (verinum::V0, w, has_width());
|
||||
for (unsigned idx = 0 ; idx < value_.len() ; idx += 1)
|
||||
tmp.set(idx, value_[idx]);
|
||||
for (unsigned idx = value_.len() ; idx < w ; idx += 1)
|
||||
tmp.set(idx, pad);
|
||||
|
||||
tmp.has_sign(value_.has_sign());
|
||||
value_ = tmp;
|
||||
|
||||
expr_width(w);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
unsigned use_w = w;
|
||||
|
||||
verinum::V pad_bit = value_.has_sign()
|
||||
? value_[value_.len() - 1]
|
||||
: verinum::V0;
|
||||
|
||||
if (! last_chance) {
|
||||
// Don't reduce a number too small to hold all the
|
||||
// significant bits.
|
||||
for (unsigned idx = w ; idx < value_.len() ; idx += 1)
|
||||
if (value_[idx] != pad_bit)
|
||||
use_w = idx+1;
|
||||
|
||||
// Correct for the special case of signed value. We
|
||||
// cannot have the result change sign on us.
|
||||
if (value_.has_sign() && (use_w < value_.len())
|
||||
&& (value_[use_w-1] != pad_bit))
|
||||
use_w += 1;
|
||||
}
|
||||
|
||||
verinum tmp (verinum::V0, use_w, has_width());
|
||||
for (unsigned idx = 0 ; idx < use_w ; idx += 1)
|
||||
tmp.set(idx, value_[idx]);
|
||||
|
||||
tmp.has_sign(value_.has_sign());
|
||||
value_ = tmp;
|
||||
expr_width(use_w);
|
||||
return w == use_w;
|
||||
}
|
||||
}
|
||||
|
||||
void NetEConst::cast_signed(bool sign_flag)
|
||||
{
|
||||
value_.has_sign(sign_flag);
|
||||
cast_signed_base_(sign_flag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parameter vectors cannot be resized because they refer to a common
|
||||
* value. Ditto for enumeration names.
|
||||
*/
|
||||
bool NetEConstParam::set_width(unsigned w, bool)
|
||||
{
|
||||
return w == expr_width();
|
||||
}
|
||||
|
||||
bool NetEConstEnum::set_width(unsigned w, bool)
|
||||
{
|
||||
return w == expr_width();
|
||||
}
|
||||
|
||||
/*
|
||||
* Real constants can have whatever width the environment wants,
|
||||
* because it isn't really a vector. The environment will convert this
|
||||
* to a vector at the right time.
|
||||
*/
|
||||
bool NetECReal::set_width(unsigned w, bool)
|
||||
{
|
||||
expr_width(w);
|
||||
return true;
|
||||
}
|
||||
#if 0
|
||||
bool NetEMemory::set_width(unsigned w, bool)
|
||||
{
|
||||
if (w != mem_->width())
|
||||
return false;
|
||||
|
||||
expr_width(w);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
bool NetESelect::set_width(unsigned, bool)
|
||||
{
|
||||
return expr_width() == 1;
|
||||
}
|
||||
|
||||
bool NetESFunc::set_width(unsigned w, bool)
|
||||
{
|
||||
return w == expr_width();
|
||||
}
|
||||
|
||||
/*
|
||||
* The signal should automatically pad with zeros to get to the desired
|
||||
* width. Do not allow signal bits to be truncated, however.
|
||||
*/
|
||||
bool NetESignal::set_width(unsigned w, bool)
|
||||
{
|
||||
return w == vector_width();
|
||||
}
|
||||
|
||||
bool NetETernary::set_width(unsigned w, bool last_chance)
|
||||
{
|
||||
bool flag = true;
|
||||
flag = flag && true_val_->set_width(w, last_chance);
|
||||
flag = flag && false_val_->set_width(w, last_chance);
|
||||
|
||||
/* The ternary really insists that the true and false clauses
|
||||
have the same width. Even if we fail to make the width that
|
||||
the user requests, at least pad the smaller width to suit
|
||||
the larger. */
|
||||
if (true_val_->expr_width() < false_val_->expr_width())
|
||||
true_val_ = pad_to_width(true_val_, false_val_->expr_width(),
|
||||
*this);
|
||||
if (false_val_->expr_width() < true_val_->expr_width())
|
||||
false_val_ = pad_to_width(false_val_, true_val_->expr_width(),
|
||||
*this);
|
||||
|
||||
expr_width(true_val_->expr_width());
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXX FIX ME: For now, just take whatever the caller says as my
|
||||
* width. What I really need to do is note the width of the output
|
||||
* parameter of the function definition and take that into account.
|
||||
*/
|
||||
bool NetEUFunc::set_width(unsigned w, bool)
|
||||
{
|
||||
return w == result_sig_->expr_width();
|
||||
}
|
||||
|
||||
bool NetEUnary::set_width(unsigned w, bool)
|
||||
{
|
||||
bool flag = true;
|
||||
switch (op_) {
|
||||
case '~':
|
||||
case '-':
|
||||
case 'r':
|
||||
case 'i':
|
||||
flag = expr_->set_width(w);
|
||||
expr_width(w);
|
||||
break;
|
||||
case '!':
|
||||
return w == 1;
|
||||
default:
|
||||
flag = expr_width() == w;
|
||||
break;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unary reduction operators allow its operand to have any width. The
|
||||
* result is defined to be 1.
|
||||
*/
|
||||
bool NetEUReduce::set_width(unsigned w, bool)
|
||||
{
|
||||
return w == 1;
|
||||
}
|
||||
|
|
@ -483,7 +483,7 @@ bool NetBlock::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/,
|
|||
substatement to the output of the block as a
|
||||
whole. It is occasionally possible to have outputs
|
||||
beyond the input set, for example when the l-value of
|
||||
an assignment is smaller then the r-value. */
|
||||
an assignment is smaller than the r-value. */
|
||||
for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) {
|
||||
unsigned ptr = find_nexus_in_set(nex_map,
|
||||
tmp_map->pin(idx).nexus());
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ void cleanup_sys_func_table()
|
|||
|
||||
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 the name in the function stack. */
|
||||
struct sfunc_return_type_cell*cur = sfunc_stack;
|
||||
while (cur) {
|
||||
if (strcmp(cur->name, name) == 0)
|
||||
|
|
|
|||
42
t-dll-api.cc
42
t-dll-api.cc
|
|
@ -436,9 +436,11 @@ extern "C" ivl_expr_t ivl_expr_oper1(ivl_expr_t net)
|
|||
assert(net);
|
||||
switch (net->type_) {
|
||||
case IVL_EX_BINARY:
|
||||
case IVL_EX_SELECT:
|
||||
return net->u_.binary_.lef_;
|
||||
|
||||
case IVL_EX_SELECT:
|
||||
return net->u_.select_.expr_;
|
||||
|
||||
case IVL_EX_UNARY:
|
||||
return net->u_.unary_.sub_;
|
||||
|
||||
|
|
@ -463,9 +465,11 @@ extern "C" ivl_expr_t ivl_expr_oper2(ivl_expr_t net)
|
|||
assert(net);
|
||||
switch (net->type_) {
|
||||
case IVL_EX_BINARY:
|
||||
case IVL_EX_SELECT:
|
||||
return net->u_.binary_.rig_;
|
||||
|
||||
case IVL_EX_SELECT:
|
||||
return net->u_.select_.base_;
|
||||
|
||||
case IVL_EX_TERNARY:
|
||||
return net->u_.ternary_.true_e;
|
||||
|
||||
|
|
@ -569,6 +573,13 @@ extern "C" ivl_scope_t ivl_expr_scope(ivl_expr_t net)
|
|||
return net->u_.scope_.scope;
|
||||
}
|
||||
|
||||
extern "C" ivl_select_type_t ivl_expr_sel_type(ivl_expr_t net)
|
||||
{
|
||||
assert(net);
|
||||
assert(net->type_ == IVL_EX_SELECT);
|
||||
return net->u_.select_.sel_type_;
|
||||
}
|
||||
|
||||
extern "C" ivl_signal_t ivl_expr_signal(ivl_expr_t net)
|
||||
{
|
||||
assert(net);
|
||||
|
|
@ -867,6 +878,14 @@ extern "C" char ivl_udp_init(ivl_udp_t net)
|
|||
return net->init;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_udp_port(ivl_udp_t net, unsigned idx)
|
||||
{
|
||||
assert(idx <= net->nin);
|
||||
assert(net->ports);
|
||||
assert(net->ports[idx].c_str());
|
||||
return net->ports[idx].c_str();
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_udp_row(ivl_udp_t net, unsigned idx)
|
||||
{
|
||||
assert(idx < net->nrows);
|
||||
|
|
@ -1459,6 +1478,12 @@ extern "C" ivl_expr_t ivl_lval_part_off(ivl_lval_t net)
|
|||
return net->loff;
|
||||
}
|
||||
|
||||
extern "C" ivl_select_type_t ivl_lval_sel_type(ivl_lval_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->sel_type;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_lval_width(ivl_lval_t net)
|
||||
{
|
||||
assert(net);
|
||||
|
|
@ -1903,7 +1928,8 @@ extern "C" ivl_scope_t ivl_scope_parent(ivl_scope_t net)
|
|||
extern "C" unsigned ivl_scope_ports(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
if (net->type_ == IVL_SCT_FUNCTION ||
|
||||
if (net->type_ == IVL_SCT_MODULE ||
|
||||
net->type_ == IVL_SCT_FUNCTION ||
|
||||
net->type_ == IVL_SCT_TASK) return net->ports;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1914,7 +1940,15 @@ extern "C" ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx)
|
|||
assert(net->type_ == IVL_SCT_FUNCTION ||
|
||||
net->type_ == IVL_SCT_TASK);
|
||||
assert(idx < net->ports);
|
||||
return net->port[idx];
|
||||
return net->u_.port[idx];
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_scope_mod_port(ivl_scope_t net, unsigned idx)
|
||||
{
|
||||
assert(net);
|
||||
assert(net->type_ == IVL_SCT_MODULE);
|
||||
assert(idx < net->ports);
|
||||
return net->u_.nex[idx];
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_sigs(ivl_scope_t net)
|
||||
|
|
|
|||
|
|
@ -274,8 +274,8 @@ void dll_target::expr_param(const NetEConstParam*net)
|
|||
<< ivl_scope_name(scop) << endl;
|
||||
}
|
||||
assert(par);
|
||||
assert(par->value);
|
||||
expr_ = par->value;
|
||||
expr_const(net);
|
||||
expr_->u_.string_.parameter = par;
|
||||
}
|
||||
|
||||
void dll_target::expr_rparam(const NetECRealParam*net)
|
||||
|
|
@ -359,13 +359,13 @@ void dll_target::expr_select(const NetESelect*net)
|
|||
assert(expr_ == 0);
|
||||
|
||||
net->sub_expr()->expr_scan(this);
|
||||
ivl_expr_t left = expr_;
|
||||
ivl_expr_t expr = expr_;
|
||||
|
||||
expr_ = 0;
|
||||
if (net->select())
|
||||
net->select()->expr_scan(this);
|
||||
|
||||
ivl_expr_t rght = expr_;
|
||||
ivl_expr_t base = expr_;
|
||||
|
||||
expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
|
||||
|
||||
|
|
@ -376,8 +376,9 @@ void dll_target::expr_select(const NetESelect*net)
|
|||
expr_->sized_= 1;
|
||||
FILE_NAME(expr_, net);
|
||||
|
||||
expr_->u_.binary_.lef_ = left;
|
||||
expr_->u_.binary_.rig_ = rght;
|
||||
expr_->u_.select_.sel_type_ = net->select_type();
|
||||
expr_->u_.select_.expr_ = expr;
|
||||
expr_->u_.select_.base_ = base;
|
||||
}
|
||||
|
||||
void dll_target::expr_sfunc(const NetESFunc*net)
|
||||
|
|
|
|||
|
|
@ -88,9 +88,9 @@ void dll_target::task_def(const NetScope*net)
|
|||
|
||||
scop->ports = def->port_count();
|
||||
if (scop->ports > 0) {
|
||||
scop->port = new ivl_signal_t[scop->ports];
|
||||
scop->u_.port = new ivl_signal_t[scop->ports];
|
||||
for (unsigned idx = 0 ; idx < scop->ports ; idx += 1)
|
||||
scop->port[idx] = find_signal(des_, def->port(idx));
|
||||
scop->u_.port[idx] = find_signal(des_, def->port(idx));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -110,9 +110,9 @@ bool dll_target::func_def(const NetScope*net)
|
|||
|
||||
scop->ports = def->port_count() + 1;
|
||||
if (scop->ports > 0) {
|
||||
scop->port = new ivl_signal_t[scop->ports];
|
||||
scop->u_.port = new ivl_signal_t[scop->ports];
|
||||
for (unsigned idx = 1 ; idx < scop->ports ; idx += 1)
|
||||
scop->port[idx] = find_signal(des_, def->port(idx-1));
|
||||
scop->u_.port[idx] = find_signal(des_, def->port(idx-1));
|
||||
}
|
||||
|
||||
/* FIXME: the ivl_target API expects port-0 to be the output
|
||||
|
|
@ -121,7 +121,7 @@ bool dll_target::func_def(const NetScope*net)
|
|||
this, but that will break code generators that use this
|
||||
result. */
|
||||
if (const NetNet*ret_sig = def->return_sig()) {
|
||||
scop->port[0] = find_signal(des_, ret_sig);
|
||||
scop->u_.port[0] = find_signal(des_, ret_sig);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -153,9 +153,11 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net)
|
|||
|
||||
if (loff == 0) {
|
||||
cur->loff = 0;
|
||||
cur->sel_type = IVL_SEL_OTHER;
|
||||
} else {
|
||||
loff->expr_scan(this);
|
||||
cur->loff = expr_;
|
||||
cur->sel_type = asn->select_type();
|
||||
expr_ = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
91
t-dll.cc
91
t-dll.cc
|
|
@ -563,6 +563,13 @@ void dll_target::add_root(ivl_design_s &des__, const NetScope *s)
|
|||
root_->attr = fill_in_attributes(s);
|
||||
root_->is_auto = 0;
|
||||
root_->is_cell = s->is_cell();
|
||||
root_->ports = s->module_ports();
|
||||
if (root_->ports > 0) {
|
||||
root_->u_.net = new NetNet*[root_->ports];
|
||||
for (unsigned idx = 0; idx < root_->ports; idx += 1) {
|
||||
root_->u_.net[idx] = s->module_port(idx);
|
||||
}
|
||||
}
|
||||
|
||||
des__.nroots_++;
|
||||
if (des__.roots_)
|
||||
|
|
@ -1270,38 +1277,36 @@ void dll_target::udp(const NetUDP*net)
|
|||
static map<perm_string,ivl_udp_t> udps;
|
||||
ivl_udp_t u;
|
||||
|
||||
if (udps.find(net->udp_name()) != udps.end())
|
||||
{
|
||||
u = udps[net->udp_name()];
|
||||
}
|
||||
else
|
||||
{
|
||||
u = new struct ivl_udp_s;
|
||||
u->nrows = net->rows();
|
||||
u->table = (ivl_udp_s::ccharp_t*)malloc((u->nrows+1)*sizeof(char*));
|
||||
u->table[u->nrows] = 0x0;
|
||||
u->nin = net->nin();
|
||||
u->sequ = net->is_sequential();
|
||||
u->file = net->udp_file();
|
||||
u->lineno = net->udp_lineno();
|
||||
if (u->sequ)
|
||||
u->init = net->get_initial();
|
||||
else
|
||||
u->init = 'x';
|
||||
u->name = net->udp_name();
|
||||
string inp;
|
||||
char out;
|
||||
unsigned int i = 0;
|
||||
if (net->first(inp, out))
|
||||
do
|
||||
{
|
||||
string tt = inp+out;
|
||||
u->table[i++] = strings_.add(tt.c_str());
|
||||
} while (net->next(inp, out));
|
||||
assert(i==u->nrows);
|
||||
if (udps.find(net->udp_name()) != udps.end()) {
|
||||
u = udps[net->udp_name()];
|
||||
} else {
|
||||
u = new struct ivl_udp_s;
|
||||
u->nrows = net->rows();
|
||||
u->table = (ivl_udp_s::ccharp_t*)malloc((u->nrows+1)*sizeof(char*));
|
||||
u->table[u->nrows] = 0x0;
|
||||
u->nin = net->nin();
|
||||
u->sequ = net->is_sequential();
|
||||
u->file = net->udp_file();
|
||||
u->lineno = net->udp_lineno();
|
||||
if (u->sequ) u->init = net->get_initial();
|
||||
else u->init = 'x';
|
||||
u->name = net->udp_name();
|
||||
string inp;
|
||||
char out;
|
||||
unsigned int i = 0;
|
||||
if (net->first(inp, out)) do {
|
||||
string tt = inp+out;
|
||||
u->table[i++] = strings_.add(tt.c_str());
|
||||
} while (net->next(inp, out));
|
||||
assert(i==u->nrows);
|
||||
assert((u->nin + 1) == net->port_count());
|
||||
u->ports = new string [u->nin + 1];
|
||||
for(unsigned idx = 0; idx <= u->nin; idx += 1) {
|
||||
u->ports[idx] = net->port_name(idx);
|
||||
}
|
||||
|
||||
udps[net->udp_name()] = u;
|
||||
}
|
||||
udps[net->udp_name()] = u;
|
||||
}
|
||||
|
||||
obj->udp = u;
|
||||
|
||||
|
|
@ -2275,6 +2280,7 @@ void dll_target::scope(const NetScope*net)
|
|||
FILE_NAME(scop, net);
|
||||
scop->parent = find_scope(des_, net->parent());
|
||||
assert(scop->parent);
|
||||
scop->parent->children[net->fullname()] = scop;
|
||||
scop->nsigs_ = 0;
|
||||
scop->sigs_ = 0;
|
||||
scop->nlog_ = 0;
|
||||
|
|
@ -2296,6 +2302,13 @@ void dll_target::scope(const NetScope*net)
|
|||
case NetScope::MODULE:
|
||||
scop->type_ = IVL_SCT_MODULE;
|
||||
scop->tname_ = net->module_name();
|
||||
scop->ports = net->module_ports();
|
||||
if (scop->ports > 0) {
|
||||
scop->u_.net = new NetNet*[scop->ports];
|
||||
for (unsigned idx = 0; idx < scop->ports; idx += 1) {
|
||||
scop->u_.net[idx] = net->module_port(idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetScope::TASK: {
|
||||
const NetTaskDef*def = net->task_def();
|
||||
|
|
@ -2326,10 +2339,20 @@ void dll_target::scope(const NetScope*net)
|
|||
scop->tname_ = scop->name_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(scop->parent != 0);
|
||||
|
||||
scop->parent->children[net->fullname()] = scop;
|
||||
void dll_target::convert_module_ports(const NetScope*net)
|
||||
{
|
||||
ivl_scope_t scop = find_scope(des_, net);
|
||||
if (scop->ports > 0) {
|
||||
NetNet**nets = scop->u_.net;
|
||||
scop->u_.nex = new ivl_nexus_t[scop->ports];
|
||||
for (unsigned idx = 0; idx < scop->ports; idx += 1) {
|
||||
ivl_signal_t sig = find_signal(des_, nets[idx]);
|
||||
scop->u_.nex[idx] = nexus_sig_make(sig, 0);
|
||||
}
|
||||
delete nets;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
17
t-dll.h
17
t-dll.h
|
|
@ -93,6 +93,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
|||
bool process(const NetProcTop*);
|
||||
bool process(const NetAnalogTop*);
|
||||
void scope(const NetScope*);
|
||||
void convert_module_ports(const NetScope*);
|
||||
void signal(const NetNet*);
|
||||
bool signal_paths(const NetNet*);
|
||||
ivl_dll_t dll_;
|
||||
|
|
@ -231,6 +232,12 @@ struct ivl_expr_s {
|
|||
ivl_expr_t rig_;
|
||||
} binary_;
|
||||
|
||||
struct {
|
||||
ivl_select_type_t sel_type_;
|
||||
ivl_expr_t expr_;
|
||||
ivl_expr_t base_;
|
||||
} select_;
|
||||
|
||||
struct {
|
||||
ivl_branch_t branch;
|
||||
ivl_nature_t nature;
|
||||
|
|
@ -427,6 +434,7 @@ enum ivl_lval_type_t {
|
|||
|
||||
struct ivl_lval_s {
|
||||
ivl_expr_t loff;
|
||||
ivl_select_type_t sel_type;
|
||||
ivl_expr_t idx;
|
||||
unsigned width_;
|
||||
unsigned type_ : 8;
|
||||
|
|
@ -517,6 +525,7 @@ struct ivl_udp_s {
|
|||
ccharp_t*table; // zero terminated array of pointers
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
string*ports;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -599,7 +608,7 @@ struct ivl_process_s {
|
|||
/*
|
||||
* Scopes are kept in a tree. Each scope points to its first child,
|
||||
* and also to any siblings. Thus a parent can scan all its children
|
||||
* by following its child pointer then following sibling pointers from
|
||||
* by following its child pointer, then following sibling pointers from
|
||||
* there.
|
||||
*/
|
||||
struct ivl_scope_s {
|
||||
|
|
@ -638,7 +647,11 @@ struct ivl_scope_s {
|
|||
unsigned is_cell;
|
||||
|
||||
unsigned ports;
|
||||
ivl_signal_t*port;
|
||||
union {
|
||||
ivl_signal_t*port;
|
||||
ivl_nexus_t*nex;
|
||||
NetNet**net;
|
||||
} u_;
|
||||
|
||||
std::vector<ivl_switch_t>switches;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2010 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2011 Stephen Williams <steve@icarus.com>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -32,6 +32,10 @@ void target_t::scope(const NetScope*)
|
|||
{
|
||||
}
|
||||
|
||||
void target_t::convert_module_ports(const NetScope*)
|
||||
{
|
||||
}
|
||||
|
||||
bool target_t::branch(const NetBranch*obj)
|
||||
{
|
||||
cerr << obj->get_fileline() << ": error: target (" << typeid(*this).name()
|
||||
|
|
|
|||
6
target.h
6
target.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __target_H
|
||||
#define __target_H
|
||||
/*
|
||||
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -56,6 +56,10 @@ struct target_t {
|
|||
anything else is called. */
|
||||
virtual void scope(const NetScope*);
|
||||
|
||||
/* This is called to convert module ports from a NetNet* to an
|
||||
* ivl_signal_t object. */
|
||||
virtual void convert_module_ports(const NetScope*);
|
||||
|
||||
/* Output an event object. Called for each named event in the scope. */
|
||||
virtual void event(const NetEvent*);
|
||||
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ static void virtex_or_wide(ivl_net_logic_t net)
|
|||
|
||||
/*
|
||||
* Pick off the cases where there is a Virtex specific implementation
|
||||
* that is better then the generic Xilinx implementation. Route the
|
||||
* that is better than the generic Xilinx implementation. Route the
|
||||
* remaining to the base xilinx_logic implementation.
|
||||
*/
|
||||
void virtex_logic(ivl_net_logic_t net)
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ vhdl_expr *vhdl_expr::to_string()
|
|||
{
|
||||
bool numeric = type_->get_name() == VHDL_TYPE_UNSIGNED
|
||||
|| type_->get_name() == VHDL_TYPE_SIGNED;
|
||||
|
||||
|
||||
if (numeric) {
|
||||
vhdl_fcall *image = new vhdl_fcall("integer'image", vhdl_type::string());
|
||||
image->add_expr(this->cast(vhdl_type::integer()));
|
||||
|
|
|
|||
|
|
@ -473,8 +473,18 @@ static vhdl_expr *translate_select(ivl_expr_t e)
|
|||
// We can't directly select bits from something that's not
|
||||
// a variable reference in VHDL, but we can emulate the
|
||||
// effect with a shift and a resize
|
||||
return new vhdl_binop_expr(from, VHDL_BINOP_SR, base->to_integer(),
|
||||
new vhdl_type(*from->get_type()));
|
||||
|
||||
if (ivl_expr_signed(ivl_expr_oper1(e))) {
|
||||
vhdl_fcall *sra = new vhdl_fcall("shift_right", from->get_type());
|
||||
sra->add_expr(from);
|
||||
sra->add_expr(base->to_integer());
|
||||
|
||||
return sra;
|
||||
}
|
||||
else
|
||||
return new vhdl_binop_expr(from, VHDL_BINOP_SR, base->to_integer(),
|
||||
from->get_type());
|
||||
|
||||
}
|
||||
else if (from_var_ref->get_type()->get_name() != VHDL_TYPE_STD_LOGIC) {
|
||||
// We can use the more idiomatic VHDL slice notation on a
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc)
|
|||
// will optimise the process out of the output
|
||||
bool is_initial = ivl_process_type(proc) == IVL_PR_INITIAL;
|
||||
bool is_empty = vhdl_proc->get_container()->empty();
|
||||
|
||||
|
||||
if (is_initial && !is_empty) {
|
||||
vhdl_wait_stmt *wait = new vhdl_wait_stmt();
|
||||
vhdl_proc->get_container()->add_stmt(wait);
|
||||
|
|
|
|||
|
|
@ -945,7 +945,7 @@ static void create_skeleton_entity_for(ivl_scope_t scope, int depth)
|
|||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
arch->set_comment(ss.str());
|
||||
ent->set_comment(ss.str());
|
||||
|
||||
|
|
|
|||
|
|
@ -187,8 +187,8 @@ vhdl_entity* find_entity(ivl_scope_t scope)
|
|||
return NULL;
|
||||
}
|
||||
else {
|
||||
const char *tname = ivl_scope_tname(scope);
|
||||
|
||||
const char *tname = ivl_scope_tname(scope);
|
||||
|
||||
for (scope_name_map_t::iterator it = g_scope_names.begin();
|
||||
it != g_scope_names.end(); ++it) {
|
||||
if (strcmp(tname, ivl_scope_tname((*it).first)) == 0)
|
||||
|
|
@ -248,8 +248,8 @@ void set_active_entity(vhdl_entity *ent)
|
|||
static bool same_scope_type_name(ivl_scope_t a, ivl_scope_t b)
|
||||
{
|
||||
if (strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) != 0)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
|
||||
unsigned nparams_a = ivl_scope_params(a);
|
||||
unsigned nparams_b = ivl_scope_params(b);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
static void emit_wait_for_0(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt, vhdl_expr *expr);
|
||||
|
||||
|
||||
/*
|
||||
* VHDL has no real equivalent of Verilog's $finish task. The
|
||||
* current solution is to use `assert false ...' to terminate
|
||||
|
|
@ -79,7 +79,7 @@ static int draw_stask_display(vhdl_procedural *proc,
|
|||
{
|
||||
vhdl_binop_expr *text = new vhdl_binop_expr(VHDL_BINOP_CONCAT,
|
||||
vhdl_type::string());
|
||||
|
||||
|
||||
const int count = ivl_stmt_parm_count(stmt);
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
|
|
@ -91,7 +91,7 @@ static int draw_stask_display(vhdl_procedural *proc,
|
|||
text->add_expr(new vhdl_const_string(" "));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (ivl_expr_type(net) == IVL_EX_STRING) {
|
||||
ostringstream ss;
|
||||
for (const char *p = ivl_expr_string(net); *p; p++) {
|
||||
|
|
@ -110,7 +110,7 @@ static int draw_stask_display(vhdl_procedural *proc,
|
|||
// Flush the output string up to this point
|
||||
text->add_expr(new vhdl_const_string(ss.str()));
|
||||
ss.str("");
|
||||
|
||||
|
||||
// Skip over width for now
|
||||
while (isdigit(*p)) ++p;
|
||||
|
||||
|
|
@ -125,13 +125,13 @@ static int draw_stask_display(vhdl_procedural *proc,
|
|||
assert(i < count);
|
||||
ivl_expr_t netp = ivl_stmt_parm(stmt, i++);
|
||||
assert(netp);
|
||||
|
||||
|
||||
vhdl_expr *base = translate_expr(netp);
|
||||
if (NULL == base)
|
||||
return 1;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, base);
|
||||
|
||||
|
||||
text->add_expr(base->cast(text->get_type()));
|
||||
}
|
||||
}
|
||||
|
|
@ -141,16 +141,16 @@ static int draw_stask_display(vhdl_procedural *proc,
|
|||
}
|
||||
|
||||
// Emit any non-empty string data left in the buffer
|
||||
if (!ss.str().empty())
|
||||
if (!ss.str().empty())
|
||||
text->add_expr(new vhdl_const_string(ss.str()));
|
||||
}
|
||||
else {
|
||||
vhdl_expr *base = translate_expr(net);
|
||||
if (NULL == base)
|
||||
if (NULL == base)
|
||||
return 1;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, base);
|
||||
|
||||
|
||||
text->add_expr(base->cast(text->get_type()));
|
||||
}
|
||||
}
|
||||
|
|
@ -158,7 +158,7 @@ static int draw_stask_display(vhdl_procedural *proc,
|
|||
if (count == 0)
|
||||
text->add_expr(new vhdl_const_string(""));
|
||||
|
||||
container->add_stmt(new vhdl_report_stmt(text));
|
||||
container->add_stmt(new vhdl_report_stmt(text));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -397,7 +397,7 @@ static void emit_wait_for_0(vhdl_procedural *proc,
|
|||
<< ivl_stmt_file(stmt)
|
||||
<< ":" << ivl_stmt_lineno(stmt) << ")";
|
||||
wait->set_comment(ss.str());
|
||||
|
||||
|
||||
container->add_stmt(wait);
|
||||
proc->added_wait_stmt();
|
||||
}
|
||||
|
|
@ -451,7 +451,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
assign_type = decl->assignment_type();
|
||||
|
||||
if (assign_type == vhdl_decl::ASSIGN_NONBLOCK && emul_blocking)
|
||||
proc->add_blocking_target(lhs);
|
||||
proc->add_blocking_target(lhs);
|
||||
|
||||
// A small optimisation is to expand ternary RHSs into an
|
||||
// if statement (eliminates a function call and produces
|
||||
|
|
@ -589,7 +589,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
width_so_far += lval_width;
|
||||
|
||||
if (assign_type == vhdl_decl::ASSIGN_NONBLOCK && emul_blocking)
|
||||
proc->add_blocking_target(*it);
|
||||
proc->add_blocking_target(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -615,9 +615,9 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container,
|
|||
{
|
||||
vhdl_decl::assign_type_t assign_type = vhdl_decl::ASSIGN_NONBLOCK;
|
||||
bool emulate_blocking = proc->get_scope()->allow_signal_assignment();
|
||||
|
||||
|
||||
make_assignment(proc, container, stmt, emulate_blocking, assign_type);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -645,7 +645,7 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container,
|
|||
if (NULL == time)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt);
|
||||
vhdl_wait_stmt *wait =
|
||||
new vhdl_wait_stmt(VHDL_WAIT_FOR, time);
|
||||
|
|
@ -665,8 +665,8 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container,
|
|||
// Any further assignments occur after simulation time 0
|
||||
// so they cannot be used to initialise signal declarations
|
||||
// (if this scope is an initial process)
|
||||
proc->get_scope()->set_initializing(false);
|
||||
|
||||
proc->get_scope()->set_initializing(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -939,7 +939,7 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container,
|
|||
else {
|
||||
// Build a test expression to represent the edge event
|
||||
// If this process contains no `wait' statements and this
|
||||
// is the top-level container then we
|
||||
// is the top-level container, then we
|
||||
// wrap it in an `if' statement with this test and add the
|
||||
// edge triggered signals to the sensitivity, otherwise
|
||||
// build a `wait until' statement at the top of the process
|
||||
|
|
@ -1022,10 +1022,10 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container,
|
|||
return 1;
|
||||
|
||||
emit_wait_for_0(proc, container, stmt, test);
|
||||
|
||||
|
||||
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
|
||||
container->add_stmt(vhdif);
|
||||
|
||||
|
||||
ivl_statement_t cond_true_stmt = ivl_stmt_cond_true(stmt);
|
||||
if (cond_true_stmt)
|
||||
draw_stmt(proc, vhdif->get_then_container(), cond_true_stmt, is_last);
|
||||
|
|
@ -1555,7 +1555,7 @@ int draw_while(vhdl_procedural *proc, stmt_container *container,
|
|||
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
|
||||
|
||||
emit_wait_for_0(proc, loop->get_container(), stmt, test);
|
||||
|
||||
|
||||
container->add_stmt(loop);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ bool vhdl_procedural::is_blocking_target(vhdl_var_ref* ref) const
|
|||
{
|
||||
return blocking_targets_.find(ref->get_name()) != blocking_targets_.end();
|
||||
}
|
||||
|
||||
|
||||
void vhdl_process::add_sensitivity(const std::string &name)
|
||||
{
|
||||
sens_.push_back(name);
|
||||
|
|
@ -283,7 +283,7 @@ void stmt_container::find_vars(vhdl_var_set_t& read,
|
|||
|
||||
for (stmt_list_t::const_iterator it = stmts_.begin();
|
||||
it != stmts_.end(); ++it)
|
||||
(*it)->find_vars(read, write);
|
||||
(*it)->find_vars(read, write);
|
||||
}
|
||||
|
||||
void stmt_container::emit(std::ostream &of, int level, bool newline) const
|
||||
|
|
@ -800,7 +800,7 @@ void vhdl_report_stmt::emit(ostream& of, int level) const
|
|||
const char *levels[] = { "note", "warning", "error", "failure" };
|
||||
of << " severity " << levels[severity_];
|
||||
}
|
||||
|
||||
|
||||
of << ";";
|
||||
}
|
||||
|
||||
|
|
@ -812,7 +812,7 @@ void vhdl_report_stmt::find_vars(vhdl_var_set_t& read, vhdl_var_set_t& write)
|
|||
vhdl_assert_stmt::vhdl_assert_stmt(const char *reason)
|
||||
: vhdl_report_stmt(new vhdl_const_string(reason), SEVERITY_FAILURE)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void vhdl_assert_stmt::emit(std::ostream &of, int level) const
|
||||
|
|
@ -876,7 +876,7 @@ void vhdl_if_stmt::find_vars(vhdl_var_set_t& read,
|
|||
it != elsif_parts_.end(); ++it) {
|
||||
(*it).test->find_vars(read);
|
||||
(*it).container->find_vars(read, write);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vhdl_expr::paren_levels(0);
|
||||
|
|
@ -890,7 +890,7 @@ void vhdl_expr::open_parens(std::ostream& of)
|
|||
void vhdl_expr::close_parens(std::ostream& of)
|
||||
{
|
||||
assert(paren_levels > 0);
|
||||
|
||||
|
||||
if (--paren_levels > 0)
|
||||
of << ")";
|
||||
}
|
||||
|
|
@ -908,7 +908,7 @@ void vhdl_unaryop_expr::find_vars(vhdl_var_set_t& read)
|
|||
void vhdl_unaryop_expr::emit(std::ostream &of, int level) const
|
||||
{
|
||||
open_parens(of);
|
||||
|
||||
|
||||
switch (op_) {
|
||||
case VHDL_UNARYOP_NOT:
|
||||
of << "not ";
|
||||
|
|
@ -923,7 +923,7 @@ void vhdl_unaryop_expr::emit(std::ostream &of, int level) const
|
|||
}
|
||||
|
||||
vhdl_binop_expr::vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op,
|
||||
vhdl_expr *right, vhdl_type *type)
|
||||
vhdl_expr *right, const vhdl_type *type)
|
||||
: vhdl_expr(type), op_(op)
|
||||
{
|
||||
add_expr(left);
|
||||
|
|
@ -944,7 +944,7 @@ void vhdl_binop_expr::find_vars(vhdl_var_set_t& read)
|
|||
{
|
||||
for (list<vhdl_expr*>::const_iterator it = operands_.begin();
|
||||
it != operands_.end(); ++it)
|
||||
(*it)->find_vars(read);
|
||||
(*it)->find_vars(read);
|
||||
}
|
||||
|
||||
void vhdl_binop_expr::emit(std::ostream &of, int level) const
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ public:
|
|||
virtual vhdl_expr *to_vector(vhdl_type_name_t name, int w);
|
||||
virtual vhdl_expr *to_string();
|
||||
virtual void find_vars(vhdl_var_set_t& read) {}
|
||||
|
||||
|
||||
protected:
|
||||
static void open_parens(ostream& of);
|
||||
static void close_parens(ostream& of);
|
||||
static int paren_levels;
|
||||
|
||||
|
||||
const vhdl_type *type_;
|
||||
bool isconst_;
|
||||
};
|
||||
|
|
@ -119,10 +119,10 @@ enum vhdl_binop_t {
|
|||
*/
|
||||
class vhdl_binop_expr : public vhdl_expr {
|
||||
public:
|
||||
vhdl_binop_expr(vhdl_binop_t op, vhdl_type *type)
|
||||
vhdl_binop_expr(vhdl_binop_t op, const vhdl_type *type)
|
||||
: vhdl_expr(type), op_(op) {}
|
||||
vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op,
|
||||
vhdl_expr *right, vhdl_type *type);
|
||||
vhdl_expr *right, const vhdl_type *type);
|
||||
~vhdl_binop_expr();
|
||||
|
||||
void add_expr(vhdl_expr *e);
|
||||
|
|
@ -271,7 +271,7 @@ private:
|
|||
*/
|
||||
class vhdl_fcall : public vhdl_expr {
|
||||
public:
|
||||
vhdl_fcall(const string& name, vhdl_type *rtype)
|
||||
vhdl_fcall(const string& name, const vhdl_type *rtype)
|
||||
: vhdl_expr(rtype), name_(name) {};
|
||||
~vhdl_fcall() {}
|
||||
|
||||
|
|
@ -820,7 +820,7 @@ public:
|
|||
// Managing set of blocking assignment targets in this block
|
||||
void add_blocking_target(vhdl_var_ref* ref);
|
||||
bool is_blocking_target(vhdl_var_ref* ref) const;
|
||||
|
||||
|
||||
protected:
|
||||
stmt_container stmts_;
|
||||
vhdl_scope scope_;
|
||||
|
|
|
|||
|
|
@ -62,8 +62,10 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
/* We have a named event if there were no edge events. */
|
||||
if (!had_edge) {
|
||||
ivl_scope_t ev_scope = ivl_event_scope(event);
|
||||
if (first) first = 0;
|
||||
else fprintf(vlog_out, " or ");
|
||||
emit_scope_module_path(scope, ev_scope);
|
||||
fprintf(vlog_out, "%s", ivl_event_basename(event));
|
||||
emit_id(ivl_event_basename(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr,
|
|||
static void emit_expr_array(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
emit_scope_module_path(scope, ivl_signal_scope(sig));
|
||||
fprintf(vlog_out, "%s", ivl_signal_basename(sig));
|
||||
emit_scope_call_path(scope, ivl_signal_scope(sig));
|
||||
emit_id(ivl_signal_basename(sig));
|
||||
}
|
||||
|
||||
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
|
|
@ -142,9 +142,13 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
fprintf(vlog_out, " %s ", oper);
|
||||
emit_expr(scope, ivl_expr_oper2(expr), 0);
|
||||
break;
|
||||
case 'R':
|
||||
fprintf(stderr, "%s:%u: vlog95 error: >>> operator is not "
|
||||
"supported.\n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
case 'l':
|
||||
case 'r':
|
||||
case 'R':
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
fprintf(vlog_out, " %s ", oper);
|
||||
emit_expr(scope, ivl_expr_oper2(expr), 0);
|
||||
|
|
@ -215,13 +219,24 @@ static void emit_expr_event(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
assert(! ivl_event_nany(event));
|
||||
assert(! ivl_event_npos(event));
|
||||
assert(! ivl_event_nneg(event));
|
||||
emit_scope_module_path(scope, ev_scope);
|
||||
fprintf(vlog_out, "%s", ivl_event_basename(event));
|
||||
emit_scope_call_path(scope, ev_scope);
|
||||
emit_id(ivl_event_basename(event));
|
||||
}
|
||||
|
||||
static void emit_expr_scope_piece(ivl_scope_t scope)
|
||||
{
|
||||
ivl_scope_t parent = ivl_scope_parent(scope);
|
||||
/* If this scope has a parent then emit it first. */
|
||||
if (parent) {
|
||||
emit_expr_scope_piece(parent);
|
||||
fprintf(vlog_out, ".");
|
||||
}
|
||||
emit_id(ivl_scope_basename(scope));
|
||||
}
|
||||
|
||||
static void emit_expr_scope(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
fprintf(vlog_out, "%s", ivl_scope_name(ivl_expr_scope(expr)));
|
||||
emit_expr_scope_piece(ivl_expr_scope(expr));
|
||||
}
|
||||
|
||||
static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr)
|
||||
|
|
@ -254,7 +269,7 @@ static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr)
|
|||
break;
|
||||
}
|
||||
}
|
||||
fprintf(vlog_out, "%s", ivl_parameter_basename(par));
|
||||
emit_id(ivl_parameter_basename(par));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -263,7 +278,7 @@ static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr)
|
|||
|
||||
static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
/* A select of a number is reall a parameter select. */
|
||||
/* A select of a number is really a parameter select. */
|
||||
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
|
||||
/* Look in the current scope. */
|
||||
if (emit_param_name_in_scope(scope, expr)) return;
|
||||
|
|
@ -280,41 +295,129 @@ static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
fprintf(stderr, "%s:%u: vlog95 error: Unable to find parameter "
|
||||
"for select expression \n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
} else {
|
||||
emit_expr(scope, expr, wid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit an indexed part select as a concatenation of bit selects.
|
||||
*/
|
||||
static void emit_expr_ips(ivl_scope_t scope, ivl_expr_t sig_expr,
|
||||
ivl_expr_t sel_expr, ivl_select_type_t sel_type,
|
||||
unsigned wid, int msb, int lsb)
|
||||
{
|
||||
unsigned idx;
|
||||
assert(wid > 0);
|
||||
fprintf(vlog_out, "{");
|
||||
if (msb >= lsb) {
|
||||
if (sel_type == IVL_SEL_IDX_DOWN) {
|
||||
lsb += wid - 1;
|
||||
msb += wid - 1;
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]");
|
||||
for (idx = 1; idx < wid; idx += 1) {
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, " - %u]", idx);
|
||||
}
|
||||
fprintf(vlog_out, "}");
|
||||
} else {
|
||||
assert(sel_type == IVL_SEL_IDX_UP);
|
||||
for (idx = wid - 1; idx > 0; idx -= 1) {
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, " + %u], ", idx);
|
||||
}
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]}");
|
||||
}
|
||||
} else {
|
||||
if (sel_type == IVL_SEL_IDX_UP) {
|
||||
lsb -= wid - 1;
|
||||
msb -= wid - 1;
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]");
|
||||
for (idx = 1; idx < wid; idx += 1) {
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, " + %u]", idx);
|
||||
}
|
||||
fprintf(vlog_out, "}");
|
||||
} else {
|
||||
assert(sel_type == IVL_SEL_IDX_DOWN);
|
||||
for (idx = wid - 1; idx > 0; idx -= 1) {
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, " - %u], ", idx);
|
||||
}
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
ivl_expr_t sel_expr = ivl_expr_oper2(expr);
|
||||
ivl_expr_t sig_expr = ivl_expr_oper1(expr);
|
||||
ivl_select_type_t sel_type = ivl_expr_sel_type(expr);
|
||||
if (sel_expr) {
|
||||
int msb = 1;
|
||||
int lsb = 0;
|
||||
unsigned width = ivl_expr_width(expr);
|
||||
ivl_expr_type_t type = ivl_expr_type(sig_expr);
|
||||
assert(width > 0);
|
||||
if (type == IVL_EX_SIGNAL) {
|
||||
ivl_signal_t sig = ivl_expr_signal(sig_expr);
|
||||
msb = ivl_signal_msb(sig);
|
||||
lsb = ivl_signal_lsb(sig);
|
||||
}
|
||||
/* The compiler uses selects for some shifts. */
|
||||
if (type != IVL_EX_NUMBER && type != IVL_EX_SIGNAL) {
|
||||
fprintf(vlog_out, "(" );
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, " >> " );
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
emit_scaled_expr(scope, sel_expr, 1, 0);
|
||||
fprintf(vlog_out, ")" );
|
||||
} else {
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
/* A constant/parameter must be zero based in 1364-1995
|
||||
* so keep the compiler generated normalization. This
|
||||
* does not always work for selects before the parameter
|
||||
* since 1364-1995 does not support signed math. */
|
||||
int msb = 1;
|
||||
int lsb = 0;
|
||||
if (type == IVL_EX_SIGNAL) {
|
||||
ivl_signal_t sig = ivl_expr_signal(sig_expr);
|
||||
msb = ivl_signal_msb(sig);
|
||||
lsb = ivl_signal_lsb(sig);
|
||||
}
|
||||
/* A bit select. */
|
||||
if (width == 1) {
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]");
|
||||
} else {
|
||||
emit_scaled_range(scope, sel_expr, width, msb, lsb);
|
||||
if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) {
|
||||
/* A constant part select. */
|
||||
emit_select_name(scope, sig_expr, wid);
|
||||
emit_scaled_range(scope, sel_expr, width,
|
||||
msb, lsb);
|
||||
} else {
|
||||
/* An indexed part select. */
|
||||
assert(sel_type != IVL_SEL_OTHER);
|
||||
emit_expr_ips(scope, sig_expr, sel_expr,
|
||||
sel_type, width, msb, lsb);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -326,11 +429,10 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
/*
|
||||
* This routine is used to emit both system and user functions.
|
||||
*/
|
||||
static void emit_expr_func(ivl_scope_t scope, ivl_expr_t expr, const char* name)
|
||||
static void emit_expr_func(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
unsigned count = ivl_expr_parms(expr);
|
||||
fprintf(vlog_out, "%s", name);
|
||||
if (count != 0) {
|
||||
if (count) {
|
||||
unsigned idx;
|
||||
fprintf(vlog_out, "(");
|
||||
count -= 1;
|
||||
|
|
@ -343,16 +445,11 @@ static void emit_expr_func(ivl_scope_t scope, ivl_expr_t expr, const char* name)
|
|||
}
|
||||
}
|
||||
|
||||
static void emit_expr_sfunc(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
emit_expr_func(scope, expr, ivl_expr_name(expr));
|
||||
}
|
||||
|
||||
static void emit_expr_signal(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
emit_scope_module_path(scope, ivl_signal_scope(sig));
|
||||
fprintf(vlog_out, "%s", ivl_signal_basename(sig));
|
||||
emit_scope_call_path(scope, ivl_signal_scope(sig));
|
||||
emit_id(ivl_signal_basename(sig));
|
||||
if (ivl_signal_dimensions(sig)) {
|
||||
int lsb = ivl_signal_array_base(sig);
|
||||
int msb = lsb + ivl_signal_array_count(sig);
|
||||
|
|
@ -373,13 +470,6 @@ static void emit_expr_ternary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
fprintf(vlog_out, ")");
|
||||
}
|
||||
|
||||
static void emit_expr_ufunc(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
ivl_scope_t ufunc_def = ivl_expr_def(expr);
|
||||
emit_scope_module_path(scope, ufunc_def);
|
||||
emit_expr_func(scope, expr, ivl_scope_tname(ufunc_def));
|
||||
}
|
||||
|
||||
static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||
{
|
||||
char *oper = "invalid";
|
||||
|
|
@ -404,13 +494,15 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
case 'N':
|
||||
case 'X':
|
||||
case '!':
|
||||
fprintf(vlog_out, "%s", oper);
|
||||
fprintf(vlog_out, "(%s", oper);
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
fprintf(vlog_out, ")");
|
||||
break;
|
||||
case '2':
|
||||
case 'i':
|
||||
case 'r':
|
||||
/* A cast is a noop. */
|
||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||
break;
|
||||
default:
|
||||
fprintf(vlog_out, "<unknown>");
|
||||
|
|
@ -457,7 +549,8 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
emit_expr_select(scope, expr, wid);
|
||||
break;
|
||||
case IVL_EX_SFUNC:
|
||||
emit_expr_sfunc(scope, expr, wid);
|
||||
fprintf(vlog_out, "%s", ivl_expr_name(expr));
|
||||
emit_expr_func(scope, expr, wid);
|
||||
break;
|
||||
case IVL_EX_SIGNAL:
|
||||
emit_expr_signal(scope, expr, wid);
|
||||
|
|
@ -469,7 +562,8 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
|||
emit_expr_ternary(scope, expr, wid);
|
||||
break;
|
||||
case IVL_EX_UFUNC:
|
||||
emit_expr_ufunc(scope, expr, wid);
|
||||
emit_scope_path(scope, ivl_expr_def(expr));
|
||||
emit_expr_func(scope, expr, wid);
|
||||
break;
|
||||
case IVL_EX_UNARY:
|
||||
emit_expr_unary(scope, expr, wid);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -16,6 +16,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
# include <ctype.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include "config.h"
|
||||
|
|
@ -61,13 +62,109 @@ void emit_scaled_delay(ivl_scope_t scope, uint64_t delay)
|
|||
free(frac);
|
||||
}
|
||||
|
||||
static void emit_delay(ivl_scope_t scope, ivl_expr_t expr, unsigned is_stmt)
|
||||
{
|
||||
/* A delay in a continuous assignment can also be a continuous
|
||||
* assignment expression. */
|
||||
if (ivl_expr_type(expr) == IVL_EX_SIGNAL) {
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
if (ivl_signal_local(sig)) {
|
||||
assert(! is_stmt);
|
||||
emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
emit_expr(scope, expr, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the bit based expression is of the form (expr) * <scale>
|
||||
*/
|
||||
static unsigned check_scaled_expr(ivl_expr_t expr, uint64_t scale,
|
||||
const char *msg, unsigned must_match)
|
||||
{
|
||||
uint64_t scale_val;
|
||||
int rtype;
|
||||
if ((ivl_expr_type(expr) != IVL_EX_BINARY) ||
|
||||
(ivl_expr_opcode(expr) != '*') ||
|
||||
(ivl_expr_type(ivl_expr_oper2(expr)) != IVL_EX_NUMBER)) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: %s expression/value "
|
||||
"cannot be scaled.\n ",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr), msg);
|
||||
vlog_errors += 1;
|
||||
return 0;
|
||||
}
|
||||
scale_val = get_uint64_from_number(ivl_expr_oper2(expr), &rtype);
|
||||
if (rtype > 0) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: %s expression/value "
|
||||
"scale coefficient was greater than 64 bits "
|
||||
"(%d).\n", ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr), msg, rtype);
|
||||
vlog_errors += 1;
|
||||
return 0;
|
||||
}
|
||||
if (rtype < 0) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: %s expression/value "
|
||||
"scale coefficient has an undefined bit.\n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr), msg);
|
||||
vlog_errors += 1;
|
||||
return 0;
|
||||
}
|
||||
if (scale != scale_val) {
|
||||
if (must_match) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: %s expression/value "
|
||||
"scale coefficient did not match expected "
|
||||
"value (%"PRIu64" != %"PRIu64").\n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr),
|
||||
msg, scale, scale_val);
|
||||
vlog_errors += 1;
|
||||
return 0;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
/* Yes, this expression is of the correct form. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the real expression is of the form (expr) * <scale>
|
||||
*/
|
||||
static unsigned check_scaled_real_expr(ivl_expr_t expr, double scale)
|
||||
{
|
||||
double scale_val;
|
||||
if ((ivl_expr_type(expr) != IVL_EX_BINARY) ||
|
||||
(ivl_expr_opcode(expr) != '*') ||
|
||||
(ivl_expr_type(ivl_expr_oper2(expr)) != IVL_EX_REALNUM)) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Variable real time unit "
|
||||
" expression/value cannot be scaled.\n ",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
return 0;
|
||||
}
|
||||
scale_val = ivl_expr_dvalue(ivl_expr_oper2(expr));
|
||||
if (scale != scale_val) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Variable real time unit "
|
||||
"expression/value scale coefficient did not "
|
||||
"match expected value (%g != %g).\n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr),
|
||||
scale, scale_val);
|
||||
vlog_errors += 1;
|
||||
return 0;
|
||||
}
|
||||
/* Yes, this expression is of the correct form. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a constant or variable delay that has been rescaled to the given
|
||||
* scopes timescale.
|
||||
*/
|
||||
void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr)
|
||||
void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr, unsigned is_stmt)
|
||||
{
|
||||
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
|
||||
ivl_expr_type_t type = ivl_expr_type(expr);
|
||||
if (type == IVL_EX_DELAY) {
|
||||
emit_scaled_delay(scope, ivl_expr_delay_val(expr));
|
||||
} else if (type == IVL_EX_NUMBER) {
|
||||
assert(! ivl_expr_signed(expr));
|
||||
int rtype;
|
||||
uint64_t value = get_uint64_from_number(expr, &rtype);
|
||||
|
|
@ -93,80 +190,82 @@ void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr)
|
|||
} else {
|
||||
int exponent = ivl_scope_time_units(scope) - sim_precision;
|
||||
assert(exponent >= 0);
|
||||
if (exponent == 0) emit_expr(scope, expr, 0);
|
||||
/* A real delay variable is not scaled by the compiler. */
|
||||
else if (ivl_expr_type(expr) == IVL_EX_SIGNAL) {
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
if (ivl_signal_data_type(sig) != IVL_VT_REAL) {
|
||||
if ((exponent == 0) && (type == IVL_EX_SIGNAL)) {
|
||||
emit_delay(scope, expr, is_stmt);
|
||||
/* A real delay variable is not scaled by the compiler. */
|
||||
} else if (type == IVL_EX_SIGNAL) {
|
||||
if (is_stmt) {
|
||||
fprintf(vlog_out, "<invalid>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Only real "
|
||||
"delay variables are scaled at run "
|
||||
"time.\n", ivl_expr_file(expr),
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Only continuous "
|
||||
"assignment delay variables are scaled "
|
||||
"at run time.\n", ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
return;
|
||||
}
|
||||
emit_expr(scope, expr, 0);
|
||||
return;
|
||||
emit_delay(scope, expr, is_stmt);
|
||||
} else {
|
||||
uint64_t scale_val, scale = 1;
|
||||
int rtype;
|
||||
uint64_t iscale = 1;
|
||||
unsigned rtn;
|
||||
assert(! ivl_expr_signed(expr));
|
||||
/* This is as easy as removing the multiple that was
|
||||
* added to scale the value to the simulation time,
|
||||
* but we need to verify that the scaling value is
|
||||
* correct first. */
|
||||
if ((ivl_expr_type(expr) != IVL_EX_BINARY) ||
|
||||
(ivl_expr_opcode(expr) != '*') ||
|
||||
(ivl_expr_type(ivl_expr_oper2(expr)) != IVL_EX_NUMBER)) {
|
||||
fprintf(vlog_out, "<invalid>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Variable time "
|
||||
"expression/value cannot be scaled.\n ",
|
||||
ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
return;
|
||||
}
|
||||
scale_val = get_uint64_from_number(ivl_expr_oper2(expr),
|
||||
&rtype);
|
||||
if (rtype > 0) {
|
||||
fprintf(vlog_out, "<invalid>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Variable time "
|
||||
"expression/value scale coefficient "
|
||||
"was greater then 64 bits (%d).\n",
|
||||
ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr),
|
||||
rtype);
|
||||
vlog_errors += 1;
|
||||
return;
|
||||
}
|
||||
if (rtype < 0) {
|
||||
fprintf(vlog_out, "<invalid>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Variable time "
|
||||
"expression/value scale coefficient "
|
||||
"has an undefined bit.\n",
|
||||
ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
return;
|
||||
}
|
||||
/* Calculate the integer time scaling coefficient. */
|
||||
while (exponent > 0) {
|
||||
scale *= 10;
|
||||
iscale *= 10;
|
||||
exponent -= 1;
|
||||
}
|
||||
if (scale != scale_val) {
|
||||
fprintf(vlog_out, "<invalid>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Variable time "
|
||||
"expression/value scale coefficient "
|
||||
"did not match expected value "
|
||||
"(%"PRIu64" != %"PRIu64").\n",
|
||||
ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr),
|
||||
scale, scale_val);
|
||||
vlog_errors += 1;
|
||||
/* Check to see if this is an integer time value. */
|
||||
rtn = check_scaled_expr(expr, iscale, "Variable time", 0);
|
||||
/* This may be a scaled real value. */
|
||||
if (rtn == 2){
|
||||
ivl_expr_t tmp_expr;
|
||||
uint64_t rprec = 1;
|
||||
/* This could be a scaled real time so calculate
|
||||
* the real time scaling coefficients and check
|
||||
* that the expression matches (statements only). */
|
||||
exponent = ivl_scope_time_precision(scope) -
|
||||
sim_precision;
|
||||
assert(exponent >= 0);
|
||||
while (exponent > 0) {
|
||||
rprec *= 10;
|
||||
exponent -= 1;
|
||||
}
|
||||
/* Verify that the precision scaling is correct. */
|
||||
if (! check_scaled_expr(expr, rprec,
|
||||
"Variable real time prec.",
|
||||
1)) {
|
||||
fprintf(vlog_out, "<invalid>");
|
||||
return;
|
||||
}
|
||||
/* Verify that the left operator is a real to
|
||||
* integer cast. */
|
||||
tmp_expr = ivl_expr_oper1(expr);
|
||||
if ((ivl_expr_type(tmp_expr) != IVL_EX_UNARY) ||
|
||||
(ivl_expr_opcode(tmp_expr) != 'i')) {
|
||||
fprintf(vlog_out, "<invalid>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Real time "
|
||||
"value does not have a cast to "
|
||||
"integer.\n",
|
||||
ivl_expr_file(expr),
|
||||
ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
return;
|
||||
}
|
||||
/* Check that the cast value is scaled correctly. */
|
||||
assert(iscale >= rprec);
|
||||
tmp_expr = ivl_expr_oper1(tmp_expr);
|
||||
assert(ivl_expr_value(tmp_expr) == IVL_VT_REAL);
|
||||
if (! check_scaled_real_expr(tmp_expr, iscale/rprec)) {
|
||||
fprintf(vlog_out, "<invalid>");
|
||||
return;
|
||||
}
|
||||
assert(is_stmt);
|
||||
emit_delay(scope, ivl_expr_oper1(tmp_expr), is_stmt);
|
||||
return;
|
||||
} else if (rtn == 1) {
|
||||
emit_delay(scope, ivl_expr_oper1(expr), is_stmt);
|
||||
return;
|
||||
}
|
||||
emit_expr(scope, ivl_expr_oper1(expr), 0);
|
||||
fprintf(vlog_out, "<invalid>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -255,42 +354,21 @@ void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr, unsigned width,
|
|||
int msb, int lsb)
|
||||
{
|
||||
if (msb >= lsb) {
|
||||
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
|
||||
int rtype;
|
||||
int64_t value = get_valid_int64_from_number(expr, &rtype,
|
||||
"range value");
|
||||
if (rtype) return;
|
||||
value += lsb;
|
||||
fprintf(vlog_out, "[%"PRId64":%"PRId64"]",
|
||||
value + (int64_t)(width - 1), value);
|
||||
} else {
|
||||
// HERE: Need to scale the select expression and create a concatenation of
|
||||
// variable bit selects for that. We need the signal name as well.
|
||||
// As an optimization determine if this is an up or down to simplify
|
||||
// the generated expression.
|
||||
fprintf(vlog_out, "[<invalid>:<invalid>]");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Indexed part-selects "
|
||||
"are not currently supported.\n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
int rtype;
|
||||
int64_t value = get_valid_int64_from_number(expr, &rtype,
|
||||
"range value");
|
||||
if (rtype) return;
|
||||
value += lsb;
|
||||
fprintf(vlog_out, "[%"PRId64":%"PRId64"]",
|
||||
value + (int64_t)(width - 1), value);
|
||||
} else {
|
||||
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
|
||||
int rtype;
|
||||
int64_t value = get_valid_int64_from_number(expr, &rtype,
|
||||
"range value");
|
||||
if (rtype) return;
|
||||
value = (int64_t)lsb - value;
|
||||
fprintf(vlog_out, "[%"PRId64":%"PRId64"]",
|
||||
value - (int64_t)(width - 1), value);
|
||||
} else {
|
||||
// HERE: Do basically the same as above.
|
||||
fprintf(vlog_out, "[<invalid>:<invalid>]");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Indexed part-selects "
|
||||
"are not currently supported.\n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
int rtype;
|
||||
int64_t value = get_valid_int64_from_number(expr, &rtype,
|
||||
"range value");
|
||||
if (rtype) return;
|
||||
value = (int64_t)lsb - value;
|
||||
fprintf(vlog_out, "[%"PRId64":%"PRId64"]",
|
||||
value - (int64_t)(width - 1), value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -377,8 +455,8 @@ static unsigned find_signal_in_nexus(ivl_scope_t scope, ivl_nexus_t nex)
|
|||
tmp_idx += ivl_signal_array_base(sig);
|
||||
fprintf(stderr, "[%"PRId64"]", tmp_idx);
|
||||
}
|
||||
fprintf(stderr, ") found for nexus ");
|
||||
fprintf(stderr, "(%s", ivl_signal_basename(use_sig));
|
||||
fprintf(stderr, ") found for nexus (%s",
|
||||
ivl_signal_basename(use_sig));
|
||||
if (is_array) fprintf(stderr, "[%"PRId64"]", array_idx);
|
||||
fprintf(stderr, ")\n");
|
||||
} else {
|
||||
|
|
@ -397,9 +475,8 @@ static unsigned find_signal_in_nexus(ivl_scope_t scope, ivl_nexus_t nex)
|
|||
}
|
||||
}
|
||||
|
||||
// HERE: Check bit, part, etc. selects to make sure they work as well.
|
||||
if (use_sig) {
|
||||
fprintf(vlog_out, "%s", ivl_signal_basename(use_sig));
|
||||
emit_id(ivl_signal_basename(use_sig));
|
||||
if (is_array) fprintf(vlog_out, "[%"PRId64"]", array_idx);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -454,12 +531,16 @@ static unsigned find_const_nexus(ivl_scope_t scope, ivl_nexus_t nex)
|
|||
// HERE: Does this work correctly with an array reference created from @*?
|
||||
void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex)
|
||||
{
|
||||
ivl_scope_t mod_scope;
|
||||
/* First look in the local scope for the nexus name. */
|
||||
if (find_signal_in_nexus(scope, nex)) return;
|
||||
|
||||
/* If the signal was not found in the passed scope then look in
|
||||
* the module scope if the passed scope was not the module scope. */
|
||||
if (find_signal_in_nexus(get_module_scope(scope), nex)) return;
|
||||
mod_scope = get_module_scope(scope);
|
||||
if (mod_scope != scope) {
|
||||
if (find_signal_in_nexus(mod_scope, nex)) return;
|
||||
}
|
||||
|
||||
/* If there is no signals driving this then look for a constant. */
|
||||
if (find_const_nexus(scope, nex)) return;
|
||||
|
|
@ -468,6 +549,8 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex)
|
|||
// Then look for down scopes and then any scope. For all this warn if
|
||||
// multiples are found in a given scope. This all needs to be before
|
||||
// the constant code.
|
||||
fprintf(stderr, "?:?: vlog95 sorry: Unable to find nexus name.\n");
|
||||
vlog_errors += 1;
|
||||
fprintf(vlog_out, "<missing>");
|
||||
}
|
||||
|
||||
|
|
@ -486,6 +569,19 @@ ivl_scope_t get_module_scope(ivl_scope_t scope)
|
|||
return scope;
|
||||
}
|
||||
|
||||
static void emit_scope_piece(ivl_scope_t scope, ivl_scope_t call_scope)
|
||||
{
|
||||
ivl_scope_t parent = ivl_scope_parent(call_scope);
|
||||
/* If we are not at the top of the scope (parent != 0) and the two
|
||||
* scopes do not match then print the parent scope. */
|
||||
if ((parent != 0) && (scope != parent)) {
|
||||
emit_scope_piece(scope, parent);
|
||||
}
|
||||
/* Print the base scope. */
|
||||
emit_id(ivl_scope_basename(call_scope));
|
||||
fprintf(vlog_out, ".");
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine emits the appropriate string to call the call_scope from the
|
||||
* given scope. If the module scopes for the two match then do nothing. If
|
||||
|
|
@ -498,30 +594,48 @@ void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope)
|
|||
{
|
||||
ivl_scope_t mod_scope = get_module_scope(scope);
|
||||
ivl_scope_t call_mod_scope = get_module_scope(call_scope);
|
||||
|
||||
if (mod_scope == call_mod_scope) return;
|
||||
emit_scope_piece(mod_scope, call_mod_scope);
|
||||
}
|
||||
|
||||
/* This is the same as emit_scope_module_path() except we need to add down
|
||||
* references for variables, etc. */
|
||||
void emit_scope_call_path(ivl_scope_t scope, ivl_scope_t call_scope)
|
||||
{
|
||||
ivl_scope_t mod_scope = get_module_scope(scope);
|
||||
ivl_scope_t call_mod_scope = get_module_scope(call_scope);
|
||||
|
||||
if (mod_scope != call_mod_scope) {
|
||||
/* Trim off the top of the call name if it exactly matches
|
||||
* the module scope of the caller. */
|
||||
char *sc_name = strdup(ivl_scope_name(mod_scope));
|
||||
const char *sc_ptr = sc_name;
|
||||
char *call_name = strdup(ivl_scope_name(call_mod_scope));
|
||||
const char *call_ptr = call_name;
|
||||
while ((*sc_ptr == *call_ptr) &&
|
||||
(*sc_ptr != 0) && (*call_ptr != 0)) {
|
||||
sc_ptr += 1;
|
||||
call_ptr += 1;
|
||||
emit_scope_piece(mod_scope, call_mod_scope);
|
||||
} else if (scope != call_scope) {
|
||||
ivl_scope_t parent;
|
||||
/* We only emit a scope path if the scope is a parent of the
|
||||
* call scope. */
|
||||
for (parent = ivl_scope_parent(call_scope);
|
||||
parent != 0;
|
||||
parent = ivl_scope_parent(parent)) {
|
||||
if (parent == scope) {
|
||||
emit_scope_piece(scope, call_scope);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (*sc_ptr == 0) {
|
||||
assert(*call_ptr == '.');
|
||||
call_ptr += 1;
|
||||
} else {
|
||||
call_ptr = call_name;
|
||||
}
|
||||
fprintf(vlog_out, "%s.", call_ptr);
|
||||
free(sc_name);
|
||||
free(call_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_scope_path_piece(ivl_scope_t scope, ivl_scope_t call_scope)
|
||||
{
|
||||
ivl_scope_t parent = ivl_scope_parent(call_scope);
|
||||
/* If we are not at the top of the scope (parent != 0) and the two
|
||||
* scopes do not match then print the parent scope. */
|
||||
if ((parent != 0) && (scope != parent)) {
|
||||
emit_scope_path_piece(scope, parent);
|
||||
fprintf(vlog_out, ".");
|
||||
}
|
||||
/* Print the base scope. */
|
||||
emit_id(ivl_scope_basename(call_scope));
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine emits the appropriate string to call the call_scope from the
|
||||
* given scope. If the module scopes for the two match then just return the
|
||||
|
|
@ -534,28 +648,34 @@ void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope)
|
|||
{
|
||||
ivl_scope_t mod_scope = get_module_scope(scope);
|
||||
ivl_scope_t call_mod_scope = get_module_scope(call_scope);
|
||||
|
||||
if (mod_scope == call_mod_scope) {
|
||||
fprintf(vlog_out, "%s", ivl_scope_basename(call_scope));
|
||||
emit_id(ivl_scope_basename(call_scope));
|
||||
} else {
|
||||
/* Trim off the top of the call name if it exactly matches
|
||||
* the module scope of the caller. */
|
||||
char *sc_name = strdup(ivl_scope_name(mod_scope));
|
||||
const char *sc_ptr = sc_name;
|
||||
char *call_name = strdup(ivl_scope_name(call_scope));
|
||||
const char *call_ptr = call_name;
|
||||
while ((*sc_ptr == *call_ptr) &&
|
||||
(*sc_ptr != 0) && (*call_ptr != 0)) {
|
||||
sc_ptr += 1;
|
||||
call_ptr += 1;
|
||||
}
|
||||
if (*sc_ptr == 0) {
|
||||
assert(*call_ptr == '.');
|
||||
call_ptr += 1;
|
||||
} else {
|
||||
call_ptr = call_name;
|
||||
}
|
||||
fprintf(vlog_out, "%s", call_ptr);
|
||||
free(sc_name);
|
||||
free(call_name);
|
||||
emit_scope_path_piece(mod_scope, call_scope);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned is_escaped(const char *id)
|
||||
{
|
||||
assert(id);
|
||||
/* The first digit must be alpha or '_' to be a normal id. */
|
||||
if (isalpha((int)id[0]) || id[0] == '_') {
|
||||
unsigned idx;
|
||||
for (idx = 1; id[idx] != '\0'; idx += 1) {
|
||||
if (! (isalnum((int)id[idx]) ||
|
||||
id[idx] == '_' || id[idx] == '$')) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* We looked at all the digits, so this is a normal id. */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void emit_id(const char *id)
|
||||
{
|
||||
if (is_escaped(id)) fprintf(vlog_out, "\\%s ", id);
|
||||
else fprintf(vlog_out, "%s", id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ static int32_t get_int32_from_bits(const char *bits, unsigned nbits,
|
|||
else if (bits[idx] != '0') {
|
||||
*result_type = -1;
|
||||
/* If the value is entirely x/z then return -2 or -3. */
|
||||
if ((idx == 0) && (trim_wid == 1)) {
|
||||
if (trim_wid == 1) {
|
||||
if (bits[idx] == 'x') *result_type -= 1;
|
||||
*result_type -= 1;
|
||||
}
|
||||
|
|
@ -190,7 +190,7 @@ uint64_t get_uint64_from_number(ivl_expr_t expr, int *result_type)
|
|||
else if (bits[idx] != '0') {
|
||||
*result_type = -1;
|
||||
/* If the value is entirely x/z then return -2 or -3. */
|
||||
if ((idx == 0) && (trim_wid == 1)) {
|
||||
if (trim_wid == 1) {
|
||||
if (bits[idx] == 'x') *result_type -= 1;
|
||||
*result_type -= 1;
|
||||
}
|
||||
|
|
@ -236,7 +236,7 @@ int64_t get_int64_from_number(ivl_expr_t expr, int *result_type)
|
|||
else if (bits[idx] != '0') {
|
||||
*result_type = -1;
|
||||
/* If the value is entirely x/z then return -2 or -3. */
|
||||
if ((idx == 0) && (trim_wid == 1)) {
|
||||
if (trim_wid == 1) {
|
||||
if (bits[idx] == 'x') *result_type -= 1;
|
||||
*result_type -= 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,14 +76,21 @@ void emit_sig_file_line(ivl_signal_t sig)
|
|||
}
|
||||
}
|
||||
|
||||
static void emit_sig_id(ivl_signal_t sig)
|
||||
{
|
||||
emit_id(ivl_signal_basename(sig));
|
||||
fprintf(vlog_out, ";");
|
||||
emit_sig_file_line(sig);
|
||||
fprintf(vlog_out, "\n");
|
||||
}
|
||||
|
||||
void emit_var_def(ivl_signal_t sig)
|
||||
{
|
||||
if (ivl_signal_local(sig)) return;
|
||||
fprintf(vlog_out, "%*c", indent, ' ');
|
||||
if (ivl_signal_integer(sig)) {
|
||||
fprintf(vlog_out, "integer %s;", ivl_signal_basename(sig));
|
||||
emit_sig_file_line(sig);
|
||||
fprintf(vlog_out, "\n");
|
||||
fprintf(vlog_out, "integer ");
|
||||
emit_sig_id(sig);
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Integer arrays (%s) "
|
||||
"are not supported.\n", ivl_signal_file(sig),
|
||||
|
|
@ -92,9 +99,8 @@ void emit_var_def(ivl_signal_t sig)
|
|||
vlog_errors += 1;
|
||||
}
|
||||
} else if (ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
fprintf(vlog_out, "real %s;", ivl_signal_basename(sig));
|
||||
emit_sig_file_line(sig);
|
||||
fprintf(vlog_out, "\n");
|
||||
fprintf(vlog_out, "real ");
|
||||
emit_sig_id(sig);
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Real arrays (%s) "
|
||||
"are not supported.\n", ivl_signal_file(sig),
|
||||
|
|
@ -105,9 +111,9 @@ void emit_var_def(ivl_signal_t sig)
|
|||
} else {
|
||||
int msb = ivl_signal_msb(sig);
|
||||
int lsb = ivl_signal_lsb(sig);
|
||||
fprintf(vlog_out, "reg");
|
||||
if (msb != 0 || lsb != 0) fprintf(vlog_out, " [%d:%d]", msb, lsb);
|
||||
fprintf(vlog_out, " %s", ivl_signal_basename(sig));
|
||||
fprintf(vlog_out, "reg ");
|
||||
if (msb != 0 || lsb != 0) fprintf(vlog_out, "[%d:%d] ", msb, lsb);
|
||||
emit_id(ivl_signal_basename(sig));
|
||||
if (ivl_signal_dimensions(sig) > 0) {
|
||||
unsigned wd_count = ivl_signal_array_count(sig);
|
||||
int first = ivl_signal_array_base(sig);
|
||||
|
|
@ -178,23 +184,24 @@ void emit_net_def(ivl_scope_t scope, ivl_signal_t sig)
|
|||
if (ivl_signal_local(sig)) return;
|
||||
fprintf(vlog_out, "%*c", indent, ' ');
|
||||
if (ivl_signal_data_type(sig) == IVL_VT_REAL){
|
||||
fprintf(vlog_out, "wire %s;\n", ivl_signal_basename(sig));
|
||||
fprintf(vlog_out, "wire ");
|
||||
emit_sig_id(sig);
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Real nets (%s) are "
|
||||
"not supported.\n", ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig), ivl_signal_basename(sig));
|
||||
vlog_errors += 1;
|
||||
} else if (ivl_signal_signed(sig)) {
|
||||
fprintf(vlog_out, "wire");
|
||||
if (msb != 0 || lsb != 0) fprintf(vlog_out, " [%d:%d]", msb, lsb);
|
||||
fprintf(vlog_out, " %s;\n", ivl_signal_basename(sig));
|
||||
fprintf(vlog_out, "wire ");
|
||||
if (msb != 0 || lsb != 0) fprintf(vlog_out, "[%d:%d] ", msb, lsb);
|
||||
emit_sig_id(sig);
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Signed nets (%s) are "
|
||||
"not supported.\n", ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig), ivl_signal_basename(sig));
|
||||
vlog_errors += 1;
|
||||
} else if (ivl_signal_dimensions(sig) > 0) {
|
||||
fprintf(vlog_out, "wire");
|
||||
if (msb != 0 || lsb != 0) fprintf(vlog_out, " [%d:%d]", msb, lsb);
|
||||
fprintf(vlog_out, " %s;\n", ivl_signal_basename(sig));
|
||||
fprintf(vlog_out, "wire ");
|
||||
if (msb != 0 || lsb != 0) fprintf(vlog_out, "[%d:%d] ", msb, lsb);
|
||||
emit_sig_id(sig);
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Array nets (%s) are "
|
||||
"not supported.\n", ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig), ivl_signal_basename(sig));
|
||||
|
|
@ -205,59 +212,58 @@ void emit_net_def(ivl_scope_t scope, ivl_signal_t sig)
|
|||
case IVL_SIT_UWIRE:
|
||||
// HERE: Need to add support for supply nets. Probably supply strength
|
||||
// with a constant 0/1 driver for all the bits.
|
||||
fprintf(vlog_out, "wire");
|
||||
fprintf(vlog_out, "wire ");
|
||||
break;
|
||||
case IVL_SIT_TRI0:
|
||||
fprintf(vlog_out, "tri0");
|
||||
fprintf(vlog_out, "tri0 ");
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
fprintf(vlog_out, "tri1");
|
||||
fprintf(vlog_out, "tri1 ");
|
||||
break;
|
||||
case IVL_SIT_TRIAND:
|
||||
fprintf(vlog_out, "wand");
|
||||
fprintf(vlog_out, "wand ");
|
||||
break;
|
||||
case IVL_SIT_TRIOR:
|
||||
fprintf(vlog_out, "wor");
|
||||
fprintf(vlog_out, "wor ");
|
||||
break;
|
||||
default:
|
||||
fprintf(vlog_out, "<unknown>");
|
||||
fprintf(vlog_out, "<unknown> ");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Unknown net type "
|
||||
"(%d).\n", ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig), (int)ivl_signal_type(sig));
|
||||
vlog_errors += 1;
|
||||
break;
|
||||
}
|
||||
if (msb != 0 || lsb != 0) fprintf(vlog_out, " [%d:%d]", msb, lsb);
|
||||
fprintf(vlog_out, " %s;", ivl_signal_basename(sig));
|
||||
emit_sig_file_line(sig);
|
||||
fprintf(vlog_out, "\n");
|
||||
if (msb != 0 || lsb != 0) fprintf(vlog_out, "[%d:%d] ", msb, lsb);
|
||||
emit_sig_id(sig);
|
||||
/* A constant driving a net does not create an lpm or logic
|
||||
* element in the design so save them from the definition. */
|
||||
save_net_constants(scope, sig);
|
||||
}
|
||||
}
|
||||
|
||||
static char *get_mangled_name(ivl_scope_t scope, unsigned root)
|
||||
static void emit_mangled_name(ivl_scope_t scope, unsigned root)
|
||||
{
|
||||
char *name;
|
||||
/* If the module has parameters and it's not a root module than it
|
||||
* may not be unique so we create a mangled name version instead. */
|
||||
/* If the module has parameters and it's not a root module then it
|
||||
* may not be unique so we create a mangled name version instead.
|
||||
* The mangled name is of the form:
|
||||
* <module_name>[<full_instance_scope>]. */
|
||||
if (ivl_scope_params(scope) && ! root) {
|
||||
unsigned idx;
|
||||
char *name;
|
||||
size_t len = strlen(ivl_scope_name(scope)) +
|
||||
strlen(ivl_scope_tname(scope)) + 2;
|
||||
strlen(ivl_scope_tname(scope)) + 3;
|
||||
name = (char *)malloc(len);
|
||||
(void) strcpy(name, ivl_scope_tname(scope));
|
||||
(void) strcat(name, "_");
|
||||
(void) strcat(name, "[");
|
||||
(void) strcat(name, ivl_scope_name(scope));
|
||||
(void) strcat(name, "]");
|
||||
assert(name[len-1] == 0);
|
||||
for (idx = 0; idx < len; idx += 1) {
|
||||
if (name[idx] == '.') name[idx] = '_';
|
||||
}
|
||||
/* Emit the mangled name as an escaped identifier. */
|
||||
fprintf(vlog_out, "\\%s ", name);
|
||||
free(name);
|
||||
} else {
|
||||
name = strdup(ivl_scope_tname(scope));
|
||||
emit_id(ivl_scope_tname(scope));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -279,8 +285,9 @@ void emit_scope_variables(ivl_scope_t scope)
|
|||
for (idx = 0; idx < count; idx += 1) {
|
||||
ivl_parameter_t par = ivl_scope_param(scope, idx);
|
||||
ivl_expr_t pex = ivl_parameter_expr(par);
|
||||
fprintf(vlog_out, "%*cparameter %s = ", indent, ' ',
|
||||
ivl_parameter_basename(par));
|
||||
fprintf(vlog_out, "%*cparameter ", indent, ' ');
|
||||
emit_id(ivl_parameter_basename(par));
|
||||
fprintf(vlog_out, " = ");
|
||||
emit_expr(scope, pex, 0);
|
||||
fprintf(vlog_out, ";");
|
||||
if (emit_file_line) {
|
||||
|
|
@ -317,8 +324,9 @@ void emit_scope_variables(ivl_scope_t scope)
|
|||
if (ivl_event_nany(event)) continue;
|
||||
if (ivl_event_npos(event)) continue;
|
||||
if (ivl_event_nneg(event)) continue;
|
||||
fprintf(vlog_out, "%*cevent %s;", indent, ' ',
|
||||
ivl_event_basename(event));
|
||||
fprintf(vlog_out, "%*cevent ", indent, ' ');
|
||||
emit_id(ivl_event_basename(event));
|
||||
fprintf(vlog_out, ";");
|
||||
if (emit_file_line) {
|
||||
fprintf(vlog_out, " /* %s:%u */",
|
||||
ivl_event_file(event),
|
||||
|
|
@ -339,6 +347,176 @@ static void emit_scope_file_line(ivl_scope_t scope)
|
|||
}
|
||||
}
|
||||
|
||||
static void emit_module_ports(ivl_scope_t scope)
|
||||
{
|
||||
unsigned idx, count = ivl_scope_ports(scope);
|
||||
|
||||
if (count == 0) return;
|
||||
|
||||
fprintf(vlog_out, "(");
|
||||
emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, 0));
|
||||
for (idx = 1; idx < count; idx += 1) {
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, idx));
|
||||
}
|
||||
fprintf(vlog_out, ")");
|
||||
}
|
||||
|
||||
static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex)
|
||||
{
|
||||
assert(nex);
|
||||
unsigned idx, count = ivl_nexus_ptrs(nex);
|
||||
ivl_signal_t sig = 0;
|
||||
for (idx = 0; idx < count; idx += 1) {
|
||||
ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx);
|
||||
ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr);
|
||||
if (t_sig) {
|
||||
if (ivl_signal_scope(t_sig) != scope) continue;
|
||||
assert(! sig);
|
||||
sig = t_sig;
|
||||
}
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
|
||||
static void emit_sig_type(ivl_signal_t sig)
|
||||
{
|
||||
ivl_signal_type_t type = ivl_signal_type(sig);
|
||||
assert(ivl_signal_dimensions(sig) == 0);
|
||||
/* Check to see if we have a variable (reg) or a net. */
|
||||
if (type == IVL_SIT_REG) {
|
||||
if (ivl_signal_integer(sig)) {
|
||||
fprintf(vlog_out, " integer");
|
||||
} else if (ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
fprintf(vlog_out, " real");
|
||||
} else {
|
||||
int msb = ivl_signal_msb(sig);
|
||||
int lsb = ivl_signal_lsb(sig);
|
||||
if (msb != 0 || lsb != 0) {
|
||||
fprintf(vlog_out, " [%d:%d]", msb, lsb);
|
||||
}
|
||||
if (ivl_signal_signed(sig)) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Signed ports "
|
||||
"(%s) are not supported.\n",
|
||||
ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig),
|
||||
ivl_signal_basename(sig));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(type == IVL_SIT_TRI);
|
||||
if (ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Real net ports (%s) "
|
||||
"are not supported.\n",
|
||||
ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig),
|
||||
ivl_signal_basename(sig));
|
||||
vlog_errors += 1;
|
||||
} else {
|
||||
int msb = ivl_signal_msb(sig);
|
||||
int lsb = ivl_signal_lsb(sig);
|
||||
if (ivl_signal_signed(sig)) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Signed net ports "
|
||||
"(%s) are not supported.\n",
|
||||
ivl_signal_file(sig),
|
||||
ivl_signal_lineno(sig),
|
||||
ivl_signal_basename(sig));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
if (msb != 0 || lsb != 0) {
|
||||
fprintf(vlog_out, " [%d:%d]", msb, lsb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_port(ivl_signal_t port)
|
||||
{
|
||||
assert(port);
|
||||
fprintf(vlog_out, "%*c", indent, ' ');
|
||||
switch (ivl_signal_port(port)) {
|
||||
case IVL_SIP_INPUT:
|
||||
fprintf(vlog_out, "input");
|
||||
break;
|
||||
case IVL_SIP_OUTPUT:
|
||||
fprintf(vlog_out, "output");
|
||||
break;
|
||||
case IVL_SIP_INOUT:
|
||||
fprintf(vlog_out, "inout");
|
||||
break;
|
||||
default:
|
||||
fprintf(vlog_out, "<unknown>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Unknown port direction (%d) "
|
||||
"for signal %s.\n", ivl_signal_file(port),
|
||||
ivl_signal_lineno(port), (int)ivl_signal_port(port),
|
||||
ivl_signal_basename(port));
|
||||
vlog_errors += 1;
|
||||
break;
|
||||
}
|
||||
emit_sig_type(port);
|
||||
fprintf(vlog_out, " ");
|
||||
emit_id(ivl_signal_basename(port));
|
||||
fprintf(vlog_out, ";");
|
||||
emit_sig_file_line(port);
|
||||
fprintf(vlog_out, "\n");
|
||||
}
|
||||
|
||||
static void emit_module_port_defs(ivl_scope_t scope)
|
||||
{
|
||||
unsigned idx, count = ivl_scope_ports(scope);
|
||||
for (idx = 0; idx < count; idx += 1) {
|
||||
ivl_nexus_t nex = ivl_scope_mod_port(scope, idx);
|
||||
ivl_signal_t port = get_port_from_nexus(scope, nex);
|
||||
if (port) emit_port(port);
|
||||
else {
|
||||
fprintf(vlog_out, "<missing>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Could not find signal "
|
||||
"definition for port (%u) of module %s.\n",
|
||||
ivl_scope_file(scope), ivl_scope_lineno(scope),
|
||||
idx + 1, ivl_scope_basename(scope));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
}
|
||||
if (count) fprintf(vlog_out, "\n");
|
||||
}
|
||||
|
||||
static void emit_module_call_expr(ivl_scope_t scope, unsigned idx)
|
||||
{
|
||||
ivl_nexus_t nex = ivl_scope_mod_port(scope, idx);
|
||||
ivl_signal_t port = get_port_from_nexus(scope, nex);
|
||||
/* For an input port we need to emit the driving expression. */
|
||||
if (ivl_signal_port(port) == IVL_SIP_INPUT) {
|
||||
emit_nexus_port_driver_as_ca(ivl_scope_parent(scope),
|
||||
ivl_signal_nex(port, 0));
|
||||
/* For an output we need to emit the signal the output is driving. */
|
||||
} else {
|
||||
emit_nexus_as_ca(ivl_scope_parent(scope), ivl_signal_nex(port, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_module_call_expressions(ivl_scope_t scope)
|
||||
{
|
||||
unsigned idx, count = ivl_scope_ports(scope);
|
||||
if (count == 0) return;
|
||||
emit_module_call_expr(scope, 0);
|
||||
for (idx = 1; idx < count; idx += 1) {
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_module_call_expr(scope, idx);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_task_func_port_defs(ivl_scope_t scope)
|
||||
{
|
||||
unsigned idx, count = ivl_scope_ports(scope);
|
||||
unsigned start = ivl_scope_type(scope) == IVL_SCT_FUNCTION;
|
||||
for (idx = start; idx < count; idx += 1) {
|
||||
ivl_signal_t port = ivl_scope_port(scope, idx);
|
||||
emit_port(port);
|
||||
}
|
||||
if (count) fprintf(vlog_out, "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* This search method may be slow for a large structural design with a
|
||||
* large number of gate types. That's not what this converter was built
|
||||
|
|
@ -384,26 +562,26 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
{
|
||||
ivl_scope_type_t sc_type = ivl_scope_type(scope);
|
||||
unsigned is_auto = ivl_scope_is_auto(scope);
|
||||
unsigned idx, count, start = 0;
|
||||
char *name;
|
||||
unsigned idx, count;
|
||||
|
||||
/* Output the scope definition. */
|
||||
switch (sc_type) {
|
||||
case IVL_SCT_MODULE:
|
||||
assert(!is_auto);
|
||||
name = get_mangled_name(scope, !parent && !emitting_scopes);
|
||||
/* This is an instantiation. */
|
||||
if (parent) {
|
||||
assert(indent != 0);
|
||||
/* If the module has parameters than it may not be unique
|
||||
/* If the module has parameters then it may not be unique
|
||||
* so we create a mangled name version instead. */
|
||||
fprintf(vlog_out, "\n%*c%s %s(", indent, ' ', name,
|
||||
ivl_scope_basename(scope));
|
||||
// HERE: Still need to add port information.
|
||||
fprintf(vlog_out, "\n%*c", indent, ' ');
|
||||
emit_mangled_name(scope, !parent && !emitting_scopes);
|
||||
fprintf(vlog_out, " ");
|
||||
emit_id(ivl_scope_basename(scope));
|
||||
fprintf(vlog_out, "(");
|
||||
emit_module_call_expressions(scope);
|
||||
fprintf(vlog_out, ");");
|
||||
emit_scope_file_line(scope);
|
||||
fprintf(vlog_out, "\n");
|
||||
free(name);
|
||||
num_scopes_to_emit += 1;
|
||||
scopes_to_emit = realloc(scopes_to_emit, num_scopes_to_emit *
|
||||
sizeof(ivl_scope_t));
|
||||
|
|
@ -422,9 +600,9 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
"file %s at line %u. */\n",
|
||||
ivl_scope_def_file(scope),
|
||||
ivl_scope_def_lineno(scope));
|
||||
fprintf(vlog_out, "module %s", name);
|
||||
free(name);
|
||||
// HERE: Still need to add port information.
|
||||
fprintf(vlog_out, "module ");
|
||||
emit_mangled_name(scope, !parent && !emitting_scopes);
|
||||
emit_module_ports(scope);
|
||||
break;
|
||||
case IVL_SCT_FUNCTION:
|
||||
assert(indent != 0);
|
||||
|
|
@ -432,8 +610,8 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
assert(ivl_scope_ports(scope) >= 2);
|
||||
/* The function return information is the zero port. */
|
||||
emit_func_return(ivl_scope_port(scope, 0));
|
||||
start = 1;
|
||||
fprintf(vlog_out, " %s", ivl_scope_tname(scope));
|
||||
fprintf(vlog_out, " ");
|
||||
emit_id(ivl_scope_tname(scope));
|
||||
if (is_auto) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Automatic functions "
|
||||
"(%s) are not supported.\n", ivl_scope_file(scope),
|
||||
|
|
@ -443,8 +621,8 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
break;
|
||||
case IVL_SCT_TASK:
|
||||
assert(indent != 0);
|
||||
fprintf(vlog_out, "\n%*ctask %s", indent, ' ',
|
||||
ivl_scope_tname(scope));
|
||||
fprintf(vlog_out, "\n%*ctask ", indent, ' ');
|
||||
emit_id(ivl_scope_tname(scope));
|
||||
if (is_auto) {
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Automatic tasks "
|
||||
"(%s) are not supported.\n", ivl_scope_file(scope),
|
||||
|
|
@ -470,35 +648,11 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
indent += indent_incr;
|
||||
|
||||
/* Output the scope ports for this scope. */
|
||||
count = ivl_scope_ports(scope);
|
||||
for (idx = start; idx < count; idx += 1) {
|
||||
fprintf(vlog_out, "%*c", indent, ' ');
|
||||
ivl_signal_t port = ivl_scope_port(scope, idx);
|
||||
switch (ivl_signal_port(port)) {
|
||||
case IVL_SIP_INPUT:
|
||||
fprintf(vlog_out, "input");
|
||||
break;
|
||||
case IVL_SIP_OUTPUT:
|
||||
fprintf(vlog_out, "output");
|
||||
break;
|
||||
case IVL_SIP_INOUT:
|
||||
fprintf(vlog_out, "inout");
|
||||
break;
|
||||
default:
|
||||
fprintf(vlog_out, "<unknown>");
|
||||
fprintf(stderr, "%s:%u: vlog95 error: Unknown port "
|
||||
"direction (%d) for signal %s.\n",
|
||||
ivl_signal_file(port), ivl_signal_lineno(port),
|
||||
(int)ivl_signal_port(port),
|
||||
ivl_signal_basename(port));
|
||||
vlog_errors += 1;
|
||||
break;
|
||||
}
|
||||
fprintf(vlog_out, " %s;", ivl_signal_basename(port));
|
||||
emit_sig_file_line(port);
|
||||
fprintf(vlog_out, " \n");
|
||||
if (sc_type == IVL_SCT_MODULE) {
|
||||
emit_module_port_defs(scope);
|
||||
} else {
|
||||
emit_task_func_port_defs(scope);
|
||||
}
|
||||
if (count) fprintf(vlog_out, "\n");
|
||||
|
||||
emit_scope_variables(scope);
|
||||
|
||||
|
|
@ -539,7 +693,9 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
|
|||
switch (sc_type) {
|
||||
case IVL_SCT_MODULE:
|
||||
assert(indent == 0);
|
||||
fprintf(vlog_out, "endmodule /* %s */\n", ivl_scope_tname(scope));
|
||||
fprintf(vlog_out, "endmodule /* ");
|
||||
emit_mangled_name(scope, !parent && !emitting_scopes);
|
||||
fprintf(vlog_out, " */\n");
|
||||
if (ivl_scope_is_cell(scope)) {
|
||||
fprintf(vlog_out, "`endcelldefine\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,46 +80,138 @@ static void emit_stmt_inter_delay(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
}
|
||||
if (delay) {
|
||||
assert(nevents == 0);
|
||||
fprintf(vlog_out, "#");
|
||||
emit_expr(scope, delay, 0);
|
||||
fprintf(vlog_out, " ");
|
||||
fprintf(vlog_out, "#(");
|
||||
emit_scaled_delayx(scope, delay, 1);
|
||||
fprintf(vlog_out, ") ");
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval)
|
||||
static void emit_stmt_lval_name(ivl_scope_t scope, ivl_lval_t lval,
|
||||
ivl_signal_t sig)
|
||||
{
|
||||
ivl_expr_t expr;
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
unsigned width = ivl_lval_width(lval);
|
||||
int msb, lsb;
|
||||
assert(width > 0);
|
||||
emit_scope_module_path(scope, ivl_signal_scope(sig));
|
||||
fprintf(vlog_out, "%s", ivl_signal_basename(sig));
|
||||
/* Check to see if we have an array word access. */
|
||||
expr = ivl_lval_idx(lval);
|
||||
if (expr) {
|
||||
ivl_expr_t array_idx = ivl_lval_idx(lval);
|
||||
emit_scope_call_path(scope, ivl_signal_scope(sig));
|
||||
emit_id(ivl_signal_basename(sig));
|
||||
if (array_idx) {
|
||||
int msb, lsb;
|
||||
assert(ivl_signal_dimensions(sig));
|
||||
fprintf(vlog_out, "[");
|
||||
/* For an array the LSB/MSB order is not important. They are
|
||||
* always accessed from base counting up. */
|
||||
lsb = ivl_signal_array_base(sig);
|
||||
msb = lsb + ivl_signal_array_count(sig) - 1;
|
||||
emit_scaled_expr(scope, expr, msb, lsb);
|
||||
emit_scaled_expr(scope, array_idx, msb, lsb);
|
||||
fprintf(vlog_out, "]");
|
||||
}
|
||||
}
|
||||
|
||||
/* If there are no selects then just return. */
|
||||
if (width == ivl_signal_width(sig)) return;
|
||||
static void emit_stmt_lval_ips(ivl_scope_t scope, ivl_lval_t lval,
|
||||
ivl_signal_t sig, ivl_expr_t sel_expr,
|
||||
ivl_select_type_t sel_type,
|
||||
unsigned wid, int msb, int lsb)
|
||||
{
|
||||
unsigned idx;
|
||||
assert(wid > 0);
|
||||
fprintf(vlog_out, "{");
|
||||
if (msb >= lsb) {
|
||||
if (sel_type == IVL_SEL_IDX_DOWN) {
|
||||
lsb += wid - 1;
|
||||
msb += wid - 1;
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]");
|
||||
for (idx = 1; idx < wid; idx += 1) {
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, " - %u]", idx);
|
||||
}
|
||||
fprintf(vlog_out, "}");
|
||||
} else {
|
||||
assert(sel_type == IVL_SEL_IDX_UP);
|
||||
for (idx = wid - 1; idx > 0; idx -= 1) {
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, " + %u], ", idx);
|
||||
}
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]}");
|
||||
}
|
||||
} else {
|
||||
if (sel_type == IVL_SEL_IDX_UP) {
|
||||
lsb -= wid - 1;
|
||||
msb -= wid - 1;
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]");
|
||||
for (idx = 1; idx < wid; idx += 1) {
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, " + %u]", idx);
|
||||
}
|
||||
fprintf(vlog_out, "}");
|
||||
} else {
|
||||
assert(sel_type == IVL_SEL_IDX_DOWN);
|
||||
for (idx = wid - 1; idx > 0; idx -= 1) {
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, " - %u], ", idx);
|
||||
}
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
ivl_expr_t sel_expr;
|
||||
ivl_select_type_t sel_type;
|
||||
unsigned width = ivl_lval_width(lval);
|
||||
int msb, lsb;
|
||||
assert(width > 0);
|
||||
|
||||
/* If there are no selects then just print the name. */
|
||||
sel_expr = ivl_lval_part_off(lval);
|
||||
if (! sel_expr && (width == ivl_signal_width(sig))) {
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We have some kind of select. */
|
||||
lsb = ivl_signal_lsb(sig);
|
||||
msb = ivl_signal_msb(sig);
|
||||
sel_type = ivl_lval_sel_type(lval);
|
||||
assert(sel_expr);
|
||||
/* A bit select. */
|
||||
if (width == 1) {
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
fprintf(vlog_out, "[");
|
||||
emit_scaled_expr(scope, ivl_lval_part_off(lval), msb, lsb);
|
||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||
fprintf(vlog_out, "]");
|
||||
} else {
|
||||
emit_scaled_range(scope, ivl_lval_part_off(lval), width, msb, lsb);
|
||||
/* A constant part select. */
|
||||
if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) {
|
||||
emit_stmt_lval_name(scope, lval, sig);
|
||||
emit_scaled_range(scope, sel_expr, width, msb, lsb);
|
||||
/* An indexed part select. */
|
||||
} else {
|
||||
assert(sel_type != IVL_SEL_OTHER);
|
||||
emit_stmt_lval_ips(scope, lval, sig, sel_expr, sel_type,
|
||||
width, msb, lsb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,18 +242,20 @@ static unsigned emit_stmt_lval(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
}
|
||||
|
||||
/*
|
||||
* Icarus translated <var> = <delay> <value> into
|
||||
* Icarus translated <var> = <delay or event> <value> into
|
||||
* begin
|
||||
* <tmp> = <value>;
|
||||
* <delay> <var> = <tmp>;
|
||||
* <delay or event> <var> = <tmp>;
|
||||
* end
|
||||
* This routine looks for this pattern and turns it back into the
|
||||
* appropriate blocking assignment.
|
||||
*/
|
||||
static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
static unsigned is_delayed_or_event_assign(ivl_scope_t scope,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
unsigned wid;
|
||||
ivl_statement_t assign, delay, delayed_assign;
|
||||
ivl_statement_type_t delay_type;
|
||||
ivl_lval_t lval;
|
||||
ivl_expr_t rval;
|
||||
ivl_signal_t lsig, rsig;
|
||||
|
|
@ -173,7 +267,9 @@ static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* The second must be a delayx. */
|
||||
delay = ivl_stmt_block_stmt(stmt, 1);
|
||||
if (ivl_statement_type(delay) != IVL_ST_DELAYX) return 0;
|
||||
delay_type = ivl_statement_type(delay);
|
||||
if ((delay_type != IVL_ST_DELAYX) &&
|
||||
(delay_type != IVL_ST_WAIT)) return 0;
|
||||
/* The statement for the delayx must be an assign. */
|
||||
delayed_assign = ivl_stmt_sub_stmt(delay);
|
||||
if (ivl_statement_type(delayed_assign) != IVL_ST_ASSIGN) return 0;
|
||||
|
|
@ -193,16 +289,27 @@ static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
/* It must not be an array word. */
|
||||
if (ivl_expr_oper1(rval)) return 0;
|
||||
rsig = ivl_expr_signal(rval);
|
||||
/* And finally the two signals must be the same. */
|
||||
/* The two signals must be the same. */
|
||||
if (lsig != rsig) return 0;
|
||||
/* And finally the three statements must have the same line number
|
||||
* as the block. */
|
||||
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(delay)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(delayed_assign))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The pattern matched so generate the appropriate code. */
|
||||
fprintf(vlog_out, "%*c", get_indent(), ' ');
|
||||
// HERE: Do we need to calculate the width? The compiler should have already
|
||||
// done this for us.
|
||||
wid = emit_stmt_lval(scope, delayed_assign);
|
||||
fprintf(vlog_out, " = #(");
|
||||
emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay));
|
||||
fprintf(vlog_out, " = ");
|
||||
if (delay_type == IVL_ST_DELAYX) {
|
||||
fprintf(vlog_out, "#(");
|
||||
emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay), 1);
|
||||
} else {
|
||||
fprintf(vlog_out, "@(");
|
||||
emit_event(scope, delay);
|
||||
}
|
||||
fprintf(vlog_out, ") ");
|
||||
emit_expr(scope, ivl_stmt_rval(assign), wid);
|
||||
fprintf(vlog_out, ";");
|
||||
|
|
@ -213,19 +320,93 @@ static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
}
|
||||
|
||||
/*
|
||||
* Icarus translated <var> = <event> <value> into
|
||||
* Icarus translated for(<assign>; <cond>; <incr_assign>) <body> into
|
||||
*
|
||||
* begin
|
||||
* <assign>;
|
||||
* while (<cond>) begin
|
||||
* <body>
|
||||
* <incr_assign>
|
||||
* end
|
||||
* end
|
||||
* This routine looks for this pattern and turns it back into the
|
||||
* appropriate for loop.
|
||||
*/
|
||||
static unsigned is_for_loop(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
unsigned wid;
|
||||
ivl_statement_t assign, while_lp, while_blk, body, incr_assign;
|
||||
|
||||
/* We must have two block elements. */
|
||||
if (ivl_stmt_block_count(stmt) != 2) return 0;
|
||||
/* The first must be an assign. */
|
||||
assign = ivl_stmt_block_stmt(stmt, 0);
|
||||
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* The second must be a while. */
|
||||
while_lp = ivl_stmt_block_stmt(stmt, 1);
|
||||
if (ivl_statement_type(while_lp) != IVL_ST_WHILE) return 0;
|
||||
/* The while statement must be a block. */
|
||||
while_blk = ivl_stmt_sub_stmt(while_lp);
|
||||
if (ivl_statement_type(while_blk) != IVL_ST_BLOCK) return 0;
|
||||
/* It must not be a named block. */
|
||||
if (ivl_stmt_block_scope(while_blk)) return 0;
|
||||
/* It must have two elements. */
|
||||
if (ivl_stmt_block_count(while_blk) != 2) return 0;
|
||||
/* The first block element (the body) can be anything. */
|
||||
body = ivl_stmt_block_stmt(while_blk, 0);
|
||||
/* The second block element must be the increment assign. */
|
||||
incr_assign = ivl_stmt_block_stmt(while_blk, 1);
|
||||
if (ivl_statement_type(incr_assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* And finally the for statements must have the same line number
|
||||
* as the block. */
|
||||
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_lp)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_blk)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(incr_assign))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The pattern matched so generate the appropriate code. */
|
||||
fprintf(vlog_out, "%*cfor(", get_indent(), ' ');
|
||||
/* Emit the initialization statement. */
|
||||
// HERE: Do we need to calculate the width? The compiler should have already
|
||||
// done this for us.
|
||||
wid = emit_stmt_lval(scope, assign);
|
||||
fprintf(vlog_out, " = ");
|
||||
emit_expr(scope, ivl_stmt_rval(assign), wid);
|
||||
fprintf(vlog_out, "; ");
|
||||
/* Emit the condition. */
|
||||
emit_expr(scope, ivl_stmt_cond_expr(while_lp), 0);
|
||||
fprintf(vlog_out, "; ");
|
||||
/* Emit in increment statement. */
|
||||
// HERE: Do we need to calculate the width? The compiler should have already
|
||||
// done this for us.
|
||||
wid = emit_stmt_lval(scope, incr_assign);
|
||||
fprintf(vlog_out, " = ");
|
||||
emit_expr(scope, ivl_stmt_rval(incr_assign), wid);
|
||||
fprintf(vlog_out, ")");
|
||||
emit_stmt_file_line(stmt);
|
||||
/* Now emit the body. */
|
||||
single_indent = 1;
|
||||
emit_stmt(scope, body);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Icarus translated <var> = repeat(<count>) <event> <value> into
|
||||
* begin
|
||||
* <tmp> = <value>;
|
||||
* <event>;
|
||||
* repeat(<count>) <event>;
|
||||
* <var> = <tmp>;
|
||||
* end
|
||||
* This routine looks for this pattern and turns it back into the
|
||||
* appropriate blocking assignment.
|
||||
*/
|
||||
static unsigned find_event_assign(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
static unsigned is_repeat_event_assign(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
unsigned wid;
|
||||
ivl_statement_t assign, event, event_assign, repeat = 0;
|
||||
ivl_statement_t assign, event, event_assign, repeat;
|
||||
ivl_lval_t lval;
|
||||
ivl_expr_t rval;
|
||||
ivl_signal_t lsig, rsig;
|
||||
|
|
@ -236,14 +417,11 @@ static unsigned find_event_assign(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
assign = ivl_stmt_block_stmt(stmt, 0);
|
||||
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* The second must be a repeat with an event or an event. */
|
||||
event = ivl_stmt_block_stmt(stmt, 1);
|
||||
if (ivl_statement_type(event) != IVL_ST_REPEAT &&
|
||||
ivl_statement_type(event) != IVL_ST_WAIT) return 0;
|
||||
if (ivl_statement_type(event) == IVL_ST_REPEAT) {
|
||||
repeat = event;
|
||||
event = ivl_stmt_sub_stmt(repeat);
|
||||
if (ivl_statement_type(event) != IVL_ST_WAIT) return 0;
|
||||
}
|
||||
repeat = ivl_stmt_block_stmt(stmt, 1);
|
||||
if (ivl_statement_type(repeat) != IVL_ST_REPEAT) return 0;
|
||||
/* The repeat must have an event statement. */
|
||||
event = ivl_stmt_sub_stmt(repeat);
|
||||
if (ivl_statement_type(event) != IVL_ST_WAIT) return 0;
|
||||
/* The third must be an assign. */
|
||||
event_assign = ivl_stmt_block_stmt(stmt, 2);
|
||||
if (ivl_statement_type(event_assign) != IVL_ST_ASSIGN) return 0;
|
||||
|
|
@ -263,16 +441,21 @@ static unsigned find_event_assign(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
/* It must not be an array word. */
|
||||
if (ivl_expr_oper1(rval)) return 0;
|
||||
rsig = ivl_expr_signal(rval);
|
||||
/* And finally the two signals must be the same. */
|
||||
/* The two signals must be the same. */
|
||||
if (lsig != rsig) return 0;
|
||||
/* And finally the four statements must have the same line number
|
||||
* as the block. */
|
||||
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(repeat)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(event)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(event_assign))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The pattern matched so generate the appropriate code. */
|
||||
fprintf(vlog_out, "%*c", get_indent(), ' ');
|
||||
// HERE: Do we need to calculate the width? The compiler should have already
|
||||
// done this for us.
|
||||
wid = emit_stmt_lval(scope, event_assign);
|
||||
fprintf(vlog_out, " =");
|
||||
single_indent = 1;
|
||||
if (repeat) {
|
||||
fprintf(vlog_out, " repeat (");
|
||||
emit_expr(scope, ivl_stmt_cond_expr(repeat), 0);
|
||||
|
|
@ -298,7 +481,7 @@ static unsigned find_event_assign(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
* This routine looks for this pattern and turns it back into a
|
||||
* wait statement.
|
||||
*/
|
||||
static unsigned find_wait(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
static unsigned is_wait(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
ivl_statement_t while_wait, wait, wait_stmt;
|
||||
ivl_expr_t while_expr, expr;
|
||||
|
|
@ -317,7 +500,7 @@ static unsigned find_wait(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
while_expr = ivl_stmt_cond_expr(while_wait);
|
||||
if (ivl_expr_type(while_expr) != IVL_EX_BINARY) return 0;
|
||||
if (ivl_expr_opcode(while_expr) != 'N') return 0;
|
||||
/* And has a second operator that is a constant 1'b1. */
|
||||
/* Has a second operator that is a constant 1'b1. */
|
||||
expr = ivl_expr_oper2(while_expr);
|
||||
if (ivl_expr_type(expr) != IVL_EX_NUMBER) return 0;
|
||||
if (ivl_expr_width(expr) != 1) return 0;
|
||||
|
|
@ -325,6 +508,12 @@ static unsigned find_wait(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
if (*bits != '1') return 0;
|
||||
// HERE: There is no easy way to verify that the @ sensitivity list
|
||||
// matches the first expression so we don't check for that yet.
|
||||
/* And finally the two statements that represent the wait must
|
||||
* have the same line number as the block. */
|
||||
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_wait)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(wait))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The pattern matched so generate the appropriate code. */
|
||||
fprintf(vlog_out, "%*cwait(", get_indent(), ' ');
|
||||
|
|
@ -415,7 +604,7 @@ typedef struct port_expr_s {
|
|||
union {
|
||||
ivl_statement_t lval;
|
||||
ivl_expr_t rval;
|
||||
};
|
||||
} expr;
|
||||
} *port_expr_t;
|
||||
|
||||
/*
|
||||
|
|
@ -424,17 +613,16 @@ typedef struct port_expr_s {
|
|||
static void emit_port(ivl_scope_t scope, struct port_expr_s port_expr)
|
||||
{
|
||||
if (port_expr.type == IVL_SIP_INPUT) {
|
||||
emit_expr(scope, port_expr.rval, 0);
|
||||
emit_expr(scope, port_expr.expr.rval, 0);
|
||||
} else {
|
||||
/* This is a self-determined context so we don't care about
|
||||
* the width of the L-value. */
|
||||
(void) emit_stmt_lval(scope, port_expr.lval);
|
||||
(void) emit_stmt_lval(scope, port_expr.expr.lval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Icarus encodes a task call with arguments as:
|
||||
* Icarus encodes a user task call with arguments as:
|
||||
* begin
|
||||
* <input 1> = <arg>
|
||||
* ...
|
||||
|
|
@ -454,6 +642,7 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
|
|||
{
|
||||
unsigned idx, ports, task_idx = 0;
|
||||
unsigned count = ivl_stmt_block_count(stmt);
|
||||
unsigned lineno = ivl_stmt_lineno(stmt);
|
||||
ivl_scope_t task_scope = 0;
|
||||
port_expr_t port_exprs;
|
||||
/* Check to see if the block is of the basic form first. */
|
||||
|
|
@ -477,23 +666,24 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
|
|||
port_exprs = (port_expr_t) malloc(sizeof(struct port_expr_s)*ports);
|
||||
for (idx = 0; idx < ports; idx += 1) {
|
||||
port_exprs[idx].type = IVL_SIP_NONE;
|
||||
port_exprs[idx].rval = 0;
|
||||
port_exprs[idx].expr.rval = 0;
|
||||
}
|
||||
/* Now do a detailed check that the arguments are correct. */
|
||||
/* Check that the input arguments are correct. */
|
||||
for (idx = 0; idx < task_idx; idx += 1) {
|
||||
ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx);
|
||||
unsigned port = utask_in_port_idx(task_scope, assign);
|
||||
if (port == ports) {
|
||||
if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) {
|
||||
free(port_exprs);
|
||||
return 0;
|
||||
}
|
||||
port_exprs[port].type = IVL_SIP_INPUT;
|
||||
port_exprs[port].rval = ivl_stmt_rval(assign);
|
||||
port_exprs[port].expr.rval = ivl_stmt_rval(assign);
|
||||
}
|
||||
/* Check that the output arguments are correct. */
|
||||
for (idx = task_idx + 1; idx < count; idx += 1) {
|
||||
ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx);
|
||||
unsigned port = utask_out_port_idx(task_scope, assign);
|
||||
if (port == ports) {
|
||||
if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) {
|
||||
free(port_exprs);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -504,7 +694,12 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
|
|||
} else {
|
||||
port_exprs[port].type = IVL_SIP_OUTPUT;
|
||||
}
|
||||
port_exprs[port].lval = assign;
|
||||
port_exprs[port].expr.lval = assign;
|
||||
}
|
||||
/* Check that the task call has the correct line number. */
|
||||
if (lineno != ivl_stmt_lineno(ivl_stmt_block_stmt(stmt, task_idx))) {
|
||||
free(port_exprs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Verify that all the ports were defined. */
|
||||
|
|
@ -562,7 +757,6 @@ static void emit_stmt_assign_nb(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
|
||||
static void emit_stmt_block(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
if (is_utask_call_with_args(scope, stmt)) return;
|
||||
fprintf(vlog_out, "%*cbegin", get_indent(), ' ');
|
||||
emit_stmt_file_line(stmt);
|
||||
fprintf(vlog_out, "\n");
|
||||
|
|
@ -573,8 +767,8 @@ static void emit_stmt_block(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
static void emit_stmt_block_named(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
ivl_scope_t my_scope = ivl_stmt_block_scope(stmt);
|
||||
fprintf(vlog_out, "%*cbegin: %s", get_indent(), ' ',
|
||||
ivl_scope_basename(my_scope));
|
||||
fprintf(vlog_out, "%*cbegin: ", get_indent(), ' ');
|
||||
emit_id(ivl_scope_basename(my_scope));
|
||||
emit_stmt_file_line(stmt);
|
||||
fprintf(vlog_out, "\n");
|
||||
emit_stmt_block_body(scope, stmt);
|
||||
|
|
@ -584,23 +778,23 @@ static void emit_stmt_block_named(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
|
||||
static void emit_stmt_case(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
char *name;
|
||||
char *case_type;
|
||||
unsigned idx, default_case, count = ivl_stmt_case_count(stmt);
|
||||
switch(ivl_statement_type(stmt)) {
|
||||
case IVL_ST_CASE:
|
||||
case IVL_ST_CASER:
|
||||
name = "case";
|
||||
case_type = "case";
|
||||
break;
|
||||
case IVL_ST_CASEX:
|
||||
name = "casex";
|
||||
case_type = "casex";
|
||||
break;
|
||||
case IVL_ST_CASEZ:
|
||||
name = "casez";
|
||||
case_type = "casez";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
fprintf(vlog_out, "%*c%s (", get_indent(), ' ', name);
|
||||
fprintf(vlog_out, "%*c%s (", get_indent(), ' ', case_type);
|
||||
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0);
|
||||
fprintf(vlog_out, ")");
|
||||
emit_stmt_file_line(stmt);
|
||||
|
|
@ -704,7 +898,7 @@ static void emit_stmt_delay(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
static void emit_stmt_delayx(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
fprintf(vlog_out, "%*c#(", get_indent(), ' ');
|
||||
emit_scaled_delayx(scope, ivl_stmt_delay_expr(stmt));
|
||||
emit_scaled_delayx(scope, ivl_stmt_delay_expr(stmt), 1);
|
||||
fprintf(vlog_out, ")");
|
||||
emit_stmt_file_line(stmt);
|
||||
single_indent = 1;
|
||||
|
|
@ -755,8 +949,8 @@ static void emit_stmt_fork(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
static void emit_stmt_fork_named(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
ivl_scope_t my_scope = ivl_stmt_block_scope(stmt);
|
||||
fprintf(vlog_out, "%*cfork: %s", get_indent(), ' ',
|
||||
ivl_scope_basename(my_scope));
|
||||
fprintf(vlog_out, "%*cfork: ", get_indent(), ' ');
|
||||
emit_id(ivl_scope_basename(my_scope));
|
||||
emit_stmt_file_line(stmt);
|
||||
fprintf(vlog_out, "\n");
|
||||
emit_stmt_block_body(scope, stmt);
|
||||
|
|
@ -880,9 +1074,11 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
if (ivl_stmt_block_scope(stmt)) {
|
||||
emit_stmt_block_named(scope, stmt);
|
||||
} else {
|
||||
if (find_delayed_assign(scope, stmt)) break;
|
||||
if (find_event_assign(scope, stmt)) break;
|
||||
if (find_wait(scope, stmt)) break;
|
||||
if (is_delayed_or_event_assign(scope, stmt)) break;
|
||||
if (is_for_loop(scope, stmt)) break;
|
||||
if (is_repeat_event_assign(scope, stmt)) break;
|
||||
if (is_wait(scope, stmt)) break;
|
||||
if (is_utask_call_with_args(scope, stmt)) break;
|
||||
emit_stmt_block(scope, stmt);
|
||||
}
|
||||
break;
|
||||
|
|
@ -963,6 +1159,7 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
|
||||
void emit_process(ivl_scope_t scope, ivl_process_t proc)
|
||||
{
|
||||
ivl_statement_t stmt;
|
||||
fprintf(vlog_out, "\n%*c", get_indent(), ' ');
|
||||
switch (ivl_process_type(proc)) {
|
||||
case IVL_PR_INITIAL:
|
||||
|
|
@ -984,6 +1181,11 @@ void emit_process(ivl_scope_t scope, ivl_process_t proc)
|
|||
ivl_process_file(proc),
|
||||
ivl_process_lineno(proc));
|
||||
}
|
||||
single_indent = 1;
|
||||
emit_stmt(scope, ivl_process_stmt(proc));
|
||||
stmt = ivl_process_stmt(proc);
|
||||
if (ivl_statement_type(stmt) == IVL_ST_NOOP) {
|
||||
fprintf(vlog_out, " begin\n%*cend\n", get_indent(), ' ');
|
||||
} else {
|
||||
single_indent = 1;
|
||||
emit_stmt(scope, stmt);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,24 +183,30 @@ static void emit_udp(ivl_udp_t udp)
|
|||
fprintf(vlog_out, "/* This primitive was originally defined in "
|
||||
"file %s at line %u. */\n",
|
||||
ivl_udp_file(udp), ivl_udp_lineno(udp));
|
||||
fprintf(vlog_out, "primitive %s (", ivl_udp_name(udp));
|
||||
// HERE: we need to keep and export the real pin names.
|
||||
fprintf(vlog_out, "out");
|
||||
fprintf(vlog_out, "primitive ");
|
||||
emit_id(ivl_udp_name(udp));
|
||||
fprintf(vlog_out, " (");
|
||||
emit_id(ivl_udp_port(udp, 0));
|
||||
count = ivl_udp_nin(udp);
|
||||
for (idx = 1; idx <= count; idx += 1) {
|
||||
fprintf(vlog_out, ", in%u", idx);
|
||||
fprintf(vlog_out, ", ");
|
||||
emit_id(ivl_udp_port(udp, idx));
|
||||
}
|
||||
fprintf(vlog_out, ");\n");
|
||||
// HERE: we need to keep and export the real pin names.
|
||||
fprintf(vlog_out, "%*coutput out;\n", indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*coutput ", indent_incr, ' ');
|
||||
emit_id(ivl_udp_port(udp, 0));
|
||||
fprintf(vlog_out, ";\n");
|
||||
for (idx = 1; idx <= count; idx += 1) {
|
||||
fprintf(vlog_out, "%*cinput in%u;\n", indent_incr, ' ', idx);
|
||||
fprintf(vlog_out, "%*cinput ", indent_incr, ' ');
|
||||
emit_id(ivl_udp_port(udp, idx));
|
||||
fprintf(vlog_out, ";\n");
|
||||
}
|
||||
if (ivl_udp_sequ(udp)) {
|
||||
char init = ivl_udp_init(udp);
|
||||
fprintf(vlog_out, "\n");
|
||||
// HERE: we need to keep and export the real pin names.
|
||||
fprintf(vlog_out, "%*creg out;\n", indent_incr, ' ');
|
||||
fprintf(vlog_out, "%*creg ", indent_incr, ' ');
|
||||
emit_id(ivl_udp_port(udp, 0));
|
||||
fprintf(vlog_out, ";\n");
|
||||
switch (init) {
|
||||
case '0':
|
||||
case '1':
|
||||
|
|
@ -209,9 +215,9 @@ static void emit_udp(ivl_udp_t udp)
|
|||
init = 'x';
|
||||
break;
|
||||
}
|
||||
// HERE: we need to keep and export the real pin names.
|
||||
fprintf(vlog_out, "%*cinitial out = 1'b%c;\n",
|
||||
indent_incr, ' ', init);
|
||||
fprintf(vlog_out, "%*cinitial ", indent_incr, ' ');
|
||||
emit_id(ivl_udp_port(udp, 0));
|
||||
fprintf(vlog_out, " = 1'b%c;\n", init);
|
||||
}
|
||||
fprintf(vlog_out, "\n");
|
||||
fprintf(vlog_out, "%*ctable\n", indent_incr, ' ');
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ int target_design(ivl_design_t des)
|
|||
char *eptr;
|
||||
long fl_value = strtol(fileline, &eptr, 0);
|
||||
/* Nothing usable in the file/line string. */
|
||||
if (spacing == eptr) {
|
||||
if (fileline == eptr) {
|
||||
fprintf(stderr, "vlog95 error: Unable to extract file/line "
|
||||
"information from string: %s\n", fileline);
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -69,15 +69,19 @@ extern void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt);
|
|||
extern void emit_tran(ivl_scope_t scope, ivl_switch_t tran);
|
||||
|
||||
extern void emit_scaled_delay(ivl_scope_t scope, uint64_t delay);
|
||||
extern void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr);
|
||||
extern void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr,
|
||||
unsigned is_stmt);
|
||||
extern void emit_scaled_expr(ivl_scope_t scope, ivl_expr_t expr,
|
||||
int msb, int lsb);
|
||||
extern void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr,
|
||||
unsigned width, int msb, int lsb);
|
||||
extern void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope);
|
||||
extern void emit_scope_variables(ivl_scope_t scope);
|
||||
extern void emit_scope_call_path(ivl_scope_t scope, ivl_scope_t call_scope);
|
||||
extern void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope);
|
||||
extern void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex);
|
||||
extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex);
|
||||
extern void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex);
|
||||
extern void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t const_net);
|
||||
extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig);
|
||||
extern void emit_icarus_generated_udps();
|
||||
|
|
@ -86,6 +90,7 @@ extern void add_udp_to_list(ivl_udp_t udp);
|
|||
extern void emit_udp_list();
|
||||
extern void emit_sig_file_line(ivl_signal_t sig);
|
||||
|
||||
extern void emit_id(const char *id);
|
||||
extern void emit_real_number(double value);
|
||||
extern void emit_number(const char *bits, unsigned nbits, unsigned is_signed,
|
||||
const char *file, unsigned lineno);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
# include <math.h>
|
||||
# include <string.h>
|
||||
# include <inttypes.h>
|
||||
# include <limits.h>
|
||||
# include <assert.h>
|
||||
# include "ivl_alloc.h"
|
||||
|
||||
|
|
@ -564,7 +565,7 @@ static void display_multi_driver_error(ivl_nexus_t nex, unsigned ndrivers,
|
|||
mdriver_type_t type)
|
||||
{
|
||||
unsigned idx;
|
||||
unsigned scope_len = -1;
|
||||
unsigned scope_len = UINT_MAX;
|
||||
ivl_signal_t sig = 0;
|
||||
/* Find the signal. */
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2005-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -51,7 +51,7 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t expr)
|
|||
/* ports cannot be arrays. */
|
||||
assert(ivl_signal_dimensions(port) == 0);
|
||||
|
||||
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res);
|
||||
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res);
|
||||
clr_word(res);
|
||||
}
|
||||
|
||||
|
|
@ -180,9 +180,9 @@ int draw_ufunc_real(ivl_expr_t expr)
|
|||
|
||||
|
||||
/* Call the function */
|
||||
fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def)));
|
||||
fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def)));
|
||||
fprintf(vvp_out, ", S_%p;\n", def);
|
||||
fprintf(vvp_out, " %%join;\n");
|
||||
fprintf(vvp_out, " %%join;\n");
|
||||
|
||||
/* Return value signal cannot be an array. */
|
||||
assert(ivl_signal_dimensions(retval) == 0);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
|||
|
||||
switch (ivl_expr_type(expr)) {
|
||||
case IVL_EX_SIGNAL:
|
||||
/* If the signal node is narrower then the signal itself,
|
||||
/* If the signal node is narrower than the signal itself,
|
||||
then this is a part select so I'm going to need to
|
||||
evaluate the expression.
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
assert((unsigned)(dp - buffer) <= sizeof buffer);
|
||||
}
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
case IVL_EX_STRING:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2005-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -54,7 +54,8 @@ static int eval_bool64_logic(ivl_expr_t expr)
|
|||
if (ivl_expr_signed(expr))
|
||||
s_flag = "/s";
|
||||
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", s_flag, res, tmp.base, tmp.wid);
|
||||
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", s_flag, res,
|
||||
tmp.base, tmp.wid);
|
||||
clr_vector(tmp);
|
||||
|
||||
return res;
|
||||
|
|
@ -75,7 +76,7 @@ static int draw_number_bool64(ivl_expr_t expr)
|
|||
res = allocate_word();
|
||||
low = val % UINT64_C(0x100000000);
|
||||
hig = val / UINT64_C(0x100000000);
|
||||
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n", res, low, hig);
|
||||
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n", res, low, hig);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -750,7 +750,7 @@ static struct vector_info draw_binary_expr_lor(ivl_expr_t expr, unsigned wid,
|
|||
if (wid == 1) {
|
||||
if (lv.base >= 4 && lv.base < 8) {
|
||||
unsigned tmp = allocate_vector(1);
|
||||
fprintf(vvp_out, " %%mov %u, %u, 1;\n", tmp, lv.base);
|
||||
fprintf(vvp_out, " %%mov %u, %u, 1;\n", tmp, lv.base);
|
||||
lv.base = tmp;
|
||||
}
|
||||
return lv;
|
||||
|
|
@ -932,7 +932,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
|
|||
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
|
||||
long imm = get_number_immediate(le);
|
||||
assert(imm >= 0);
|
||||
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
|
||||
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
|
||||
rv.base, imm, rv.wid);
|
||||
} else {
|
||||
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
|
||||
|
|
@ -948,7 +948,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
|
|||
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
|
||||
long imm = get_number_immediate(re);
|
||||
assert(imm >= 0);
|
||||
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
|
||||
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
|
||||
lv.base, imm, lv.wid);
|
||||
} else {
|
||||
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
|
||||
|
|
@ -964,7 +964,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
|
|||
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
|
||||
long imm = get_number_immediate(re);
|
||||
assert(imm >= 0);
|
||||
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
|
||||
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
|
||||
lv.base, imm, lv.wid);
|
||||
} else {
|
||||
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
|
||||
|
|
@ -979,7 +979,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
|
|||
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
|
||||
long imm = get_number_immediate(le);
|
||||
assert(imm >= 0);
|
||||
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
|
||||
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
|
||||
rv.base, imm, rv.wid);
|
||||
} else {
|
||||
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
|
||||
|
|
@ -1039,7 +1039,7 @@ static struct vector_info draw_logic_immediate(ivl_expr_t expr,
|
|||
switch (ivl_expr_opcode(expr)) {
|
||||
|
||||
case '&':
|
||||
fprintf(vvp_out, " %%andi %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
||||
fprintf(vvp_out, " %%andi %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1158,8 +1158,9 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t expr, unsigned wid)
|
|||
case 'l': /* << (left shift) */
|
||||
lv = draw_eval_expr_wid(le, wid, 0);
|
||||
|
||||
/* shifting 0 gets 0. */
|
||||
if (lv.base == 0)
|
||||
/* Shifting 0 gets 0, if we can be sure the shift value
|
||||
contains no 'x' or 'z' bits. */
|
||||
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
|
||||
return lv;
|
||||
|
||||
if (lv.base < 4) {
|
||||
|
|
@ -1194,8 +1195,9 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t expr, unsigned wid)
|
|||
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
|
||||
}
|
||||
|
||||
/* shifting 0 gets 0. */
|
||||
if (lv.base == 0)
|
||||
/* Shifting 0 gets 0, if we can be sure the shift value
|
||||
contains no 'x' or 'z' bits. */
|
||||
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
|
||||
return lv;
|
||||
|
||||
if (lv.base < 4) {
|
||||
|
|
@ -1230,13 +1232,15 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t expr, unsigned wid)
|
|||
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
|
||||
}
|
||||
|
||||
/* shifting 0 gets 0. */
|
||||
if (lv.base == 0)
|
||||
/* Shifting 0 gets 0, if we can be sure the shift value
|
||||
contains no 'x' or 'z' bits. */
|
||||
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
|
||||
return lv;
|
||||
|
||||
/* Sign extend any constant begets itself, if this
|
||||
expression is signed. */
|
||||
if ((lv.base < 4) && (ivl_expr_signed(expr)))
|
||||
/* Similarly, sign extending any constant bit begets itself,
|
||||
if this expression is signed. */
|
||||
if ((lv.base < 4) && ivl_expr_signed(expr)
|
||||
&& (ivl_expr_value(re) == IVL_VT_BOOL))
|
||||
return lv;
|
||||
|
||||
if (lv.base < 4) {
|
||||
|
|
@ -1984,7 +1988,7 @@ static struct vector_info draw_pad_expr(ivl_expr_t expr, unsigned wid)
|
|||
return res;
|
||||
}
|
||||
|
||||
/* So now we know that the subexpression is smaller then the
|
||||
/* So now we know that the subexpression is smaller than the
|
||||
desired result (the usual case) so we build the
|
||||
result. Evaluate the subexpression into the target buffer,
|
||||
then pad it as appropriate. */
|
||||
|
|
@ -2441,7 +2445,7 @@ static void draw_select_signal_dest(ivl_expr_t expr,
|
|||
|
||||
/* Special case: If the operand is a signal (not an array) and
|
||||
the part select is coming from the LSB, and the part select
|
||||
is no larger then the signal itself, then we can load the
|
||||
is no larger than the signal itself, then we can load the
|
||||
value in place, directly. */
|
||||
if ((ivl_signal_dimensions(sig) == 0)
|
||||
&& (ivl_expr_width(sube) >= dest.wid)
|
||||
|
|
@ -2597,7 +2601,7 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr,
|
|||
subv = res;
|
||||
}
|
||||
|
||||
/* If the subv result is narrower then the select width, then
|
||||
/* If the subv result is narrower than the select width, then
|
||||
copy it into a wider vector. */
|
||||
if (subv.wid < wid && ivl_expr_signed(sube)) {
|
||||
res.base = allocate_vector(wid);
|
||||
|
|
@ -3008,7 +3012,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid)
|
|||
break;
|
||||
}
|
||||
|
||||
/* If the result needs to be bigger then the calculated
|
||||
/* If the result needs to be bigger than the calculated
|
||||
value, then write it into a padded vector. */
|
||||
if (res.wid < wid) {
|
||||
struct vector_info tmp;
|
||||
|
|
@ -3071,7 +3075,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid)
|
|||
fprintf(vvp_out, " %%inv %u, 1;\n", res.base);
|
||||
}
|
||||
|
||||
/* If the result needs to be bigger then the calculated
|
||||
/* If the result needs to be bigger than the calculated
|
||||
value, then write it into a passed vector. */
|
||||
if (res.wid < wid) {
|
||||
struct vector_info tmp;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -22,12 +22,13 @@
|
|||
# include "vvp_priv.h"
|
||||
# include <string.h>
|
||||
# include <assert.h>
|
||||
# include <stdlib.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
|
||||
static const char*version_string =
|
||||
"Icarus Verilog VVP Code Generator " VERSION " (" VERSION_TAG ")\n\n"
|
||||
"Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)\n\n"
|
||||
"Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)\n\n"
|
||||
" This program is free software; you can redistribute it and/or modify\n"
|
||||
" it under the terms of the GNU General Public License as published by\n"
|
||||
" the Free Software Foundation; either version 2 of the License, or\n"
|
||||
|
|
@ -45,6 +46,7 @@ static const char*version_string =
|
|||
|
||||
FILE*vvp_out = 0;
|
||||
int vvp_errors = 0;
|
||||
unsigned show_file_line = 0;
|
||||
|
||||
__inline__ static void draw_execute_header(ivl_design_t des)
|
||||
{
|
||||
|
|
@ -95,8 +97,39 @@ int target_design(ivl_design_t des)
|
|||
unsigned size;
|
||||
unsigned idx;
|
||||
const char*path = ivl_design_flag(des, "-o");
|
||||
/* Use -pfileline to determine if file and line information is
|
||||
* printed for procedural statements. (e.g. -pfileline=1).
|
||||
* The default is no file/line information will be included. */
|
||||
const char*fileline = ivl_design_flag(des, "fileline");
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Check to see if file/line information should be included. */
|
||||
if (strcmp(fileline, "") != 0) {
|
||||
char *eptr;
|
||||
long fl_value = strtol(fileline, &eptr, 0);
|
||||
/* Nothing usable in the file/line string. */
|
||||
if (fileline == eptr) {
|
||||
fprintf(stderr, "vvp error: Unable to extract file/line "
|
||||
"information from string: %s\n", fileline);
|
||||
return 1;
|
||||
}
|
||||
/* Extra stuff at the end. */
|
||||
if (*eptr != 0) {
|
||||
fprintf(stderr, "vvp error: Extra characters '%s' "
|
||||
"included at end of file/line string: %s\n",
|
||||
eptr, fileline);
|
||||
return 1;
|
||||
}
|
||||
/* The file/line flag must be positive. */
|
||||
if (fl_value < 0) {
|
||||
fprintf(stderr, "vvp error: File/line flag (%ld) must "
|
||||
"be positive.\n", fl_value);
|
||||
return 1;
|
||||
}
|
||||
show_file_line = fl_value > 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FOPEN64
|
||||
vvp_out = fopen64(path, "w");
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __vvp_priv_H
|
||||
#define __vvp_priv_H
|
||||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -39,6 +39,12 @@ extern FILE* vvp_out;
|
|||
*/
|
||||
extern int vvp_errors;
|
||||
|
||||
/*
|
||||
* Set to non-zero when the user wants to display file and line number
|
||||
* information for procedural statements.
|
||||
*/
|
||||
extern unsigned show_file_line;
|
||||
|
||||
struct vector_info {
|
||||
unsigned base;
|
||||
unsigned wid;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -111,13 +111,13 @@ static void set_to_lvariable(ivl_lval_t lval,
|
|||
unsigned skip_set = transient_id++;
|
||||
if (word_ix) {
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
}
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
||||
|
|
@ -128,12 +128,12 @@ static void set_to_lvariable(ivl_lval_t lval,
|
|||
unsigned skip_set = transient_id++;
|
||||
if (word_ix) {
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
}
|
||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
if (word_ix) /* Only need this label if word_ix is set. */
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
|
@ -155,9 +155,9 @@ static void set_to_lvariable(ivl_lval_t lval,
|
|||
unsigned skip_set = transient_id++;
|
||||
unsigned index_reg = 3;
|
||||
draw_eval_expr_into_integer(word_ix, index_reg);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
}
|
||||
|
|
@ -171,9 +171,10 @@ static void set_to_lvariable(ivl_lval_t lval,
|
|||
directly to the word and save the index calculation. */
|
||||
if (word_ix == 0) {
|
||||
if (use_word < ivl_signal_array_count(sig)) {
|
||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
|
||||
use_word);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
} else {
|
||||
fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u "
|
||||
|
|
@ -184,9 +185,9 @@ static void set_to_lvariable(ivl_lval_t lval,
|
|||
unsigned skip_set = transient_id++;
|
||||
unsigned index_reg = 3;
|
||||
draw_eval_expr_into_integer(word_ix, index_reg);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
}
|
||||
|
|
@ -535,6 +536,24 @@ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to insert statement tracing information into the output stream
|
||||
* when requested by the user (compiler).
|
||||
*/
|
||||
static void show_stmt_file_line(ivl_statement_t net, const char* desc)
|
||||
{
|
||||
if (show_file_line) {
|
||||
/* If the line number is not zero then the file should also
|
||||
* be set. It's safe to skip the assert during debug, but
|
||||
* the assert represents missing file/line information that
|
||||
* should be reported/fixed. */
|
||||
unsigned lineno = ivl_stmt_lineno(net);
|
||||
assert(lineno);
|
||||
fprintf(vvp_out, " %%file_line %d %d \"%s\";\n",
|
||||
ivl_file_table_index(ivl_stmt_file(net)), lineno, desc);
|
||||
}
|
||||
}
|
||||
|
||||
static int show_stmt_alloc(ivl_statement_t net)
|
||||
{
|
||||
ivl_scope_t scope = ivl_stmt_call(net);
|
||||
|
|
@ -637,6 +656,8 @@ static int show_stmt_assign(ivl_statement_t net)
|
|||
ivl_lval_t lval;
|
||||
ivl_signal_t sig;
|
||||
|
||||
show_stmt_file_line(net, "Blocking assignment.");
|
||||
|
||||
lval = ivl_stmt_lval(net, 0);
|
||||
|
||||
sig = ivl_lval_sig(lval);
|
||||
|
|
@ -739,6 +760,8 @@ static int show_stmt_assign_nb(ivl_statement_t net)
|
|||
ivl_signal_t sig;
|
||||
unsigned nevents = ivl_stmt_nevent(net);
|
||||
|
||||
show_stmt_file_line(net, "Nonblocking assignment.");
|
||||
|
||||
/* If we have an event control build the control structure. */
|
||||
if (nevents) {
|
||||
assert(del == 0);
|
||||
|
|
@ -922,6 +945,8 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
|
|||
|
||||
unsigned idx, default_case;
|
||||
|
||||
show_stmt_file_line(net, "Case statement.");
|
||||
|
||||
local_count += count + 1;
|
||||
|
||||
/* First draw the branch table. All the non-default cases
|
||||
|
|
@ -1039,8 +1064,9 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
|
|||
|
||||
unsigned idx, default_case;
|
||||
|
||||
local_count += count + 1;
|
||||
show_stmt_file_line(net, "Case statement.");
|
||||
|
||||
local_count += count + 1;
|
||||
|
||||
/* First draw the branch table. All the non-default cases
|
||||
generate a branch out of here, to the code that implements
|
||||
|
|
@ -1282,6 +1308,8 @@ static int show_stmt_cassign(ivl_statement_t net)
|
|||
ivl_expr_t rval;
|
||||
ivl_signal_t sig;
|
||||
|
||||
show_stmt_file_line(net, "Assign statement.");
|
||||
|
||||
rval = ivl_stmt_rval(net);
|
||||
assert(rval);
|
||||
|
||||
|
|
@ -1318,6 +1346,8 @@ static int show_stmt_deassign(ivl_statement_t net)
|
|||
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
unsigned lidx;
|
||||
|
||||
show_stmt_file_line(net, "Deassign statement.");
|
||||
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
ivl_lval_t lval;
|
||||
|
||||
|
|
@ -1372,8 +1402,11 @@ static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope)
|
|||
int rc = 0;
|
||||
unsigned lab_false, lab_out;
|
||||
ivl_expr_t expr = ivl_stmt_cond_expr(net);
|
||||
struct vector_info cond
|
||||
= draw_eval_expr(expr, STUFF_OK_XZ|STUFF_OK_47|STUFF_OK_RO);
|
||||
struct vector_info cond;
|
||||
|
||||
show_stmt_file_line(net, "If statement.");
|
||||
|
||||
cond = draw_eval_expr(expr, STUFF_OK_XZ|STUFF_OK_47|STUFF_OK_RO);
|
||||
|
||||
assert(cond.wid == 1);
|
||||
|
||||
|
|
@ -1426,6 +1459,8 @@ static int show_stmt_delay(ivl_statement_t net, ivl_scope_t sscope)
|
|||
unsigned long low = delay % UINT64_C(0x100000000);
|
||||
unsigned long hig = delay / UINT64_C(0x100000000);
|
||||
|
||||
show_stmt_file_line(net, "Delay statement.");
|
||||
|
||||
fprintf(vvp_out, " %%delay %lu, %lu;\n", low, hig);
|
||||
/* Lots of things can happen during a delay. */
|
||||
clear_expression_lookaside();
|
||||
|
|
@ -1447,6 +1482,8 @@ static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
|
|||
ivl_expr_t expr = ivl_stmt_delay_expr(net);
|
||||
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
|
||||
|
||||
show_stmt_file_line(net, "Delay statement.");
|
||||
|
||||
switch (ivl_expr_value(expr)) {
|
||||
|
||||
case IVL_VT_BOOL:
|
||||
|
|
@ -1480,8 +1517,10 @@ static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
|
|||
static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
ivl_scope_t target = ivl_stmt_call(net);
|
||||
|
||||
show_stmt_file_line(net, "Disable statement.");
|
||||
|
||||
fprintf(vvp_out, " %%disable S_%p;\n", target);
|
||||
|
||||
return rc;
|
||||
|
|
@ -1492,6 +1531,8 @@ static int show_stmt_force(ivl_statement_t net)
|
|||
ivl_expr_t rval;
|
||||
ivl_signal_t sig;
|
||||
|
||||
show_stmt_file_line(net, "Force statement.");
|
||||
|
||||
rval = ivl_stmt_rval(net);
|
||||
assert(rval);
|
||||
|
||||
|
|
@ -1524,6 +1565,8 @@ static int show_stmt_forever(ivl_statement_t net, ivl_scope_t sscope)
|
|||
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
|
||||
unsigned lab_top = local_count++;
|
||||
|
||||
show_stmt_file_line(net, "Forever statement.");
|
||||
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_top);
|
||||
rc += show_statement(stmt, sscope);
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
|
||||
|
|
@ -1614,6 +1657,8 @@ static int show_stmt_release(ivl_statement_t net)
|
|||
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
unsigned lidx;
|
||||
|
||||
show_stmt_file_line(net, "Release statement.");
|
||||
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
unsigned type = 0;
|
||||
ivl_lval_t lval;
|
||||
|
|
@ -1682,9 +1727,13 @@ static int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope)
|
|||
int rc = 0;
|
||||
unsigned lab_top = local_count++, lab_out = local_count++;
|
||||
ivl_expr_t expr = ivl_stmt_cond_expr(net);
|
||||
struct vector_info cnt = draw_eval_expr(expr, 0);
|
||||
struct vector_info cnt;
|
||||
const char *sign = ivl_expr_signed(expr) ? "s" : "u";
|
||||
|
||||
show_stmt_file_line(net, "Repeat statement.");
|
||||
|
||||
cnt = draw_eval_expr(expr, 0);
|
||||
|
||||
/* Test that 0 < expr */
|
||||
fprintf(vvp_out, "T_%u.%u %%cmp/%s 0, %u, %u;\n", thread_count,
|
||||
lab_top, sign, cnt.base, cnt.wid);
|
||||
|
|
@ -1712,6 +1761,9 @@ static int show_stmt_trigger(ivl_statement_t net)
|
|||
{
|
||||
ivl_event_t ev = ivl_stmt_events(net, 0);
|
||||
assert(ev);
|
||||
|
||||
show_stmt_file_line(net, "Event trigger statement.");
|
||||
|
||||
fprintf(vvp_out, " %%set/v E_%p, 0,1;\n", ev);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1720,6 +1772,8 @@ static int show_stmt_utask(ivl_statement_t net)
|
|||
{
|
||||
ivl_scope_t task = ivl_stmt_call(net);
|
||||
|
||||
show_stmt_file_line(net, "User task call.");
|
||||
|
||||
fprintf(vvp_out, " %%fork TD_%s",
|
||||
vvp_mangle_id(ivl_scope_name(task)));
|
||||
fprintf(vvp_out, ", S_%p;\n", task);
|
||||
|
|
@ -1730,6 +1784,8 @@ static int show_stmt_utask(ivl_statement_t net)
|
|||
|
||||
static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
show_stmt_file_line(net, "Event wait (@) statement.");
|
||||
|
||||
if (ivl_stmt_nevent(net) == 1) {
|
||||
ivl_event_t ev = ivl_stmt_events(net, 0);
|
||||
fprintf(vvp_out, " %%wait E_%p;\n", ev);
|
||||
|
|
@ -1793,6 +1849,8 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
|
|||
unsigned top_label = local_count++;
|
||||
unsigned out_label = local_count++;
|
||||
|
||||
show_stmt_file_line(net, "While statement.");
|
||||
|
||||
/* Start the loop. The top of the loop starts a basic block
|
||||
because it can be entered from above or from the bottom of
|
||||
the loop. */
|
||||
|
|
@ -1824,6 +1882,8 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
|
|||
|
||||
static int show_system_task_call(ivl_statement_t net)
|
||||
{
|
||||
show_stmt_file_line(net, "System task call.");
|
||||
|
||||
draw_vpi_task_call(net);
|
||||
|
||||
/* VPI calls can manipulate anything, so clear the expression
|
||||
|
|
@ -1833,6 +1893,361 @@ static int show_system_task_call(ivl_statement_t net)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Icarus translated <var> = <delay or event> <value> into
|
||||
* begin
|
||||
* <tmp> = <value>;
|
||||
* <delay or event> <var> = <tmp>;
|
||||
* end
|
||||
* This routine looks for this pattern so we only emit one %file_line opcode.
|
||||
*/
|
||||
|
||||
static unsigned is_delayed_or_event_assign(ivl_scope_t scope,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
ivl_statement_t assign, delay, delayed_assign;
|
||||
ivl_statement_type_t delay_type;
|
||||
ivl_lval_t lval;
|
||||
ivl_expr_t rval;
|
||||
ivl_signal_t lsig, rsig;
|
||||
|
||||
/* We must have two block elements. */
|
||||
if (ivl_stmt_block_count(stmt) != 2) return 0;
|
||||
/* The first must be an assign. */
|
||||
assign = ivl_stmt_block_stmt(stmt, 0);
|
||||
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* The second must be a delayx. */
|
||||
delay = ivl_stmt_block_stmt(stmt, 1);
|
||||
delay_type = ivl_statement_type(delay);
|
||||
if ((delay_type != IVL_ST_DELAYX) &&
|
||||
(delay_type != IVL_ST_WAIT)) return 0;
|
||||
/* The statement for the delayx must be an assign. */
|
||||
delayed_assign = ivl_stmt_sub_stmt(delay);
|
||||
if (ivl_statement_type(delayed_assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* The L-value must be a single signal. */
|
||||
if (ivl_stmt_lvals(assign) != 1) return 0;
|
||||
lval = ivl_stmt_lval(assign, 0);
|
||||
/* It must not have an array select. */
|
||||
if (ivl_lval_idx(lval)) return 0;
|
||||
/* It must not have a non-zero base. */
|
||||
if (ivl_lval_part_off(lval)) return 0;
|
||||
lsig = ivl_lval_sig(lval);
|
||||
/* It must not be part of the signal. */
|
||||
if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0;
|
||||
/* The R-value must be a single signal. */
|
||||
rval = ivl_stmt_rval(delayed_assign);
|
||||
if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return 0;
|
||||
/* It must not be an array word. */
|
||||
if (ivl_expr_oper1(rval)) return 0;
|
||||
rsig = ivl_expr_signal(rval);
|
||||
/* The two signals must be the same. */
|
||||
if (lsig != rsig) return 0;
|
||||
/* And finally the three statements must have the same line number
|
||||
* as the block. */
|
||||
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(delay)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(delayed_assign))) {
|
||||
return 0;
|
||||
}
|
||||
/* The pattern matched so this block represents a blocking
|
||||
* assignment with an inter-assignment delay or event. */
|
||||
if (delay_type == IVL_ST_DELAYX) {
|
||||
show_stmt_file_line(stmt, "Blocking assignment (delay).");
|
||||
} else {
|
||||
show_stmt_file_line(stmt, "Blocking assignment (event).");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Icarus translated <var> = repeat(<count>) <event> <value> into
|
||||
* begin
|
||||
* <tmp> = <value>;
|
||||
* repeat(<count>) <event>;
|
||||
* <var> = <tmp>;
|
||||
* end
|
||||
* This routine looks for this pattern so we only emit one %file_line opcode.
|
||||
*/
|
||||
static unsigned is_repeat_event_assign(ivl_scope_t scope,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
ivl_statement_t assign, event, event_assign, repeat;
|
||||
ivl_lval_t lval;
|
||||
ivl_expr_t rval;
|
||||
ivl_signal_t lsig, rsig;
|
||||
|
||||
/* We must have three block elements. */
|
||||
if (ivl_stmt_block_count(stmt) != 3) return 0;
|
||||
/* The first must be an assign. */
|
||||
assign = ivl_stmt_block_stmt(stmt, 0);
|
||||
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* The second must be a repeat with an event or an event. */
|
||||
repeat = ivl_stmt_block_stmt(stmt, 1);
|
||||
if (ivl_statement_type(repeat) != IVL_ST_REPEAT) return 0;
|
||||
/* The repeat must have an event statement. */
|
||||
event = ivl_stmt_sub_stmt(repeat);
|
||||
if (ivl_statement_type(event) != IVL_ST_WAIT) return 0;
|
||||
/* The third must be an assign. */
|
||||
event_assign = ivl_stmt_block_stmt(stmt, 2);
|
||||
if (ivl_statement_type(event_assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* The L-value must be a single signal. */
|
||||
if (ivl_stmt_lvals(assign) != 1) return 0;
|
||||
lval = ivl_stmt_lval(assign, 0);
|
||||
/* It must not have an array select. */
|
||||
if (ivl_lval_idx(lval)) return 0;
|
||||
/* It must not have a non-zero base. */
|
||||
if (ivl_lval_part_off(lval)) return 0;
|
||||
lsig = ivl_lval_sig(lval);
|
||||
/* It must not be part of the signal. */
|
||||
if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0;
|
||||
/* The R-value must be a single signal. */
|
||||
rval = ivl_stmt_rval(event_assign);
|
||||
if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return 0;
|
||||
/* It must not be an array word. */
|
||||
if (ivl_expr_oper1(rval)) return 0;
|
||||
rsig = ivl_expr_signal(rval);
|
||||
/* The two signals must be the same. */
|
||||
if (lsig != rsig) return 0;
|
||||
/* And finally the four statements must have the same line number
|
||||
* as the block. */
|
||||
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(repeat)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(event)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(event_assign))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The pattern matched so this block represents a blocking
|
||||
* assignment with an inter-assignment repeat event. */
|
||||
show_stmt_file_line(stmt, "Blocking assignment (repeat event).");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Icarus translated wait(<expr) <stmt> into
|
||||
* begin
|
||||
* while (<expr> !== 1'b1) @(<expr sensitivities>);
|
||||
* <stmt>
|
||||
* end
|
||||
* This routine looks for this pattern and turns it back into a
|
||||
* wait statement.
|
||||
*/
|
||||
static unsigned is_wait(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
ivl_statement_t while_wait, wait, wait_stmt;
|
||||
ivl_expr_t while_expr, expr;
|
||||
const char *bits;
|
||||
/* We must have two block elements. */
|
||||
if (ivl_stmt_block_count(stmt) != 2) return 0;
|
||||
/* The first must be a while. */
|
||||
while_wait = ivl_stmt_block_stmt(stmt, 0);
|
||||
if (ivl_statement_type(while_wait) != IVL_ST_WHILE) return 0;
|
||||
/* That has a wait with a NOOP statement. */
|
||||
wait = ivl_stmt_sub_stmt(while_wait);
|
||||
if (ivl_statement_type(wait) != IVL_ST_WAIT) return 0;
|
||||
wait_stmt = ivl_stmt_sub_stmt(wait);
|
||||
if (ivl_statement_type(wait_stmt) != IVL_ST_NOOP) return 0;
|
||||
/* Check that the while condition has the correct form. */
|
||||
while_expr = ivl_stmt_cond_expr(while_wait);
|
||||
if (ivl_expr_type(while_expr) != IVL_EX_BINARY) return 0;
|
||||
if (ivl_expr_opcode(while_expr) != 'N') return 0;
|
||||
/* Has a second operator that is a constant 1'b1. */
|
||||
expr = ivl_expr_oper2(while_expr);
|
||||
if (ivl_expr_type(expr) != IVL_EX_NUMBER) return 0;
|
||||
if (ivl_expr_width(expr) != 1) return 0;
|
||||
bits = ivl_expr_bits(expr);
|
||||
if (*bits != '1') return 0;
|
||||
/* There is no easy way to verify that the @ sensitivity list
|
||||
* matches the first expression so that is not currently checked. */
|
||||
/* And finally the two statements that represent the wait must
|
||||
* have the same line number as the block. */
|
||||
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_wait)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(wait))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The pattern matched so this block represents a wait statement. */
|
||||
show_stmt_file_line(stmt, "Wait statement.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the statement L-value is a port in the given scope.
|
||||
* If it is return the zero based port number.
|
||||
*/
|
||||
static unsigned utask_in_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
unsigned idx, ports = ivl_scope_ports(scope);
|
||||
ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
|
||||
ivl_signal_t lsig = ivl_lval_sig(lval);
|
||||
const char *sig_name;
|
||||
/* The L-value must be a single signal. */
|
||||
if (ivl_stmt_lvals(stmt) != 1) return ports;
|
||||
/* It must not have an array select. */
|
||||
if (ivl_lval_idx(lval)) return ports;
|
||||
/* It must not have a non-zero base. */
|
||||
if (ivl_lval_part_off(lval)) return ports;
|
||||
/* It must not be part of the signal. */
|
||||
if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return ports;
|
||||
/* It must have the same scope as the task. */
|
||||
if (scope != ivl_signal_scope(lsig)) return ports;
|
||||
/* It must be an input or inout port of the task. */
|
||||
sig_name = ivl_signal_basename(lsig);
|
||||
for (idx = 0; idx < ports; idx += 1) {
|
||||
ivl_signal_t port = ivl_scope_port(scope, idx);
|
||||
ivl_signal_port_t port_type = ivl_signal_port(port);
|
||||
if ((port_type != IVL_SIP_INPUT) &&
|
||||
(port_type != IVL_SIP_INOUT)) continue;
|
||||
if (strcmp(sig_name, ivl_signal_basename(port)) == 0) break;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the statement R-value is a port in the given scope.
|
||||
* If it is return the zero based port number.
|
||||
*/
|
||||
static unsigned utask_out_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
unsigned idx, ports = ivl_scope_ports(scope);
|
||||
ivl_expr_t rval = ivl_stmt_rval(stmt);
|
||||
ivl_signal_t rsig = 0;
|
||||
ivl_expr_type_t expr_type = ivl_expr_type(rval);
|
||||
const char *sig_name;
|
||||
/* We can have a simple signal. */
|
||||
if (expr_type == IVL_EX_SIGNAL) {
|
||||
rsig = ivl_expr_signal(rval);
|
||||
/* Or a simple select of a simple signal. */
|
||||
} else if (expr_type == IVL_EX_SELECT) {
|
||||
ivl_expr_t expr = ivl_expr_oper1(rval);
|
||||
/* We must have a zero select base. */
|
||||
if (ivl_expr_oper2(rval)) return ports;
|
||||
/* We must be selecting a signal. */
|
||||
if (ivl_expr_type(expr) != IVL_EX_SIGNAL) return ports;
|
||||
rsig = ivl_expr_signal(expr);
|
||||
} else return ports;
|
||||
/* The R-value must have the same scope as the task. */
|
||||
if (scope != ivl_signal_scope(rsig)) return ports;
|
||||
/* It must not be an array element. */
|
||||
if (ivl_signal_dimensions(rsig)) return ports;
|
||||
/* It must be an output or inout port of the task. */
|
||||
sig_name = ivl_signal_basename(rsig);
|
||||
for (idx = 0; idx < ports; idx += 1) {
|
||||
ivl_signal_t port = ivl_scope_port(scope, idx);
|
||||
ivl_signal_port_t port_type = ivl_signal_port(port);
|
||||
if ((port_type != IVL_SIP_OUTPUT) &&
|
||||
(port_type != IVL_SIP_INOUT)) continue;
|
||||
if (strcmp(sig_name, ivl_signal_basename(port)) == 0) break;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure to hold the port information as we extract it from the block.
|
||||
*/
|
||||
typedef struct port_expr_s {
|
||||
ivl_signal_port_t type;
|
||||
union {
|
||||
ivl_statement_t lval;
|
||||
ivl_expr_t rval;
|
||||
} expr;
|
||||
} *port_expr_t;
|
||||
|
||||
/*
|
||||
* Icarus encodes a user task call with arguments as:
|
||||
* begin
|
||||
* <input 1> = <arg>
|
||||
* ...
|
||||
* <input n> = <arg>
|
||||
* <task_call>
|
||||
* <arg> = <output 1>
|
||||
* ...
|
||||
* <arg> = <output n>
|
||||
* end
|
||||
* This routine looks for that pattern and translates it into the
|
||||
* appropriate task call. It returns true (1) if it successfully
|
||||
* translated the block to a task call, otherwise it returns false
|
||||
* (0) to indicate the block needs to be emitted.
|
||||
*/
|
||||
static unsigned is_utask_call_with_args(ivl_scope_t scope,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
unsigned idx, ports, task_idx = 0;
|
||||
unsigned count = ivl_stmt_block_count(stmt);
|
||||
unsigned lineno = ivl_stmt_lineno(stmt);
|
||||
ivl_scope_t task_scope = 0;
|
||||
port_expr_t port_exprs;
|
||||
/* Check to see if the block is of the basic form first. */
|
||||
for (idx = 0; idx < count; idx += 1) {
|
||||
ivl_statement_t tmp = ivl_stmt_block_stmt(stmt, idx);
|
||||
if (ivl_statement_type(tmp) == IVL_ST_ASSIGN) continue;
|
||||
if (ivl_statement_type(tmp) == IVL_ST_UTASK && !task_scope) {
|
||||
task_idx = idx;
|
||||
task_scope = ivl_stmt_call(tmp);
|
||||
assert(ivl_scope_type(task_scope) == IVL_SCT_TASK);
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* If there is no task call or it takes no argument then return. */
|
||||
if (!task_scope) return 0;
|
||||
ports = ivl_scope_ports(task_scope);
|
||||
if (ports == 0) return 0;
|
||||
|
||||
/* Allocate space to save the port information and initialize it. */
|
||||
port_exprs = (port_expr_t) malloc(sizeof(struct port_expr_s)*ports);
|
||||
for (idx = 0; idx < ports; idx += 1) {
|
||||
port_exprs[idx].type = IVL_SIP_NONE;
|
||||
port_exprs[idx].expr.rval = 0;
|
||||
}
|
||||
/* Check that the input arguments are correct. */
|
||||
for (idx = 0; idx < task_idx; idx += 1) {
|
||||
ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx);
|
||||
unsigned port = utask_in_port_idx(task_scope, assign);
|
||||
if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) {
|
||||
free(port_exprs);
|
||||
return 0;
|
||||
}
|
||||
port_exprs[port].type = IVL_SIP_INPUT;
|
||||
port_exprs[port].expr.rval = ivl_stmt_rval(assign);
|
||||
}
|
||||
/* Check that the output arguments are correct. */
|
||||
for (idx = task_idx + 1; idx < count; idx += 1) {
|
||||
ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx);
|
||||
unsigned port = utask_out_port_idx(task_scope, assign);
|
||||
if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) {
|
||||
free(port_exprs);
|
||||
return 0;
|
||||
}
|
||||
if (port_exprs[port].type == IVL_SIP_INPUT) {
|
||||
/* We probably should verify that the current R-value
|
||||
* matches the new L-value. */
|
||||
port_exprs[port].type = IVL_SIP_INOUT;
|
||||
} else {
|
||||
port_exprs[port].type = IVL_SIP_OUTPUT;
|
||||
}
|
||||
port_exprs[port].expr.lval = assign;
|
||||
}
|
||||
/* Check that the task call has the correct line number. */
|
||||
if (lineno != ivl_stmt_lineno(ivl_stmt_block_stmt(stmt, task_idx))) {
|
||||
free(port_exprs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Verify that all the ports were defined. */
|
||||
for (idx = 0; idx < ports; idx += 1) {
|
||||
if (port_exprs[idx].type == IVL_SIP_NONE) {
|
||||
free(port_exprs);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* The pattern matched so this block represents a call to a user
|
||||
* defined task with arguments. */
|
||||
show_stmt_file_line(stmt, "User task call (with arguments).");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function draws a statement as vvp assembly. It basically
|
||||
* switches on the statement type and draws code based on the type and
|
||||
|
|
@ -1842,6 +2257,7 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
|||
{
|
||||
const ivl_statement_type_t code = ivl_statement_type(net);
|
||||
int rc = 0;
|
||||
unsigned saved_file_line = 0;
|
||||
|
||||
switch (code) {
|
||||
|
||||
|
|
@ -1860,8 +2276,21 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
|||
case IVL_ST_BLOCK:
|
||||
if (ivl_stmt_block_scope(net))
|
||||
rc += show_stmt_block_named(net, sscope);
|
||||
else
|
||||
else {
|
||||
/* This block could really represent a single statement.
|
||||
* If so only emit a single %file_line opcode. */
|
||||
if (show_file_line) {
|
||||
if (is_delayed_or_event_assign(sscope, net) ||
|
||||
is_repeat_event_assign(sscope, net) ||
|
||||
is_wait(sscope, net) ||
|
||||
is_utask_call_with_args(sscope, net)) {
|
||||
saved_file_line = show_file_line;
|
||||
show_file_line = 0;
|
||||
}
|
||||
}
|
||||
rc += show_stmt_block(net, sscope);
|
||||
if (saved_file_line) show_file_line = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_ST_CASE:
|
||||
|
|
|
|||
37
verinum.cc
37
verinum.cc
|
|
@ -287,7 +287,7 @@ verinum::verinum(const verinum&that)
|
|||
|
||||
verinum::verinum(const verinum&that, unsigned nbits)
|
||||
{
|
||||
string_flag_ = false;
|
||||
string_flag_ = that.string_flag_ && (that.nbits_ == nbits);
|
||||
nbits_ = nbits;
|
||||
bits_ = new V[nbits_];
|
||||
has_len_ = true;
|
||||
|
|
@ -591,6 +591,39 @@ verinum pad_to_width(const verinum&that, unsigned width)
|
|||
return val;
|
||||
}
|
||||
|
||||
verinum cast_to_width(const verinum&that, unsigned width)
|
||||
{
|
||||
if (that.has_len() && (that.len() == width))
|
||||
return that;
|
||||
|
||||
if (that.len() >= width)
|
||||
return verinum(that, width);
|
||||
|
||||
if (that.len() == 0) {
|
||||
verinum val (verinum::V0, width, true);
|
||||
val.has_sign(that.has_sign());
|
||||
return val;
|
||||
}
|
||||
|
||||
verinum::V pad = that[that.len()-1];
|
||||
if (pad==verinum::V1 && !that.has_sign())
|
||||
pad = verinum::V0;
|
||||
if (that.has_len() && !that.has_sign()) {
|
||||
if (pad==verinum::Vx)
|
||||
pad = verinum::V0;
|
||||
if (pad==verinum::Vz)
|
||||
pad = verinum::V0;
|
||||
}
|
||||
|
||||
verinum val(pad, width, true);
|
||||
|
||||
for (unsigned idx = 0 ; idx < that.len() ; idx += 1)
|
||||
val.set(idx, that[idx]);
|
||||
|
||||
val.has_sign(that.has_sign());
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns a version of the verinum that has only as
|
||||
* many bits as are needed to accurately represent the value. It takes
|
||||
|
|
@ -1097,6 +1130,7 @@ verinum pow(const verinum&left, const verinum&right)
|
|||
verinum operator << (const verinum&that, unsigned shift)
|
||||
{
|
||||
verinum result(verinum::V0, that.len() + shift, that.has_len());
|
||||
result.has_sign(that.has_sign());
|
||||
|
||||
for (unsigned idx = 0 ; idx < that.len() ; idx += 1)
|
||||
result.set(idx+shift, that.get(idx));
|
||||
|
|
@ -1119,6 +1153,7 @@ verinum operator >> (const verinum&that, unsigned shift)
|
|||
|
||||
verinum result(that.has_sign()? that.get(that.len()-1) : verinum::V0,
|
||||
that.len() - shift, that.has_len());
|
||||
result.has_sign(that.has_sign());
|
||||
|
||||
for (unsigned idx = shift ; idx < that.len() ; idx += 1)
|
||||
result.set(idx-shift, that.get(idx));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __verinum_H
|
||||
#define __verinum_H
|
||||
/*
|
||||
* Copyright (c) 1998-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -64,6 +64,7 @@ class verinum {
|
|||
|
||||
// A number "has a length" if the length was specified fixed
|
||||
// in some way.
|
||||
bool has_len(bool flag) { has_len_ = flag; return has_len_; }
|
||||
bool has_len() const { return has_len_; }
|
||||
|
||||
bool has_sign(bool flag) { has_sign_ = flag; return has_sign_; }
|
||||
|
|
@ -126,6 +127,12 @@ inline verinum::V sign_bit(const verinum&val)
|
|||
extension, if the value is signed. */
|
||||
extern verinum pad_to_width(const verinum&, unsigned width);
|
||||
|
||||
/* Return a verinum that has the same value as the input, but is
|
||||
exactly the requested width. This may involve sign extension,
|
||||
if the value is signed. The returned verinum will have fixed
|
||||
width. */
|
||||
extern verinum cast_to_width(const verinum&, unsigned width);
|
||||
|
||||
/* Return a verinum that is minimal. That is, it has only the length
|
||||
needed to accurately represent the contained value, signed or not. */
|
||||
extern verinum trim_vnum(const verinum&);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@
|
|||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@ @EXTRALIBS@
|
||||
|
||||
M = StringHeap.o LineInfo.o
|
||||
M = StringHeap.o LineInfo.o
|
||||
|
||||
O = main.o architec.o compiler.o entity.o entity_elaborate.o \
|
||||
expression.o vtype.o lexor.o lexor_keyword.o parse.o parse_misc.o vhdlreal.o vhdlint.o debug.o \
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
%option never-interactive
|
||||
%option nounput
|
||||
%option noyywrap
|
||||
|
||||
%{
|
||||
/*
|
||||
|
|
@ -99,7 +98,7 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])*
|
|||
<CCOMMENT>\n { yylloc.first_line += 1; }
|
||||
<CCOMMENT>"*/" { BEGIN(comment_enter); }
|
||||
|
||||
\'.\' {
|
||||
\'.\' {
|
||||
yylval.text = escape_apostrophe_and_dup(yytext);
|
||||
return CHARACTER_LITERAL;
|
||||
}
|
||||
|
|
@ -121,7 +120,7 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])*
|
|||
if(!are_underscores_correct(yytext))
|
||||
std::cerr << "An invalid underscore in the identifier:"
|
||||
<< yytext << std::endl;
|
||||
//yywarn(yylloc, "An invalid underscore in the identifier");
|
||||
//yywarn(yylloc, "An invalid underscore in the identifier");
|
||||
yylval.text = strdupnew(yytext);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -129,10 +128,10 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])*
|
|||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
\\([^\\]|\\\\)*\\ { /* extended identifiers */
|
||||
yylval.text = strdupnew(yytext);
|
||||
return IDENTIFIER;
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
{decimal_literal} {
|
||||
|
|
@ -159,9 +158,9 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])*
|
|||
|
||||
{based_literal} {
|
||||
if(!are_underscores_correct(yytext) || !is_based_correct(yytext))
|
||||
std::cerr << "An invalid form of based literal:"
|
||||
std::cerr << "An invalid form of based literal:"
|
||||
<< yytext << std::endl;
|
||||
|
||||
|
||||
if(strchr(yytext, '.'))
|
||||
{
|
||||
double val = make_double_from_based(yytext);
|
||||
|
|
@ -176,7 +175,7 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])*
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Compound symbols */
|
||||
"<=" { return LEQ; }
|
||||
">=" { return GEQ; }
|
||||
|
|
@ -187,10 +186,10 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])*
|
|||
"=>" { return ARROW; }
|
||||
"<<" { return DLT; }
|
||||
">>" { return DGT; }
|
||||
/*
|
||||
Here comes a list of symbols that are more then strange,
|
||||
/*
|
||||
Here comes a list of symbols that are more than strange,
|
||||
at least for the time being.
|
||||
|
||||
|
||||
"??" { return K_CC; }
|
||||
"?=" {}
|
||||
"?/=" {}
|
||||
|
|
@ -213,7 +212,7 @@ extern void yyparse_set_filepath(const char*path);
|
|||
* \return true is returned if underscores are placed
|
||||
* correctly according to specification
|
||||
*/
|
||||
static bool are_underscores_correct(char* text)
|
||||
static bool are_underscores_correct(char* text)
|
||||
{
|
||||
unsigned char underscore_allowed = 0;
|
||||
const char* cp;
|
||||
|
|
@ -257,12 +256,12 @@ static bool is_based_correct(char* text)
|
|||
++clean_base_ptr;
|
||||
}
|
||||
unsigned length = clean_base_ptr - clean_base;
|
||||
unsigned base;
|
||||
unsigned base;
|
||||
if(length > 2 || length == 0)
|
||||
return 0; //the base is too big or too small
|
||||
if(length == 2)
|
||||
{
|
||||
base = 10*(clean_base[0] - '0') + (clean_base[1] - '0');
|
||||
base = 10*(clean_base[0] - '0') + (clean_base[1] - '0');
|
||||
//the base exceeds 16 or equals 0
|
||||
if(base > 16 || base == 0)
|
||||
return 0;
|
||||
|
|
@ -275,7 +274,7 @@ static bool is_based_correct(char* text)
|
|||
}
|
||||
bool point = 0;
|
||||
set<char> allowed_chars;
|
||||
|
||||
|
||||
unsigned c;
|
||||
if(base <= 10) {
|
||||
for(c = 0; c < base; ++c)
|
||||
|
|
@ -291,7 +290,7 @@ static bool is_based_correct(char* text)
|
|||
//MANTISSA examination
|
||||
for(ptr = strchr(text, '#') + 1, length = 0; ptr != strrchr(text, '#'); ++ptr)
|
||||
{
|
||||
if(*ptr == '.')
|
||||
if(*ptr == '.')
|
||||
{
|
||||
//we found a dot and another one was already found
|
||||
if(point == 1)
|
||||
|
|
@ -310,7 +309,7 @@ static bool is_based_correct(char* text)
|
|||
}
|
||||
if(length == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
//EXPONENT examination
|
||||
if(strchr(text, '\0') - strrchr(text, '#') > 1) { //the number contains an exponent
|
||||
if(*(strrchr(text, '#') + 2) == '-')
|
||||
|
|
@ -322,7 +321,7 @@ static bool is_based_correct(char* text)
|
|||
if(!((*ptr >= '0' && *ptr <= '9') || (*ptr >= 'a' && *ptr <= 'f')))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -336,13 +335,13 @@ static bool is_based_correct(char* text)
|
|||
static char* escape_quot_and_dup(char* text)
|
||||
{
|
||||
char* newstr = new char[strlen(text)+1];
|
||||
|
||||
|
||||
unsigned old_idx, new_idx;
|
||||
for(new_idx = 0, old_idx = 0; old_idx < strlen(text); )
|
||||
for(new_idx = 0, old_idx = 0; old_idx < strlen(text); )
|
||||
{
|
||||
if(text[old_idx] == '"' && old_idx == 0)
|
||||
if(text[old_idx] == '"' && old_idx == 0)
|
||||
{ //the beginning of the literal
|
||||
++old_idx;
|
||||
++old_idx;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
|
@ -352,12 +351,12 @@ static char* escape_quot_and_dup(char* text)
|
|||
return newstr;
|
||||
}
|
||||
else
|
||||
if(text[old_idx] == '"' && text[old_idx+1] == '"')
|
||||
if(text[old_idx] == '"' && text[old_idx+1] == '"')
|
||||
{
|
||||
newstr[new_idx++] = '"';
|
||||
old_idx += 2; //jump across two chars
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
newstr[new_idx] = text[old_idx];
|
||||
++old_idx;
|
||||
|
|
@ -383,7 +382,7 @@ static char* escape_apostrophe_and_dup(char* text)
|
|||
}
|
||||
|
||||
/**
|
||||
* This function takes a floating point based number
|
||||
* This function takes a floating point based number
|
||||
* in form of a C-strings and converts it to a double.
|
||||
*
|
||||
* \return new double is returned
|
||||
|
|
@ -396,10 +395,10 @@ static double make_double_from_based(char* text)
|
|||
//put null byte in lieu of hashes
|
||||
*first_hash_ptr = '\0';
|
||||
*second_hash_ptr = '\0';
|
||||
|
||||
|
||||
//now lets deduce the base
|
||||
unsigned base = (unsigned)strtol(text, 0, 10) ;
|
||||
|
||||
|
||||
double mantissa = 0.0;
|
||||
char*ptr = first_hash_ptr + 1;
|
||||
for( ; ptr != second_hash_ptr ; ++ptr)
|
||||
|
|
@ -425,12 +424,12 @@ static double make_double_from_based(char* text)
|
|||
{
|
||||
return mantissa + fraction;
|
||||
}
|
||||
|
||||
|
||||
//now calculate the value of the exponent
|
||||
double exponent = 0.0;
|
||||
//leave 'e'/'E' and '+'
|
||||
ptr = *(second_hash_ptr + 2) == '+' ? second_hash_ptr + 3 : second_hash_ptr + 2;
|
||||
|
||||
ptr = *(second_hash_ptr + 2) == '+' ? second_hash_ptr + 3 : second_hash_ptr + 2;
|
||||
|
||||
for( ; *ptr != '\0'; ++ptr)
|
||||
{
|
||||
if(*ptr != '_')
|
||||
|
|
@ -439,13 +438,13 @@ static double make_double_from_based(char* text)
|
|||
}
|
||||
}
|
||||
return pow(mantissa + fraction, exponent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* This function takes a hexadecimal digit in form of
|
||||
* a char and returns its litteral value as short
|
||||
*/
|
||||
static unsigned short short_from_hex_char(char ch)
|
||||
static unsigned short short_from_hex_char(char ch)
|
||||
{
|
||||
if(ch >= '0' && ch <= '9')
|
||||
return ch - '0';
|
||||
|
|
@ -464,9 +463,9 @@ static int64_t make_long_from_based(char* text) {
|
|||
char* second_hash_ptr = strrchr(text, '#');
|
||||
char* end_ptr = strrchr(text, '\0');
|
||||
//now lets deduce the base
|
||||
*first_hash_ptr = '\0';
|
||||
*first_hash_ptr = '\0';
|
||||
unsigned base = (unsigned)strtol(text, 0, 10) ;
|
||||
|
||||
|
||||
char *ptr = first_hash_ptr + 1;
|
||||
int64_t mantissa = 0;
|
||||
for( ; ptr != second_hash_ptr ; ++ptr)
|
||||
|
|
@ -479,9 +478,9 @@ static int64_t make_long_from_based(char* text) {
|
|||
//if there is an exponent
|
||||
if(end_ptr - second_hash_ptr > 1)
|
||||
{
|
||||
int64_t exponent = 0L;
|
||||
|
||||
ptr = *(second_hash_ptr + 2) == '+' ? second_hash_ptr + 3 : second_hash_ptr + 2;
|
||||
int64_t exponent = 0L;
|
||||
|
||||
ptr = *(second_hash_ptr + 2) == '+' ? second_hash_ptr + 3 : second_hash_ptr + 2;
|
||||
for( ; *ptr != '\0'; ++ptr)
|
||||
{
|
||||
if(*ptr != '_')
|
||||
|
|
@ -511,3 +510,8 @@ void reset_lexor(FILE*fd, const char*path)
|
|||
|
||||
yyparse_set_filepath(path);
|
||||
}
|
||||
|
||||
int yywrap()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ nand, GN_KEYWORD_2008, K_nand
|
|||
new, GN_KEYWORD_2008, K_new
|
||||
next, GN_KEYWORD_2008, K_next
|
||||
nor, GN_KEYWORD_2008, K_nor
|
||||
not, GN_KEYWORD_2008, K_not
|
||||
not, GN_KEYWORD_2008, K_not
|
||||
null, GN_KEYWORD_2008, K_null
|
||||
of, GN_KEYWORD_2008, K_of
|
||||
on, GN_KEYWORD_2008, K_on
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ int parse_errors = 0;
|
|||
port_mode_t port_mode;
|
||||
|
||||
char*text;
|
||||
|
||||
std::list<perm_string>* name_list;
|
||||
|
||||
bool flag;
|
||||
|
|
@ -199,7 +200,7 @@ design_unit
|
|||
;
|
||||
|
||||
design_units
|
||||
: design_units design_unit
|
||||
: design_units design_unit
|
||||
| design_unit
|
||||
;
|
||||
|
||||
|
|
@ -225,7 +226,7 @@ entity_declaration
|
|||
if(tmp->get_name() != $7) {
|
||||
errormsg(@1, "Syntax error in entity clause. \n");
|
||||
}
|
||||
|
||||
|
||||
delete[]$2;
|
||||
delete[]$7;
|
||||
// Transfer the ports
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@ vhdlint::vhdlint(const char* text)
|
|||
value_ = 0L;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
char* new_text = new char[text_length + 1];
|
||||
|
||||
|
||||
const char* ptr;
|
||||
char* new_ptr;
|
||||
for(ptr = text, new_ptr = new_text; *ptr != 0; ++ptr)
|
||||
|
|
@ -65,7 +65,7 @@ vhdlint::vhdlint(const char* text)
|
|||
|
||||
istringstream str(new_text);
|
||||
delete[] new_text;
|
||||
|
||||
|
||||
//TODO: check if numbers greater than MAX_INT are handled correctly
|
||||
str >> value_;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@ class vhdlint
|
|||
explicit vhdlint(const char* text);
|
||||
explicit vhdlint(const int64_t& val);
|
||||
explicit vhdlint(const vhdlint& val);
|
||||
|
||||
|
||||
bool is_negative() const;
|
||||
bool is_positive() const;
|
||||
bool is_zero() const;
|
||||
|
||||
|
||||
int64_t as_long() const;
|
||||
//vhdlv get(const unsigned index) const;
|
||||
//void set(const unsigned index, const unsigned val);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ vhdlreal::vhdlreal(const vhdlreal& val) {
|
|||
vhdlreal::vhdlreal(const char* text) {
|
||||
assert(strlen(text) != 0);
|
||||
char* buffer = new char[strlen(text)+1];
|
||||
|
||||
|
||||
char* buf_ptr;
|
||||
for(buf_ptr = buffer; *text != 0; ++buf_ptr, ++text) {
|
||||
if(*text == '_')
|
||||
|
|
@ -47,7 +47,7 @@ vhdlreal::vhdlreal(const char* text) {
|
|||
*buf_ptr = *text;
|
||||
}
|
||||
*buf_ptr = '\0';
|
||||
|
||||
|
||||
value_ = strtod(buffer, NULL);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
*/
|
||||
class vhdlreal
|
||||
{
|
||||
public:
|
||||
public:
|
||||
friend std::ostream& operator<< (std::ostream&, const vhdlreal&);
|
||||
friend vhdlreal operator+ (const vhdlreal&, const vhdlreal&);
|
||||
friend vhdlreal operator- (const vhdlreal&, const vhdlreal&);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -36,7 +36,8 @@ int is_escaped_id(const char *name)
|
|||
for (lp=1; name[lp] != '\0'; lp++) {
|
||||
/* If this digit is not alpha-numeric or '_' we have
|
||||
* an escaped identifier. */
|
||||
if (!(isalnum((int)name[lp]) || name[lp] == '_')) {
|
||||
if (!(isalnum((int)name[lp]) ||
|
||||
name[lp] == '_') || name[lp] == '$') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __vpi_user_H
|
||||
#define __vpi_user_H
|
||||
/*
|
||||
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -373,6 +373,8 @@ typedef struct t_vpi_delay {
|
|||
# define _vpiDelaySelMinimum 1
|
||||
# define _vpiDelaySelTypical 2
|
||||
# define _vpiDelaySelMaximum 3
|
||||
/* used in vvp/vpi_priv.h 0x1000003 */
|
||||
/* used in vvp/vpi_priv.h 0x1000004 */
|
||||
|
||||
/* DELAY MODES */
|
||||
#define vpiNoDelay 1
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \
|
|||
vpip_to_dec.o vpip_format.o vvp_vpi.o
|
||||
|
||||
O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
|
||||
concat.o dff.o enum_type.o extend.o npmos.o part.o permaheap.o \
|
||||
reduce.o resolv.o \
|
||||
concat.o dff.o enum_type.o extend.o file_line.o npmos.o part.o \
|
||||
permaheap.o reduce.o resolv.o \
|
||||
sfunc.o stop.o symbols.o ufunc.o codes.o vthread.o schedule.o \
|
||||
statistics.o tables.o udp.o vvp_island.o vvp_net.o vvp_net_sig.o \
|
||||
event.o logic.o delay.o words.o island_tran.o $V
|
||||
|
|
|
|||
|
|
@ -874,7 +874,7 @@ of four possible values (0, 1, x and z) so two bits are needed to
|
|||
represent them. So the input of the functor is 8 bits, and the output
|
||||
2 bits. A complete lookup table for generating the 2-bit output from
|
||||
an 8-bit input is 512 bits. That can be packed into 64 bytes. This is
|
||||
small enough that the table should take less space then the code to
|
||||
small enough that the table should take less space than the code to
|
||||
implement the logic.
|
||||
|
||||
To implement the truth table, we need to assign 2-bit encodings for
|
||||
|
|
@ -1034,7 +1034,7 @@ becomes:
|
|||
|
||||
Notice the first parameter of the .functor is the type. The type
|
||||
includes a truth table that describes the output with a given
|
||||
input. If the gate is wider then four inputs, then cascade
|
||||
input. If the gate is wider than four inputs, then cascade
|
||||
functors. For example:
|
||||
|
||||
and gate (out, i1, i2, i3, i4, i5, i6, i7, i8);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -109,6 +109,8 @@ void codespace_delete(void)
|
|||
vpi_call_delete((cur+idx)->handle);
|
||||
} else if ((cur+idx)->opcode == &of_EXEC_UFUNC) {
|
||||
exec_ufunc_delete((cur+idx));
|
||||
} else if ((cur+idx)->opcode == &of_FILE_LINE) {
|
||||
delete((cur+idx)->handle);
|
||||
}
|
||||
if (count_opcodes == 0) break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __codes_H
|
||||
#define __codes_H
|
||||
/*
|
||||
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -94,6 +94,7 @@ extern bool of_EVCTL(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_EVCTLC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVCTLI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVCTLS(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FILE_LINE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_LINK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_WR(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -1709,6 +1709,23 @@ void compile_fork(char*label, struct symb_s dest, struct symb_s scope)
|
|||
compile_vpi_lookup(&code->handle, scope.text);
|
||||
}
|
||||
|
||||
void compile_file_line(char*label, long file_idx, long lineno,
|
||||
char*description)
|
||||
{
|
||||
if (label) compile_codelabel(label);
|
||||
|
||||
/* Create an instruction in the code space. */
|
||||
vvp_code_t code = codespace_allocate();
|
||||
code->opcode = &of_FILE_LINE;
|
||||
|
||||
/* Create a vpiHandle that contains the information. */
|
||||
code->handle = vpip_build_file_line(description, file_idx, lineno);
|
||||
assert(code->handle);
|
||||
|
||||
/* Done with the lexor-allocated name string. */
|
||||
delete[] description;
|
||||
}
|
||||
|
||||
void compile_vpi_call(char*label, char*name,
|
||||
bool func_as_task_err, bool func_as_task_warn,
|
||||
long file_idx, long lineno,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __compile_H
|
||||
#define __compile_H
|
||||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -404,6 +404,9 @@ typedef struct comp_operands_s*comp_operands_t;
|
|||
extern void compile_code(char*label, char*mnem, comp_operands_t opa);
|
||||
extern void compile_disable(char*label, struct symb_s symb);
|
||||
|
||||
extern void compile_file_line(char*label, long file_idx, long lineno,
|
||||
char*description);
|
||||
|
||||
extern void compile_vpi_call(char*label, char*name,
|
||||
bool func_as_task_err, bool func_as_task_warn,
|
||||
long file_idx, long lineno,
|
||||
|
|
@ -454,7 +457,7 @@ extern void compile_var_real(char*label, char*name,
|
|||
int msb, int lsb);
|
||||
|
||||
/*
|
||||
* The compile_net functio is called to create a .net vector with a
|
||||
* The compile_net function is called to create a .net vector with a
|
||||
* given name.
|
||||
*
|
||||
* The vpi_type_code argument of compile_net() is one of the vpi
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ class vvp_fun_event_or_aa : public vvp_fun_event_or, public automatic_hooks_s {
|
|||
};
|
||||
|
||||
/*
|
||||
* A named event is simpler then a vvp_fun_edge in that it triggers on
|
||||
* A named event is simpler than a vvp_fun_edge in that it triggers on
|
||||
* any input at all to port-0. The idea here is that behavioral code
|
||||
* can use a %set/v instruction to trigger the event.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
# include "compile.h"
|
||||
# include "vpi_priv.h"
|
||||
|
||||
struct __vpiFileLine {
|
||||
struct __vpiHandle base;
|
||||
const char *description;
|
||||
unsigned file_idx;
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
bool show_file_line = false;
|
||||
bool code_is_instrumented = false;
|
||||
|
||||
static int file_line_get(int type, vpiHandle ref)
|
||||
{
|
||||
struct __vpiFileLine*rfp = (struct __vpiFileLine*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code == _vpiFileLine);
|
||||
|
||||
switch (type) {
|
||||
case vpiLineNo:
|
||||
return rfp->lineno;
|
||||
default:
|
||||
return vpiUndefined;
|
||||
}
|
||||
}
|
||||
|
||||
static char *file_line_get_str(int type, vpiHandle ref)
|
||||
{
|
||||
struct __vpiFileLine*rfp = (struct __vpiFileLine*)ref;
|
||||
|
||||
assert(ref->vpi_type->type_code == _vpiFileLine);
|
||||
|
||||
switch (type) {
|
||||
case vpiFile:
|
||||
assert(rfp->file_idx < file_names.size());
|
||||
return simple_set_rbuf_str(file_names[rfp->file_idx]);
|
||||
case _vpiDescription:
|
||||
if (rfp->description) return simple_set_rbuf_str(rfp->description);
|
||||
else return simple_set_rbuf_str("Procedural tracing.");
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct __vpirt vpip_file_line_rt = {
|
||||
_vpiFileLine,
|
||||
file_line_get,
|
||||
file_line_get_str,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
vpiHandle vpip_build_file_line(char*description, long file_idx, long lineno)
|
||||
{
|
||||
struct __vpiFileLine*obj = new struct __vpiFileLine;
|
||||
|
||||
/* Turn on the diagnostic output when we find a %file_line. */
|
||||
show_file_line = true;
|
||||
code_is_instrumented = true;
|
||||
|
||||
obj->base.vpi_type = &vpip_file_line_rt;
|
||||
if (description) obj->description = vpip_name_string(description);
|
||||
else obj->description = 0;
|
||||
obj->file_idx = (unsigned) file_idx;
|
||||
obj->lineno = (unsigned) lineno;
|
||||
|
||||
return &obj->base;
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -204,13 +204,14 @@ static char* strdupnew(char const *str)
|
|||
kind of instruction this really is. The few exceptions (that have
|
||||
exceptional parameter requirements) are listed first. */
|
||||
|
||||
"%vpi_call" { return K_vpi_call; }
|
||||
"%vpi_call" { return K_vpi_call; }
|
||||
"%vpi_call/w" { return K_vpi_call_w; }
|
||||
"%vpi_call/i" { return K_vpi_call_i; }
|
||||
"%vpi_func" { return K_vpi_func; }
|
||||
"%vpi_func" { return K_vpi_func; }
|
||||
"%vpi_func/r" { return K_vpi_func_r; }
|
||||
"%disable" { return K_disable; }
|
||||
"%fork" { return K_fork; }
|
||||
"%disable" { return K_disable; }
|
||||
"%fork" { return K_fork; }
|
||||
"%file_line" { return K_file_line; }
|
||||
|
||||
/* Handle the specialized variable access functions. */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -385,6 +385,18 @@ that this information has been cleared. You can get an assert if
|
|||
this information is not managed correctly.
|
||||
|
||||
|
||||
* %file_line <file> <line> <description>
|
||||
|
||||
This command emits the provided file and line information along with
|
||||
the description when it is executed. The output is sent to stderr and
|
||||
the format of the output is:
|
||||
<file>:<line>: <description>
|
||||
<file> is the unsigned numeric file index.
|
||||
<line> is the unsigned line number.
|
||||
<description> is a string, if string is 0 then the following default
|
||||
message is used: "Procedural tracing.".
|
||||
|
||||
|
||||
* %force/v <label>, <bit>, <wid>
|
||||
|
||||
Force a constant value to the target variable. This is similar to %set
|
||||
|
|
|
|||
13
vvp/parse.y
13
vvp/parse.y
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -95,7 +95,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_vpi_func K_vpi_func_r
|
||||
%token K_disable K_fork
|
||||
%token K_ivl_version K_ivl_delay_selection
|
||||
%token K_vpi_module K_vpi_time_precision K_file_names
|
||||
%token K_vpi_module K_vpi_time_precision K_file_names K_file_line
|
||||
|
||||
%token <text> T_INSTR
|
||||
%token <text> T_LABEL
|
||||
|
|
@ -556,6 +556,15 @@ statement
|
|||
| T_LABEL ';'
|
||||
{ compile_codelabel($1); }
|
||||
|
||||
/* %file_line statements are instructions that have unusual operand
|
||||
requirements so are handled by their own rules. */
|
||||
| label_opt K_file_line T_NUMBER T_NUMBER T_STRING ';'
|
||||
{ compile_file_line($1, $3, $4, $5); }
|
||||
|
||||
| label_opt K_file_line T_NUMBER T_NUMBER T_NUMBER ';'
|
||||
{ assert($5 == 0);
|
||||
compile_file_line($1, $3, $4, 0); }
|
||||
|
||||
/* %vpi_call statements are instructions that have unusual operand
|
||||
requirements so are handled by their own rules. The %vpi_func
|
||||
statement is a variant of %vpi_call that includes a thread vector
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -1029,6 +1029,12 @@ void schedule_simulate(void)
|
|||
|
||||
if (!schedule_runnable) break;
|
||||
schedule_time += ctim->delay;
|
||||
/* When the design is being traced (we are emitting
|
||||
* file/line information) also print any time changes. */
|
||||
if (show_file_line) {
|
||||
cerr << "Advancing to simulation time: "
|
||||
<< schedule_time << endl;
|
||||
}
|
||||
ctim->delay = 0;
|
||||
|
||||
vpiNextSimTime();
|
||||
|
|
|
|||
34
vvp/stop.cc
34
vvp/stop.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2011 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -357,6 +357,36 @@ static void cmd_time(unsigned, char*[])
|
|||
printf("%lu ticks\n", ticks);
|
||||
}
|
||||
|
||||
static void cmd_trace(unsigned argc, char*argv[])
|
||||
{
|
||||
assert(argc);
|
||||
switch (argc) {
|
||||
case 1:
|
||||
show_file_line = true;
|
||||
break;
|
||||
default:
|
||||
printf("Only using the first argument to trace.\n");
|
||||
case 2:
|
||||
if ((strcmp(argv[1], "on") == 0) || (strcmp(argv[1], "1") == 0)) {
|
||||
show_file_line = true;
|
||||
} else show_file_line = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/* You can't trace a file if the compiler didn't insert the
|
||||
* %file_line opcodes. */
|
||||
if (!code_is_instrumented) {
|
||||
printf("The vvp input must be instrumented before tracing is "
|
||||
"available.\n");
|
||||
printf("Recompile with the -pfileline=1 flag to instrument "
|
||||
"the input.\n");
|
||||
show_file_line = false;
|
||||
} else {
|
||||
printf("Turning statement tracing %s.\n",
|
||||
show_file_line ? "on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_where(unsigned, char*[])
|
||||
{
|
||||
struct __vpiScope*cur = stop_current_scope;
|
||||
|
|
@ -412,6 +442,8 @@ static struct {
|
|||
"Single-step the scheduler for 1 event."},
|
||||
{ "time", &cmd_time,
|
||||
"Print the current simulation time."},
|
||||
{ "trace", &cmd_trace,
|
||||
"Control statement tracing (on/off) when the code is instrumented."},
|
||||
{ "where", &cmd_where,
|
||||
"Show current scope, and scope hierarchy stack."},
|
||||
{ 0, &cmd_unknown, 0}
|
||||
|
|
|
|||
|
|
@ -928,7 +928,7 @@ void vpip_put_value_event::run_run()
|
|||
case vpiStringVal:
|
||||
free(value.value.str);
|
||||
break;
|
||||
/* If these are every copied then free them too. */
|
||||
/* If these are ever copied then free them too. */
|
||||
case vpiTimeVal:
|
||||
case vpiVectorVal:
|
||||
case vpiStrengthVal:
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue