Merge branch 'master' into work4

Conflicts:
	vhdlpp/lexor.lex
	vhdlpp/parse.y
	vhdlpp/vhdlint.cc
This commit is contained in:
Stephen Williams 2011-03-14 17:34:57 -07:00
commit 9330b58a3a
104 changed files with 4837 additions and 3623 deletions

View File

@ -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

502
COPYING.lesser Normal file
View File

@ -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!

View File

@ -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 \

View File

@ -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;

View File

@ -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. */

View File

@ -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
View File

@ -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
View File

@ -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,

View File

@ -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

View File

@ -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];

View File

@ -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,

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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 "

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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.
*/

View File

@ -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

View File

@ -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;
}
/*

View File

@ -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;

View File

@ -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;

View File

@ -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_;
}

View File

@ -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;

View File

@ -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];
}

View File

@ -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
View File

@ -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);

View File

@ -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);

View File

@ -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
View File

@ -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

View File

@ -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;
}

View File

@ -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());

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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;
}

View File

@ -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
View File

@ -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;

View File

@ -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()

View File

@ -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*);

View File

@ -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)

View File

@ -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()));

View File

@ -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

View File

@ -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);

View File

@ -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());

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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_;

View File

@ -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));
}
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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);
}
}

View File

@ -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, ' ');

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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:

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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:

View File

@ -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));

View File

@ -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&);

View File

@ -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 \

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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_;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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&);

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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.
*/

93
vvp/file_line.cc Normal file
View File

@ -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;
}

View File

@ -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. */

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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}

View File

@ -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