pax_global_header 0000666 0000000 0000000 00000000064 13254235275 0014522 g ustar 00root root 0000000 0000000 52 comment=73232ebd0c03bb48b74764816ef1dbb06e3505db
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/ 0000775 0000000 0000000 00000000000 13254235275 0020563 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/.gitmodules 0000664 0000000 0000000 00000000201 13254235275 0022731 0 ustar 00root root 0000000 0000000 [submodule "hdl/ip_cores/general-cores"]
path = hdl/ip_cores/general-cores
url = git://ohwr.org/hdl-core-lib/general-cores.git
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/LICENSE 0000664 0000000 0000000 00000057646 13254235275 0021612 0 ustar 00root root 0000000 0000000 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
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/Manifest.py 0000664 0000000 0000000 00000000042 13254235275 0022677 0 ustar 00root root 0000000 0000000 modules = {"local" : ["hdl/rtl"]}
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/README 0000664 0000000 0000000 00000001443 13254235275 0021445 0 ustar 00root root 0000000 0000000 VME64x Core
===========
Using the core
--------------
There is an example in the svec repository. See svec/hdl/syn/vmecore_test
The design implements the core on a svec card, with a WB slave that implements
various features (an SRAM, a pattern area to check DMA, a simple timer to
check interrupts, a bus-error generator...).
There is a C program (in svec/software/vmecore_test) to test all these
features.
Running the testbench
---------------------
After having cloned the repository, simply do:
git submodule init
git submodule update
cd hdl/testbench/simple_tb/modelsim
hdlmake
make
sh run_all.sh
This is an automatic testbench with a yes/no status.
It runs the testbench several times with a different scenario value.
The last line should be: OK!
Tested with ModelSim SE-64 10.2a on linux.
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/doc/ 0000775 0000000 0000000 00000000000 13254235275 0021330 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/doc/Makefile 0000664 0000000 0000000 00000000357 13254235275 0022775 0 ustar 00root root 0000000 0000000 all: vme64x_core-ug.pdf
vme64x_core-ug.xml: vme64x_core-ug.txt
asciidoc -v -d book -b docbook vme64x_core-ug.txt
vme64x_core-ug.pdf: vme64x_core-ug.xml
a2x -f pdf vme64x_core-ug.xml
clean:
$(RM) vme64x_core-ug.xml vme64x_core-ug.pdf
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/doc/core.fig 0000664 0000000 0000000 00000002513 13254235275 0022750 0 ustar 00root root 0000000 0000000 #FIG 3.2 Produced by xfig version 3.2.5c
Landscape
Center
Metric
A4
100.00
Single
-2
1200 2
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2475 3375 9900 3375 9900 8100 2475 8100 2475 3375
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2250 4050 3375 4050 3375 7875 2250 7875 2250 4050
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
10125 4050 9000 4050 9000 7875 10125 7875 10125 4050
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 9
3600 4050 3600 7875 8775 7875 8775 5400 7650 5400 7650 6750
4275 6750 4275 4050 3600 4050
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4500 5850 6750 5850 6750 6525 4500 6525 4500 5850
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4500 4050 7200 4050 7200 4725 4500 4725 4500 4050
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4500 4950 7200 4950 7200 5625 4500 5625 4500 4950
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
7650 4050 8775 4050 8775 5175 7650 5175 7650 4050
4 0 0 50 -1 0 24 0.0000 4 270 2340 4950 3825 VME64xCore\001
4 0 0 50 -1 0 22 1.5708 4 240 1980 2925 6975 VME64x Bus\001
4 0 0 50 -1 0 22 1.5708 4 240 2115 9675 6750 Wishbone Bus\001
4 0 0 50 -1 0 22 0.0000 4 315 420 8100 4725 Irq\001
4 0 0 50 -1 0 22 0.0000 4 315 1710 4950 4500 cr/csr space\001
4 0 0 50 -1 0 22 0.0000 4 240 1635 4950 5400 func match\001
4 0 0 50 -1 0 22 0.0000 4 165 975 4950 6300 user cr\001
4 0 0 50 -1 0 22 0.0000 4 315 2340 4950 7425 vme_bus (FSM)\001
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/doc/core.svg 0000664 0000000 0000000 00000006577 13254235275 0023020 0 ustar 00root root 0000000 0000000
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/doc/review-2017-11-13/ 0000775 0000000 0000000 00000000000 13254235275 0023660 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/doc/review-2017-11-13/GD-vme64x-core-review.txt0000664 0000000 0000000 00000010625 13254235275 0030273 0 ustar 00root root 0000000 0000000 - top VME64x core entity is called "VME64xCore_Top" while
svec/hdl/top/vmecore_test/ instantiates vme64xcore_top. Make it the same (all
lower-case?) for easier grepping.
Done.
- check comments in all the files, some of them are not complete or out of date
OK.
- shall we have some reference design in the VME64x core repo? With necessary
constraints for the clock and putting registers in IOBs (like vme_irq_n_o in
svec vmecore_test)
Done. Points to the svec repo.
- vme64x_pack.vhd -> we usually call these things *_pkg.vhd
Done.
- from files headers remove _last changes_ and _TODO_ sections, anyway, they are
empty.
OK.
- i'd prefer to have signals without "s_" prefix, but this is part of a larger
coding style discussion.
In this design most of the signals are with "s_" prefix, but some are also
without (e.g. in VME_IRQ_Controller.vhd)
'Detail'.
- how about using t_vme64x_in and t_vme64x_out types inside the design to make
the core more compact and having only an std_logic wrapper for simulations?
Done. Good convention to be adopted.
- vme64x_pack.vhd and xvme64x_core_pkg.vhd should be merged into one package
Done.
------------------------
-- vme64x_pack.vhd --
------------------------
- line 44:
rename c_CLOCK_PERIOD to something like c_default_CLK_PERIOD
because as far as I've seen in the code, that's what it is, a default clk
period value assigned to g_CLOCK_PERIOD if user does not overwrite it.
Done. Default removed.
- line 55:
c_ADEM_M is a type not a constant, rename it to t_ADEM_M
Done.
- cleanup, remove types that are not used e.g. c_ADER_C_XAM or c_ADER_C_AM
Done. Commented as unused.
------------------------
-- VME64xCore_Top.vhd --
------------------------
- if g_WB_DATA_WIDTH must be 32-bit, then don't make it a generic, just use
everywhere c_DATA_WIDTH declared in the package
Done. Removed.
- the same for g_WB_ADDR_WIDTH (see also comment for VME_bus.vhd)
Done. Removed.
- prefix Wishbone ports with "wb_"
Done.
- if you make VME_bus.vhd with reset active low, then you don't need s_reset
signal anymore (see also comment in VME_bus.vhd).
Done.
------------------------
-- VME_bus.vhd --
------------------------
- prefix Wishbone ports with "wb_"
Done.
- either fix adr_o handling or remove g_WB_ADDR_WIDTH because setting anything
else than 32-bit to g_WB_ADDR_WIDTH will result in synthesis/simulation error
Done.
- why reset is active high (rst_i) and not active low like in all other modules?
Done.
- constant num_latchDS misses "c_" prefix
Done.
- line 431: 3 nested if-s. How about simplifying to:
if decode_done_i = '1' and decode_sel_i = '1' and module_enable_i = '1'then
(...)
elsif decode_done_i = '1' then
s_mainFSMstate <= WAIT_END;
else
s_mainFSMstate <= DECODE_ACCESS;
end if;
'As you like'.
- line 461:
should you check if s_DS_latch_count >0 before decrementing it by 1?
if for whatever reason you stay longer in DECODE_ACCESS waiting for
decode_done_i='1' you might end up going to WAIT_FOR_DS when your counter is
already 0, then after your decrement your counter rolls over
Done.
--------------------------
-- VME_CR_CSR_Space.vhd --
--------------------------
- line 323:
can use xor_reduce(vme_ga_i) from std_logic_misc instead of manually xoring
all the bits
No, because std_logic_misc is not standard.
--------------------------
-- VME_Funct_Match.vhd --
--------------------------
- line 94:
That's a weird way of describing registers in the process (at least to me).
Instead of clearing the registers at every risinge_edge, and having null in
rst_n_i='0', please clear the registers when rst_n_i ='0' and add another
"else" if you want to clear them every time decode_start_i='0'.
Done.
- line 133:
What's this construction??:
mask(c_ADEM_M) := g_ADEM(s_function_sel)(c_ADEM_M);
where c_ADEM_M is a subtype is integer range 31 downto 8;
Covered.
----------------------------
-- VME_IRQ_Controller.vhd --
----------------------------
- reset_n_i, we always name it rst_n_i
Done.
- line 170:
very very tiny thing, retry_count can be cleared always when we're in
WAIT_IRQ (not only inside the _if_). This simplifies an already simple fsm.
'Tiny'.
----------------------------
-- simulation --
----------------------------
- general-cores submodule in wrong location. Move it from hdl/sim to
ip_cores/general-cores like we have for all the other repos.
Done. Cf Maciej.
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/doc/review-2017-11-13/ML-vme64x-review.txt 0000664 0000000 0000000 00000036105 13254235275 0027364 0 ustar 00root root 0000000 0000000 Review of VME64x core, Maciej Lipinski / 2017-11-13
Note:
- line numbers are relative to branch tgingold-dev. Lines are indicated by L:
- Some changes suggested by me are committed to branch ml-vme64x_review
--------------------------------------------------------------------------------
General remarks (I started by trying to simulate the core, so some remarks
about simulatin will come first):
0.1. In principle, if simulation is provided in a project, our (non-written)
convention to get the simulation running (without reading any info) would
be to do the following:
git clone
git submodule init
git submodule update
cd hdl/testbench
hdlmake
make
do run.do
this is not the case and there is no README that is helpful in discovering
how to make the simulation. Moreover, the existing README in the main
folder is out-of-date.
I see several improvements that are spread among several points below.
Done: let's follow this convention, with a README.
0.2. I would recommend to follow our folder convention (which used to be on
ohwr.org and which is now gone, probably due to migration, so I copy+paste
it at the end of this file). Using this convention would require the
following changes:
a) change /documents to /doc
Done.
b) change hdl/sim to hdl/testbench
Done.
c) keep vme64x_bfm in hdl/sim/vme64x_bfm if this is a
model of the vme64x (I do not know because it is undocumented)
Done.
0.3. the arrangement of simple_tb is confusing: first I thought that the folder
"modelsim" contains some modelsim-specific stuff. Again, how should I know
if there is no description/documentation/README. I'd recommend to do one
of the following:
a) move content from hdl/sim/simple_tb/modelsim/ to hdl/sim/simple_tb
(preferred if there are no plans to add simulation for other tools)
b) add README explaining this structure
Done: Add a README.
0.4. hdl/sim/simple_tb/modelsim/run_all.sh is not working [committed fix]
Done (merged).
0.5. It would be extremely useful to have some waveforms when running simulation.
I recommend doing one of the following:
a) modify run_all.sh to show the run simulations in waveform
b) add run.do script that runs one of the testbench cases [committed]
It is very helpful to the developer to push a wave.do with most important
signals. Ideally, the documentation provided to the user would match the
waveform so that when a developer runs the simulation, he can easily map
the output to the documentation.
Done: your run.do file was cherry-picked.
0.6. Add general-cores as submodule in /hdl/ip_cores [committed]
even if vme64x is never used standalone and general-cores are used in this
project only when running simulation, I would still include it as submodule
in ip_cores for a number of reasons:
a) when someone takes the core to us in his/her project, it is useful to
know which ip_cores and which version he/she needs
b) to make the simulation easier to to run
c) it seems to be a general policy
Done.
0.7. README in the main directory is completely out of date !
Done.
0.8. /documention folder:
- the notes from the 2012 review should stay,
Still in the repo.
- a new folder for the current review should be added.
Done.
- I would guess that some of the removed documents will be replaced with
updated versions. If this is not the case, it seems to me that the
currently provided documentation (the one reminding in the folder) is
NOT sufficient. At least, the vme64x_user_manual should be revived.
Moreover, the documentation in the project files seems to be out-of-date.
OK.
0.9. consider refactoring as follows:
(see https://www.ohwr.org/attachments/554/VHDLcoding.pdf)
- the convention of prefix s_ for signals is generally avoided, remove s_
- the convention of using the suffix _a for asynchronous (input) signals is
useful and used, add
0.10. packages:
- I do not understand why you need two separate packages for the
VME64xCore_Top and its wrapper xvme64x_core. I would recommend to
merge vme64x_pack.vhd and xvme64x_core_pkg.vhd into one file/pacakge
Done.
- a "private" package seems like a good idea and something that is used in
other projects. I would recommend to add vme64x_core_priv_pkg.vhd. Thanks
to this, you will be able to "use" this package and import the modules
from it, rather than having to call directly work.module
(as suggested in a latter comment).
I don't see the point of adding extra code.
0.11. the naming of the files in hdl/rtl is very chaotic:
- Ideally, and by the convention used in other projects, the name of a
wrapper differs from the name of the module it wrapps only by the suffix
"x", e.g.: wr_core.vhd and xwr_core.vhd, wrsw_rtu.vhd and xwrsw_rtu.vhd.
I'd recommend to follow this convention
Done.
- the capitalization and using (or not using) of "_" is very inconsistent,
please fix it.
Done.
0.12. In the description of all files, there exists section "dependencies", It
does not seem to be appropriately filled in. Remove it from all files or
fill in appropriately.I recommend the former.
Done: Removed.
0.13. git blame shows that there is not much left from the original code of
Pablo and Davide, add the other contributors as authors to appropriate
files (possibly all)
Done (Authors removed).
0.14. The descriptions in the files (which is currently the only documentation)
is written in poor English that is hard to understand. It seems to be
out-of-date. It should be thoroughly reviewed. In comments to particular
files I point out unclear text. I also included some corrections in
commits
Updated.
--------------------------------------------------------------------------------
xvme64x_core_pkg.vhd and vme64x_pack.vhd:
--------------------------------------------------------------------------------
1.1 rename both, merge packages, see 0.11
Done.
--------------------------------------------------------------------------------
VME64xCore_Top.vhd
--------------------------------------------------------------------------------
2.1 [L:14-78]the description is written badly. I improved fragments in which I
knew what author wanted to say. The fragments that need to be explained
better are listed below:
a) input or output
-- The Input signals from the WB bus aren't registered indeed the WB is a
-- synchronous protocol and some registers in the WB side will introduce a
-- delay that make impossible reproduce the WB PIPELINED protocol.
TBC: in the UG.
b) why do you say about FIFO if it is not implemented?????
-- The WB protocol is more faster than the VME protocol so to make independent
-- the two protocols a FIFO memory can be introduced.
-- The FIFO is necessary only during 2eSST access mode.
-- During the block transfer without FIFO the VME_bus accesses directly the Wb
-- bus in Single pipelined read/write mode. If this is the only Wb master this
-- solution is better than the solution with FIFO.
-- In this base version of the core the FIFO is not implemented indeed the 2e
-- access modes aren't supported yet.
Done (Removed).
c) could you elaborate on this:
-- To access the CR/CSR space: AM = 0x2f --> this is A24 addressing type,
-- SINGLE transfer type. Base Address = Slot Number.
In the UG.
2.2 [L:101]the document says "-- last changes: see log." -> what log??? you mean
git? (it is similar in many files)
Log removed.
2.3 [L:367]use new private library for internal components, do not refer directly
to "work.VME_Funct_Match" etc
Why ?
No components.
2.4 [L:367-397] There is a dedicated module that is used in many projects for
synchronizing input asynchronous signals. It seems to include the same
functionality as the module used here gc_sync_register. My suggestion is
to use the same module as the other projects and think about removing
gc_sync_register from general cores.
Less warnings than gc_sync_ffs.
--------------------------------------------------------------------------------
VME_bus.vhd
--------------------------------------------------------------------------------
3.1 Again, the description is poorly written, i.e.:
a) in the description below [L: 34-35], do you mean the "MAIN FSM"
component? you should add in the text a name corresponding to the drawing:
-- The Access decode component decodes the address to check if the board is
-- the responding Slave. This component is of fundamental importance, indeed
-- only one Slave can answer to the Master!
Removed.
b) in the top file, it is written that WR Pipelined is not possible, here
you say it is, I do not understand
-- In the right side you can see the WB Master who implements the Wb Pipelined
-- single read/write protocol.
Removed.
c) I do not understand this:
-- [...]; only one FPGA at time can
-- carry the vme64x core or other similar VME slave core.
Removed.
3.2 the description of behavior concerning VME_AS_n_i is inconsistent with
the code [L:304 and 355]. In particular, the description says about
acting upon rising/falling edge, while the condition is not detecting edge.
It seems a particularly important difference in L:355 where the FSM will be
re-entered when VME_AS_n_i is kept LOW all the time. I do not know which
behavior is correct (possibly, the description is wrong and the
implementation OK)
Done.
3.3 [L:497] the input signal VME_DS_n_i is already synchronized with the
clock domain. There should be no metastability problem. And if there was
metastability problem, such a metastability would affect also VME_IACKIN_n_i
and VME_IACK_n_i that go through the same synchronization chain and are
used directly in the FSM. I would remove the comment.
Explained: DS is 2 signals.
--------------------------------------------------------------------------------
VME_Funct_Match:
--------------------------------------------------------------------------------
4.1 [L: 13] missing description, at least one sentence, please :)
Done.
4.2 [L:94-114]: the code optimization in this process deteriorates code
readability. I would recommend to rewrite the code a bit to make it clear
what happens,i.e.:
process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' or decode_start_i = '0' then
s_function_sel <= 0;
s_function_sel_valid <= '0';
s_decode_start_1 <= '0';
elsif decode_start_i = '1' then
s_decode_start_1 <= '1';
for i in 0 to 7 loop
if s_function(i) = '1' then
s_function_sel <= i;
s_function_sel_valid <= s_ader_am_valid(i);
exit;
end if;
end loop;
end if;
end if;
end process;
Done.
--------------------------------------------------------------------------------
VME_IRQ_Controller.vhd
--------------------------------------------------------------------------------
5.1 The description is not only poorly written but also misleading. I cannot find
in the VHDL code the FSM that is described, i.e.:
a) I really do not understand this [L:24-31]
-- 4) When detects VME_IACKIN_n_i = '0' and the Interrupt Handler initiates
-- the Interrupt cycle by asserting AS,the Interrupt Controller check if it
-- is the responding interrupter. Indeed before responding to an interrupt
-- acknowledge cycle the interrupter shall have an interrupt request
-- pending, shall check if the level of that request match the level
-- indicated on the address lines A1, A2 and A3,the data transfer width
-- during the interrupt acknowledge cycle should be equal or greater than
-- the size the it can respond with, and it shall receive a falling edge on
-- its IACKIN*.
b) I do not understand this [L:37-38]
-- [...], it should pass a
-- falling edge on down the daisy-chain so other interrupters can respond.
c) I do not understand this [L:59-61]
-- The interrupter wait the IACKIN falling edge in the IRQ state, so if the
-- interrupter don't have interrupt pending for sure it will not respond
-- because it is in IDLE.
Done. Doc in UG.
5.2 [L:156-158] I do not understand the second part of this sentence
-- Interrupts are automatically masked for g_RETRY_TIMEOUT (i.e. 1 ms) once
-- they are acknowledge by the interrupt handler until they are deasserted
-- by the interrupter.
TODO: rephrase.
5.3 [L:159-225] It seems to me that these two process should be a single FSM
Works both ways.
5.4 [L:190] either remove "fsm" from the process name, or make it a real FSM.
Done.
--------------------------------------------------------------------------------
VME_User_CSR.vhd
--------------------------------------------------------------------------------
6.1 The information in this description should be also in the top module
and/or in any other documentation that will be created. A developer who
takes a top module should not be forced to go here to read this info
Doc in UG.
--------------------------------------------------------------------------------
folder convention that used to be and should be on ohwr.org. we agreed on this
convention ~year ago during WR-BTrain review
--------------------------------------------------------------------------------
MyProj
|
|-circuit_board
|-doc
|-hdl
| |-ip_cores
| | |-wr-cores (submodule)
| | |-general-cores (submodule)
| |
| |-platform
| | |-Xilinx
| | |-Altera
| |
| |-rtl
| | |-
| | |-moduleX
| | |-moduleY
| | |-wb_desc_file_y.wb
| | |-wb_vhdl_file_y.vhd
| | |-wb_vhld_file_y_pkg.vhd
| | |-moduleZ
| | |-wb_desc_file_x.wb
| | |-wb_vhdl_file_x.vhd
| | |-wb_vhld_file_x_pkg.vhd
| |
| |-syn
| | |-myStuff
| | |-Manifest.py
| | |-top_z.xise
| |
| |
| |-testbench
| | |-include
| | | |-regs
| | | | |-wb_vhdl_file_x.vh
| | | | |-wb_vhdl_file_y.vh0
| | | |-model_x
| | | |-model_y
| | |-testMyStuff
| | | |-myStuff.svh
| | |-testModuleOfMyStuff
| | | |-testModule.svh
| |-top
| | |-svec
| | |-Manifest.py
| | |-svec_top.vhd
| | |-svec_top.ucf
| | |-myBoard
|
|-software
| |-FPGA
| |-embedded
| |-host
|-mechanics
reference:
http://www.ohwr.org/projects/fmc-delay-1ns-8cha/repository
dlamprid-vme64x_review.org 0000664 0000000 0000000 00000003451 13254235275 0030621 0 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/doc/review-2017-11-13 * General notes
- pull dlamprid-vme64x_review for both the core and the SVEC demo (vmecore_test)
+ adjust/merge as you see fit
Done
- [Update]/[Delete] top-level README.txt?
Done
- [Update] HDL headers
OK.
- [Update]/[Delete]/[Move to user manual] header comments with technical explanations?
OK.
- Good opportunity to rename files, entities and instances. eg:
+ pack or pkg?
_pkg (same name as the design unit name).
+ capital or small case file names?
The same case, lower case.
+ ...
Done.
- does not strictly follow proposed folder structure
See Maciej comment
* VME64x core
- get rid of SVEC_ID, CERN_ID etc from package and default generic values
Done. OK for default generic
- what happens if the c_CLOCK_PERIOD is wrong? maybe it's better to get rid of it, set g_CLOCK_PERIOD by default to zero and assert that it is set to something else by user
Done. OK.
- shal we name/label all processes?
NO, but...
** VME64xCore_top.vhd
- Add generic/constant for number of supported functions and use it to limit size of ader/adem
arrays etc, in order to reduce number of warnings in ISE (from ~450 to ~50)
Done.
- gc_sync_register: does it even make sense? Slide #95 of NASA radiation tolerant design presentation:
https://indico.cern.ch/event/663761/contributions/2710422/attachments/1537821/2410163/Berg_SynchronousDesign_2017.pdf
No problem, discussion about width postponed.
*** VME_CR_CSR_Space.vhd
- delete unused port vme_sysfail_ena_o?
Done.
* Simulation
- how am I supposed to run it? A README would help
Done.
- why open the GUI at the end of make?
Done.
- why keep around VME BFM if you are not using it? Why the SVEC-specific file in the VME BFM?
Removed. To be restored.
- why not (also) GHDL if Modelsim is not necessary?
Shouldn't be hard, excercise let to the reader.
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/doc/vme64x_core-ug.txt 0000664 0000000 0000000 00000053134 13254235275 0024651 0 ustar 00root root 0000000 0000000 VME64x to WB core User Guide
============================
:Author: Tristan Gingold
:Date: 2017-12-14
:Revision: 2.0
Introduction
------------
This core implements a VME64x slave - WB master bridge.
The design can be downloaded from https://www.ohwr.org/projects/vme64x-core
The vme64x core conforms to the standards defined by ANSI/VITA VME64 <<1>>
and VME64x <<2>>. In particular this core is provided with the "plug and
play" capability. It means that in the vme64x core you can find a
CR/CSR space whose base address is set automatically with the
geographical address lines and does not need to be set by jumpers or
switches on the board. Manual configuration is error prone and is thus
avoided. Software must map the module memory in the address space by
writing the CSR space.
The core supports SINGLE, BLT (D32), MBLT (D64) transfers in A16, A24,
and A32 address modes and D08 (OE), D16, D32 data transfers. The core
can be configured via the CR/CSR configuration space. A ROACK type IRQ
controller with one interrupt input and a programmable interrupt level
and Status/ID register are provided optionally and can be enabled at
instantiation.
Since the vme64x core acts as a Wishbone (WB) master in the WB side,
the WB pipelined single read/write transfer is provided by the
core. This functionality conforms the Wishbone B4 standard <<3>>.
.Block schema
image::core.svg[scaledwidth="70%"]
Features
--------
VME interface
~~~~~~~~~~~~~
This section lists which VME features are supported and which are not
supported by the core.
Supported:
^^^^^^^^^^
* D08(EO), D16, D32
* Addressing mode: A16, A24, A32
* BLT, MBLT
* D08(O), I(7-1), ROAK interrupts
* CR/CSR space with extensions from VME64x
* Geographic Address (GA), dynamic configuration (ader).
Not supported:
^^^^^^^^^^^^^^
* 2eVME
* 2eSST
* Dynamic size (DFSR, DFS)
* Fixed address (FAF)
* Extra Function Mask (EFM)
* XAM (no 2e)
* A40, A64
* MD32 (multiplexed data cycle, only for A40)
* LCK (bus lock)
* UAT (unaligned accesses)
* RMW cycles (but should work)
* ADO, ADOH (address only cycle)
* D08, D16 for BLT
* RETRY (cf rule 2.91 - incompatibility with WB)
Deviations
^^^^^^^^^^
* Not compatible with non-VME64x crates (doesn't support jumpers to
set the GA).
* The reset bit in the Bit Set Register is automatically cleared at the
next access.
* Automatically repeat interrupts every 1 ms if the source is always
active.
WB interface
~~~~~~~~~~~~
This section corresponds to the datasheet required by the WB
specification <<3>>.
1. Compliant to Wishbone B4 specifications
2. Slave
3. Signals name follows the specification
4. err_i is forwarded to VME as BERR*
5. rty_i is not supported
6. no TAGs
7. Port size is 32 bit
8. Port granularity is 8 bit
9. Maximum operand size is 8 bit (TBC)
10. Data transfer ordering is BIG ENDIAN
11. Sequence of data transfer is defined by the VME side
12. No CLK_I signal, clock is provided separately.
* Non pipeline behaviour (but compatible with pipeline). The core
doesn't take any advantage of the pipeline behaviour, as the WB bus is
much faster than the VME bus.
[[crcsr-space]]
CR/CSR space
~~~~~~~~~~~~
To provide a “plug and play” capability, CR/CSR space is implemented
as defined by ANSI/VITA Standards for VME64 Extensions.
A dedicated “Configuration ROM / Control & Status Register” (CR/CSR)
address space is provided by the core. It consists of ROM and RAM
regions with a set of well-defined registers. It is addressed with the
address modifier 0x2F in the A24 address space.
Every VME module occupies a 512 kB page in this address space. The
location of this page in the A24 space is defined by geographical
address lines on the backplane: each slot is provided with a unique
geographical five bit address at the J1 connector (row d). From these
bits A23...A19 of the CR/CSR page are derived.
If the geographical address is not correct (GA parity bit does not
match), the base address is set to 0x00, which indicates a faulty
condition. An odd parity is used.
If the board is plugged into an old crate that doesn't provide the GA
lines, the CR/CSR space cannot be accessed and therefore the core
remains
disabled.
The CR/CSR space can be accessed with the data width D08(EO), D16
byte(2-3) and D32. Please note that in compliance with the CR/CSR
definition, only every fourth location in the CR/CSR space is used. If
the master tries to write another location the write will not take
effect and if the master reads the byte(0) or byte(1) or byte(2)
locations the value returned is 0.
As you can see in the table below, not all this space of memory is
defined yet, and the designer can add additional CR and CSR
spaces called User Csr and User CR which are not implemented in the
vme64x core.
The location of the User CR and User CSR regions as well as the CRAM
region are programmable. For each of these, six bytes defining the
start and the end address (with respect to the start of the
configuration space) are reserved in the CR region. Designers are free
to use these regions for module specific purposes.
By default the size of the CRAM space is 0, which means it is disabled
and doesn't use any resources. User can define the address range of
CRAM in order to generate a programmable area.
All the registers in the CSR space have been implemented as defined by
the VME64 Extensions.
.CSR Address Space
[cols=",,",options="header",]
|=====================================================
| Start Address | End Address | Content
| 0x7ff60 | 0x7ffff | CSR (Control Status Registers)
| 0x7fc00 | 0x7ff5f | Reserved for CSR
| BEG_USER_CSR | END_USER_CSR | User defined CSR (option)
| BEG_CRAM | END_CRAM | User defined CRAM (option)
| BEG_USER_CR | END_USER_CR | User defined CR (option)
| 0x00000 | 0x00fff | CR (Configuration ROM)
|=====================================================
In addition to the standard registers in the CSR space and for
compatibility with existing drivers for previous version of the core,
the VME64x defines by default a user CSR space (within the CSR space
reserved by the VME64x standard) with the following registers:
.Default User CSR Space
[cols=",,",options="header",]
|=============================
|Address |Content |Reset value
|0x7ff5f |IRQ vector |0x00
|0x7ff5b |IRQ level |0x00
|=============================
[[interrupt-controller]]
Interrupt controller
~~~~~~~~~~~~~~~~~~~~
The interrupt controller implemented is a ROAK (Release On
Acknowledge) type controller. It means that the Interrupter releases
the interrupt request lines when it acknowledges the interrupt cycle.
Upon synchronously detecting a rising edge on the interrupt request
signal input on the WB bus, the VME64x core drives the IRQ request
line on the VME bus low thus issuing an interrupt request. The VME
master acknowledges the interrupt in the form of an IACK cycle. During
the IACK cycle the vme64x core sends the IRQ_Vector to the
master. After the interrupt is acknowledged, the VME IRQ line is
released.
There are seven VME IRQ lines but only one interrupt request
input. For the purpose of configuring which of the seven IRQ lines the
VME64x core will drive (in response to a rising edge on the IRQ
input), an IRQ Level register is available in the user CSR
space. The value of this register corresponds to the number of the IRQ
line on the VME bus that is to be used (note that on the VME master
side priorities are taken into account, IRQ7 having the highest
priority and IRQ1 the lowest). If the IRQ level register is set to
0x00, interrupts are disabled. In the default power-up and reset
configuration the interrupts are disabled.
There is a non-standard mechanism to retrigger unhandled interrupts.
Once an interrupt is asserted by the WB slave, the interrupt is marked
as pending and the interrupt request that it is relayed on the VME
bus.
The OS and the driver has to acknowledge the interrupt and to act on
the
hardware so that the WB slave doesn't request anymore OS attention.
If the OS acknowledge the interrupt but doesn't acknowledge the request,
the
VME64x Core will relay again the interrupt on the VME bus after 1ms.
[[vme64x-core-instantiation]]
VME64x Core Instantiation
-------------------------
There are two top-level entities:
* The `xvme64x_core` that is the main top-level entity. It uses
records
for the `g_DECODER` generic, VME and WB buses in order to simplify the
connections.
* The `vme64x_core` that is a wrapper of `xvme64x_core` which allows
interfacing with verilog code.
[[generics]]
Generics
~~~~~~~~
Generic `g_CLOCK_PERIOD` defines the clock priod in ns. This generic
must be set by the user and is used for synchronization of the VME DS
signal.
Generic `g_DECODE_AM` enables/disables the AM field of ADER when
decoding address. When it is set to false, behavior of this core is
consistent with its previous versions. In particlular, when false, the
AM field of ADER is not used when decoding address, so the core will
recognize any access allowed by the corresponding AMCAP. New designs
should set this generic to true.
Generic `g_USER_CSR_EXT` enables/disables user-defined CSR. The
interface with the user CSR is a very simple synchronous SRAM (signals
`user_csr_addr_o`, `user_csr_data_i`, `user_csr_data_o` and
`user_csr_we_o`). In addition, if user-defined CSR is enabled, the
input port `irq_level_i` and `irq_vector_i` are used by the interrupt
controller to define the irq level and vector (otherwise they are read
from the default user CSR registers).
Generic `g_WB_GRANULARITY` specifies the address granularity of the
wishbone bus. The value is one of:
* `WORD`: addresses represent words, so VME address 4, 5, 6 and 7 are
translated to WB address 1.
* `BYTE`: addresses represents bytes, so VME addresses 4, 5, 6 and 7 are
translated to WB address 4. The two LSB of WB address are always 0.
The other generics define values in the CSR. The package `vme64x_pkg`
defines default constants for these values, see the VME64x
specification for details about these values:
* `g_MANUFACTURER_ID` provides the manufacturer ID,
* `g_BOARD_ID` provides the board ID,
* `g_REVISION_ID` provides the revision ID,
* `g_PROGRAM_ID` provides the type of code in CR,
* `g_ASCII_PTR` provides the pointer to the user defined ASCII string in
CR,
* `g_BEG_USER_CR` and `g_END_USER_CR` provides the range of the user
defined CR
area. If the range is not null, ports `user_cr_addr_o` and
`user_cr_data_i`
must be connected to a ROM.
* `g_BEG_CRAM` and `g_END_CRAM` provide the range of user CRAM. If the
range is
not null, the core instantiates an SRAM.
* `g_BEG_USER_CSR` and `g_END_USER_CSR` provide the range of the user
defined
CSR. See above the description of `g_USER_CSR_EXT`.
* `g_BEG_SN` and `g_END_SN` provides the area in CR of the serial
number.
* `g_DECODER` describes the 8 function decoder. Each decoder is
described by
the following bits (see VME64x specification for details):
* `adem` bits 8 to 31: address mask
* `adem` bits 0 to 7: must be set to 0
* `amcap`: address modifier supported by the decoder. Only bits 0x08
to
0x0f and 0x38 to 0x3f can be set to 1.
* `dawpr`: data access width (ignored by the decoder).
Note that setting `adem` to 0 disable the decoder. If disabled
decoders,
they don't use any hardware resources.
[[ports]]
Ports
~~~~~
* `clk_i` is the clock signal, and the clock of the WB bus. Note that
the `g_CLOCK_PERIOD` generic must be set according to the `clk_i`
frequency to get correct timing for the VME `DS` signals. The VME `DTACK`
and `BERR` signals are supposed to be released at most 30ns after `DS`
is released; as the design needs 4 closk to release them (due to
synchronizer), this means the minimal frequency is supposed to be 133Mhz.
In practice, VME masters are much more tolerant.
* `rst_n_i` is the reset signal. It could be considered as a power-on
reset and is synchronous.
* `rst_n_o` is the reset signal to the wishbone core. It is asserted in
case of reset on the VME bus, or if the module reset bit is set in the CSR,
or if the `rst_n_i` signal is asserted.
* `vme_i` and `vme_o` are signals for the VME bus. Refer to the VME64
standard for details.
* `wb_i` and `wb_o` are the signals for the WB bus. Refer to the WB
specification for details. Note that the WB `rty` (retry) signal cannot
be used, as the VME BLT transactions can only be retried during the
address phase and this restriction is not exposed to the WB side. The WB err
signal is forwarded to the VME bus as BERR. The address on the WB bus
corresponds to the lower bits of the address on the VME bus (bits used to
decode the address are cleared on the WB bus).
* `irq_ack_o` signal is asserted during one cycle when the VME64x Core
acknowledge the interrupt on the VME bus. This signal could be used by
the slave interrupt controller.
The following signals are used only when the `g_USER_CSR_EXT` generic
is set to true:
* `irq_level_i` defines which VME IRQ signal is asserted by the VME64x
Core to send an interrupt to the VME bus. If set to 0, interrupts are never
sent. The level corresponds to the interrupt priority on the VME bus, 7 is
the highest priority and 1 the lowest. The value shouldn't change while
an interrupt is pending.
* `irq_vector_i` is the vector sent on the VME bus by the core during
an acknowledge cycle.
* `user_csr_addr_o`, `user_csr_data_i`, `user_csr_data_o`, `user_csr_we_o`
define an interface to an external SRAM containing the user CSR values.
For read cycles, the data value must be stable on the next cycle.
The following signals are used when a user CR area is defined (i.e.
the range defined by `g_BEG_USER_CR` and `g_END_USER_CR` is not null):
* `user_cr_addr_o`, `user_cr_data_i` define an interface to an external
ROM containing the user CR values. Data must be stable on the next cycle.
Note that the `vme` ports are designed to be connected to VME bus
transceivers like SN74VMEH2250. In the particular case of the CERN
SVEC card, the signals `berr` and `irq` are inverted by the
transceivers, so a `not` gate must be inserted in the FPGA. You can
refer to the `svec_vmecore_test_top.vhd` file in the svec repository
(https://www.ohwr.org/projects/svec) for an example.
Programming the VME64x Core
---------------------------
After power-up or reset, the VME core is disabled (as the
`module_enable` bit is cleared) and therefore only the CS/CSR space
can be accessed. Software must then first map the module memory in the
address space by setting the Address Decoder Compare (ADER)
registers in CSR, which, together with Address Decoder Mask (ADEM)
registers in the CR relocate the module memory to the desired address
range. ADER for each function must also contains the AM code to
which it responds. After the module has been placed in the desired
address space, it can be enabled by writing 0x10 (`module_enable`) to
the Bit Set Register in the CSR.
If the master needs to access to the slave using different address
space (e.g. both A32 and A24), or different transaction (e.g. both
single and BLT), several function decoders must be used.
The base address is of the CR/CSR space is set by the geographical
lines. If the core is used in an old VME system without GA lines, the
core reads GA as "11111" which is invalid. As a consequence, the CS/CSR
is not accessible and the card cannot be enabled.
It is possible to reset the card in software by setting the `reset`
bit in the Bit Set Register. Contrary to the VME64 specification (and
for backward compatibility with drivers and previous versions of the
core), this bit is automatically cleared during the next CSR write
access.
.Pseudo code
. Determine the geographical address of the card (e.g. bus scan)
. Optionally reset the card (through the Bit Set and Clear registers)
. Set ADERs
. Enable the card: Write 0x10 to the Bit Set Register
[[performance]]
Performance
-----------
The performance was measured with the `test_vme` program, available in
the svec repository. In the measurement setup, the master was the MEN
A20 board (https://www.men.de/products/discontinued-products/a20/) and
the VME64x Core frequency was 125Mhz.
A24 SCT DMA:
* Read Rate: 15.7 MB/sec
* Write Rate: 17.1 MB/sec
A24 BLT DMA:
* Read Rate: 12.4 MB/sec
* Write Rate: 12.9 MB/sec
A24 MBLT DMA:
* Read Rate: 25.9 MB/sec
* Write Rate: 26.2 MB/sec
According to the simulation, the bad performances of BLT transfer is due
to the master.
[[changes-in-v2-compared-to-v1]]
Changes in V2 (compared to V1)
------------------------------
* Core is smaller (number of slices is less than 1000)
* No retry
* No endianess convertion
* WB data bus is 32 bit
* Internal component declarations removed.
* Async inputs registered with gc_sync_register.
* VME outputs `berr` and `irq` now follow the VME convention (they aren't
anymore inverted by the core).
[[appendix-implementation-of-the-core]]
Appendix: Implementation of the core
------------------------------------
This section describes the internal implementation of the VME64x core.
[[xvme64x_core.vhd]]
xvme64x_core.vhd
~~~~~~~~~~~~~~~~
The top module `xvme64x_core` instantiates the sub-modules and also
synchronizes the asynchronous VME signals (that need to be) to avoid
metastability problems.
This module also handles the `g_USER_CSR_EXT` generic and instantiates
a default user CSR if the generic is set to false.
[[vme_bus.vhd]]
vme_bus.vhd
~~~~~~~~~~~
This is the main module. It implements an FSM to handle the VME
protocol, and acts as the interface between the VME bus and either the
WB bus or the CR/CSR memory.
The module also handles the interrupt acknowledge. If IACK is asserted
on a falling edge of AS, the cycle is considered as an acknowledge
cycle. The FSM then waits until IACKIN is asserted (or until AS is
deasserted). If an interrupt was pending at the right level when
IACKIN is asserted, the VME64x Core responds to the acknowledge cycle
with the interrupt vector; otherwise it asserts IACKOUT.
[[vme_cr_csr_space.vhd]]
vme_cr_csr_space.vhd
~~~~~~~~~~~~~~~~~~~~
This module implements the CR and CSR spaces. It builds (during
elaboration) the CR memory from the generics value, handle accesses
from the VME bus to these memories, interfaces with CRAM (if present),
user CR (if present) and user CSR (if present).
[[vme_func_match.vhd]]
vme_func_match.vhd
~~~~~~~~~~~~~~~~~~
This module checks if the VME address+AM has to be handled by this VME
slave according to ADER and decoder values. Gives back the
corresponding WB address.
[[vme_user_csr.vhd]]
vme_user_csr.vhd
~~~~~~~~~~~~~~~~
This module implements a default user CSR with the irq_level and
irq_vector registers.
[[vme_irq_controller.vhd]]
vme_irq_controller.vhd
~~~~~~~~~~~~~~~~~~~~~~
This module implements the interrupt controller. The interrupt cycle is:
1. The wishbone slave generates an pulse on the `int` line when it has
to interrupts the master
2. If no interrupt is pending and the retry mechanism is not started,
this module asserts (to 0) the corresponding VME IRQ line (as defined by
`irq_level`).
3. When ack'ed, the interrupt is marked as not pending anymore.
4. If the interrupt request stays active for more than 1 cycle (therefore it
isn't a pulse), a retry mechanism is started. The interrupt will be
re-sent on the VME bus every 1ms as long as it is active.
Appendix VME64 VITA-1 rules compliance
--------------------------------------
This appendix lists all rules in the VME64 (in the textual appearance
order), and specifies how it is followed. When the rule doesn't
concern this core, the reason is brievly indicated: 'Master' when the
rule applies only to master modules, 'D64' or 'A64' for unsupported
features.
* 2.1a: Master
* 2.69: Master
* 2.2: Followed
* 2.3: Followed, excluded from c_AMCAP_ALLOWED. [no TB]
* 2.70: D64
* 2.7: Followed
* 2.8: Followed
* 2.9: Followed
* 2.71: A64
* 2.10: Master
* 2.11: Followed
* 2.72: A64
* 2.73: A40
* 2.74: Followed (A32, A24, A16 supported)
* 2.75: Followed (likewise)
* 2.76: Followed (D16 and D08(EO) supported)
* 2.77: Followed (likewise)
* 2.4: Followed (D32 supported)
* 2.5: Followed (D16 supported)
* 2.12a: Master
* 2.78: Master
* 2.66: Followed
* 2.79: Master
* 2.80: Master
* 2.6: Followed [no TB]
* 2.68: Followed [no TB]
* 2.81: Followed (LOCK not accepted)
* 2.82: Followed (likewise)
* 2.83: Master
* 2.84: Followed (lock)
* 2.85: Followed (CR/CSR layout)
* 2.86: Followed
* 2.87: Followed (D08(O) is the data access supported)
* 2.93: Master
* 2.18: Followed (A[] and LWORD lines are registered)
* 2.19: Master
* 2.20: Master
* 2.21: Master
* 2.22: Master
* 2.23: Master
* 2.24: Master
* 2.25: Followed (DATA lines are all driven for read, MBLT not
supported)
* 2.26: Followed (Likewise)
* 2.27: Master
* 2.28: Master
* 2.29: Master
* 2.30: Master
* 2.31: Master
* 2.32: Master
* 2.33a: Master
* 2.34a: Master
* 2.35: Master
* 2.36: Master
* 2.37: Master
* 2.38: Master
* 2.39: Master
* 2.40: Master
* 2.41: Master
* 2.42: Master
* 2.43: Master
* 2.44a: Master
* 2.94: Master
* 2.45: Master
* 2.46a: Master
* 2.47a: Master
* 2.48a: Master
* 2.49: Master
* 2.50: Master
* 2.51: Master
* 2.52: Master
* 2.95: Master
* 2.96: Master
* 2.53a: Followed (VME_DATA_DIR is set only once DSA goes low)
* 2.54a: Followed
* 2.55: Followed (number of states in the main FSM + synch FF)
* 2.28a: Followed (likewise)
* 2.56a: Followed
* 2.57: Followed
* 2.98: TBC
* 2.58a: Followed (released at the same time)
* 2.99: TBC (retry)
* 2.100: TBC (retry)
* 2.101: TBC (retry)
* 2.102: TBC (retry)
* 2.103: TBC (retry)
* 2.104: TBC (retry)
* 2.105: TBC (retry)
* 2.59: Bus timer
* 2.60: Bus timer
* 3.x: Arbitration
* 4.1: Backplace
* 4.50: Followed (slave can generate interrupt)
* 4.2 Followed
External References
-------------------
Specifications used for this core
* [[1]]<<1>> VME64 ANSI/VITA 1-1994 (Stabilized Maintenance 2011)
* [[2]]<<2>> VME64 Extensions ANSI/VITA 1.1-1997 (Stabilized Maintenance 2011)
* [[3]]<<3>> Wishbone System-on-chip (SoC) Interconnection Architecture for
Portable IP Cores, Revision B4
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/ 0000775 0000000 0000000 00000000000 13254235275 0021332 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/ip_cores/ 0000775 0000000 0000000 00000000000 13254235275 0023135 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/ip_cores/general-cores/ 0000775 0000000 0000000 00000000000 13254235275 0025663 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/ 0000775 0000000 0000000 00000000000 13254235275 0022133 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/Manifest.py 0000664 0000000 0000000 00000000365 13254235275 0024257 0 ustar 00root root 0000000 0000000 files = [ "vme64x_core.vhd",
"vme64x_pkg.vhd",
"vme_bus.vhd",
"vme_cr_csr_space.vhd",
"vme_funct_match.vhd",
"vme_irq_controller.vhd",
"vme_user_csr.vhd",
"xvme64x_core.vhd"]
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/vme64x_core.vhd 0000664 0000000 0000000 00000020365 13254235275 0025005 0 ustar 00root root 0000000 0000000 ----------------------------------------------------------------
-- This file was automatically generated by vhdl-unwrap for
-- entity xvme64x_core.
-- DO NOT EDIT.
----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.wishbone_pkg.all;
use work.vme64x_pkg.all;
entity vme64x_core is
generic (
g_clock_period : natural;
g_decode_am : boolean;
g_user_csr_ext : boolean;
g_wb_granularity : t_wishbone_address_granularity;
g_manufacturer_id : std_logic_vector(23 downto 0);
g_board_id : std_logic_vector(31 downto 0);
g_revision_id : std_logic_vector(31 downto 0);
g_program_id : std_logic_vector(7 downto 0);
g_ascii_ptr : std_logic_vector(23 downto 0);
g_beg_user_cr : std_logic_vector(23 downto 0);
g_end_user_cr : std_logic_vector(23 downto 0);
g_beg_cram : std_logic_vector(23 downto 0);
g_end_cram : std_logic_vector(23 downto 0);
g_beg_user_csr : std_logic_vector(23 downto 0);
g_end_user_csr : std_logic_vector(23 downto 0);
g_beg_sn : std_logic_vector(23 downto 0);
g_end_sn : std_logic_vector(23 downto 0);
g_decoder_0_adem : std_logic_vector(31 downto 0);
g_decoder_0_amcap : std_logic_vector(63 downto 0);
g_decoder_0_dawpr : std_logic_vector(7 downto 0);
g_decoder_1_adem : std_logic_vector(31 downto 0);
g_decoder_1_amcap : std_logic_vector(63 downto 0);
g_decoder_1_dawpr : std_logic_vector(7 downto 0);
g_decoder_2_adem : std_logic_vector(31 downto 0);
g_decoder_2_amcap : std_logic_vector(63 downto 0);
g_decoder_2_dawpr : std_logic_vector(7 downto 0);
g_decoder_3_adem : std_logic_vector(31 downto 0);
g_decoder_3_amcap : std_logic_vector(63 downto 0);
g_decoder_3_dawpr : std_logic_vector(7 downto 0);
g_decoder_4_adem : std_logic_vector(31 downto 0);
g_decoder_4_amcap : std_logic_vector(63 downto 0);
g_decoder_4_dawpr : std_logic_vector(7 downto 0);
g_decoder_5_adem : std_logic_vector(31 downto 0);
g_decoder_5_amcap : std_logic_vector(63 downto 0);
g_decoder_5_dawpr : std_logic_vector(7 downto 0);
g_decoder_6_adem : std_logic_vector(31 downto 0);
g_decoder_6_amcap : std_logic_vector(63 downto 0);
g_decoder_6_dawpr : std_logic_vector(7 downto 0);
g_decoder_7_adem : std_logic_vector(31 downto 0);
g_decoder_7_amcap : std_logic_vector(63 downto 0);
g_decoder_7_dawpr : std_logic_vector(7 downto 0));
port (
clk_i : std_logic;
rst_n_i : std_logic;
rst_n_o : out std_logic;
vme_as_n_i : std_logic;
vme_rst_n_i : std_logic;
vme_write_n_i : std_logic;
vme_am_i : std_logic_vector(5 downto 0);
vme_ds_n_i : std_logic_vector(1 downto 0);
vme_ga_i : std_logic_vector(5 downto 0);
vme_lword_n_i : std_logic;
vme_data_i : std_logic_vector(31 downto 0);
vme_addr_i : std_logic_vector(31 downto 1);
vme_iack_n_i : std_logic;
vme_iackin_n_i : std_logic;
vme_iackout_n_o : out std_logic;
vme_dtack_n_o : out std_logic;
vme_dtack_oe_o : out std_logic;
vme_lword_n_o : out std_logic;
vme_data_o : out std_logic_vector(31 downto 0);
vme_data_dir_o : out std_logic;
vme_data_oe_n_o : out std_logic;
vme_addr_o : out std_logic_vector(31 downto 1);
vme_addr_dir_o : out std_logic;
vme_addr_oe_n_o : out std_logic;
vme_retry_n_o : out std_logic;
vme_retry_oe_o : out std_logic;
vme_berr_n_o : out std_logic;
vme_irq_n_o : out std_logic_vector(6 downto 0);
wb_ack_i : std_logic;
wb_err_i : std_logic;
wb_rty_i : std_logic;
wb_stall_i : std_logic;
wb_dat_i : t_wishbone_data;
wb_cyc_o : out std_logic;
wb_stb_o : out std_logic;
wb_adr_o : out t_wishbone_address;
wb_sel_o : out t_wishbone_byte_select;
wb_we_o : out std_logic;
wb_dat_o : out t_wishbone_data;
int_i : std_logic;
irq_ack_o : out std_logic;
irq_level_i : std_logic_vector(2 downto 0);
irq_vector_i : std_logic_vector(7 downto 0);
user_csr_addr_o : out std_logic_vector(18 downto 2);
user_csr_data_i : std_logic_vector(7 downto 0);
user_csr_data_o : out std_logic_vector(7 downto 0);
user_csr_we_o : out std_logic;
user_cr_addr_o : out std_logic_vector(18 downto 2);
user_cr_data_i : std_logic_vector(7 downto 0));
end vme64x_core;
architecture unwrap of vme64x_core is
begin
inst : entity work.xvme64x_core
generic map (
g_clock_period => g_clock_period,
g_decode_am => g_decode_am,
g_user_csr_ext => g_user_csr_ext,
g_wb_granularity => g_wb_granularity,
g_manufacturer_id => g_manufacturer_id,
g_board_id => g_board_id,
g_revision_id => g_revision_id,
g_program_id => g_program_id,
g_ascii_ptr => g_ascii_ptr,
g_beg_user_cr => g_beg_user_cr,
g_end_user_cr => g_end_user_cr,
g_beg_cram => g_beg_cram,
g_end_cram => g_end_cram,
g_beg_user_csr => g_beg_user_csr,
g_end_user_csr => g_end_user_csr,
g_beg_sn => g_beg_sn,
g_end_sn => g_end_sn,
g_decoder(0).adem => g_decoder_0_adem,
g_decoder(0).amcap => g_decoder_0_amcap,
g_decoder(0).dawpr => g_decoder_0_dawpr,
g_decoder(1).adem => g_decoder_1_adem,
g_decoder(1).amcap => g_decoder_1_amcap,
g_decoder(1).dawpr => g_decoder_1_dawpr,
g_decoder(2).adem => g_decoder_2_adem,
g_decoder(2).amcap => g_decoder_2_amcap,
g_decoder(2).dawpr => g_decoder_2_dawpr,
g_decoder(3).adem => g_decoder_3_adem,
g_decoder(3).amcap => g_decoder_3_amcap,
g_decoder(3).dawpr => g_decoder_3_dawpr,
g_decoder(4).adem => g_decoder_4_adem,
g_decoder(4).amcap => g_decoder_4_amcap,
g_decoder(4).dawpr => g_decoder_4_dawpr,
g_decoder(5).adem => g_decoder_5_adem,
g_decoder(5).amcap => g_decoder_5_amcap,
g_decoder(5).dawpr => g_decoder_5_dawpr,
g_decoder(6).adem => g_decoder_6_adem,
g_decoder(6).amcap => g_decoder_6_amcap,
g_decoder(6).dawpr => g_decoder_6_dawpr,
g_decoder(7).adem => g_decoder_7_adem,
g_decoder(7).amcap => g_decoder_7_amcap,
g_decoder(7).dawpr => g_decoder_7_dawpr)
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
rst_n_o => rst_n_o,
vme_i.as_n => vme_as_n_i,
vme_i.rst_n => vme_rst_n_i,
vme_i.write_n => vme_write_n_i,
vme_i.am => vme_am_i,
vme_i.ds_n => vme_ds_n_i,
vme_i.ga => vme_ga_i,
vme_i.lword_n => vme_lword_n_i,
vme_i.data => vme_data_i,
vme_i.addr => vme_addr_i,
vme_i.iack_n => vme_iack_n_i,
vme_i.iackin_n => vme_iackin_n_i,
vme_o.iackout_n => vme_iackout_n_o,
vme_o.dtack_n => vme_dtack_n_o,
vme_o.dtack_oe => vme_dtack_oe_o,
vme_o.lword_n => vme_lword_n_o,
vme_o.data => vme_data_o,
vme_o.data_dir => vme_data_dir_o,
vme_o.data_oe_n => vme_data_oe_n_o,
vme_o.addr => vme_addr_o,
vme_o.addr_dir => vme_addr_dir_o,
vme_o.addr_oe_n => vme_addr_oe_n_o,
vme_o.retry_n => vme_retry_n_o,
vme_o.retry_oe => vme_retry_oe_o,
vme_o.berr_n => vme_berr_n_o,
vme_o.irq_n => vme_irq_n_o,
wb_i.ack => wb_ack_i,
wb_i.err => wb_err_i,
wb_i.rty => wb_rty_i,
wb_i.stall => wb_stall_i,
wb_i.dat => wb_dat_i,
wb_o.cyc => wb_cyc_o,
wb_o.stb => wb_stb_o,
wb_o.adr => wb_adr_o,
wb_o.sel => wb_sel_o,
wb_o.we => wb_we_o,
wb_o.dat => wb_dat_o,
int_i => int_i,
irq_ack_o => irq_ack_o,
irq_level_i => irq_level_i,
irq_vector_i => irq_vector_i,
user_csr_addr_o => user_csr_addr_o,
user_csr_data_i => user_csr_data_i,
user_csr_data_o => user_csr_data_o,
user_csr_we_o => user_csr_we_o,
user_cr_addr_o => user_cr_addr_o,
user_cr_data_i => user_cr_data_i);
end unwrap;
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/vme64x_pkg.vhd 0000664 0000000 0000000 00000023246 13254235275 0024637 0 ustar 00root root 0000000 0000000 --------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- VME64x Core
-- http://www.ohwr.org/projects/vme64x-core
--------------------------------------------------------------------------------
--
-- unit name: vme64x_pkg
--
-- author: Pablo Alvarez Sanchez
-- Davide Pedretti
--
-- description: VME64x Core Package
--
-- dependencies:
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file 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 source 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
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------
-- last changes: see log.
--------------------------------------------------------------------------------
-- TODO: -
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
package vme64x_pkg is
------------------------------------------------------------------------------
-- Constants
------------------------------------------------------------------------------
-- Manufactuer IDs.
constant c_CERN_ID : std_logic_vector(23 downto 0) := x"080030";
-- Boards IDs / Revision IDs.
-- For SVEC:
constant c_SVEC_ID : std_logic_vector(31 downto 0) := x"00000198";
constant c_SVEC_REVISION_ID : std_logic_vector(31 downto 0) := x"00000001";
-- Default Program ID value for SVEC.
constant c_SVEC_PROGRAM_ID : std_logic_vector( 7 downto 0) := x"5a";
-- Bits in ADEM/ADER registers
subtype t_ADEM_M is integer range 31 downto 8;
constant c_ADEM_M_PAD : std_logic_vector(7 downto 0) := (others => '0');
constant c_ADEM_FAF : integer := 3;
constant c_ADEM_DFS : integer := 2;
constant c_ADEM_EFD : integer := 1;
constant c_ADEM_EFM : integer := 0;
-- Although the XAM registers are not used, these declarations are still
-- present for completness.
subtype t_ADER_C_XAM is integer range 31 downto 10;
constant c_ADER_C_XAM_PAD : std_logic_vector(9 downto 0) := (others => '0');
subtype t_ADER_C_AM is integer range 31 downto 8;
constant c_ADER_C_AM_PAD : std_logic_vector(7 downto 0) := (others => '0');
subtype t_ADER_AM is integer range 7 downto 2;
subtype t_ADER_XAM is integer range 9 downto 2;
constant c_ADER_DFSR : integer := 1;
constant c_ADER_XAM_MODE : integer := 0;
-- AM table.
-- References:
-- Table 2-3 "Address Modifier Codes" pages 21/22 VME64std ANSI/VITA 1-1994
-- Table 2.4 "Extended Address Modifier Code" page 12 2eSST
-- ANSI/VITA 1.5-2003(R2009)
subtype t_am_vec is std_logic_vector(5 downto 0);
constant c_AM_A24_S_SUP : t_am_vec := "111101"; -- 0x3d
constant c_AM_A24_S : t_am_vec := "111001"; -- 0x39
constant c_AM_A24_BLT : t_am_vec := "111011"; -- 0x3b
constant c_AM_A24_BLT_SUP : t_am_vec := "111111"; -- 0x3f
constant c_AM_A24_MBLT : t_am_vec := "111000"; -- 0x38
constant c_AM_A24_MBLT_SUP : t_am_vec := "111100"; -- 0x3c
constant c_AM_A24_LCK : t_am_vec := "110010"; -- 0x32
constant c_AM_CR_CSR : t_am_vec := "101111"; -- 0x2f
constant c_AM_A16 : t_am_vec := "101001"; -- 0x29
constant c_AM_A16_SUP : t_am_vec := "101101"; -- 0x2d
constant c_AM_A16_LCK : t_am_vec := "101100"; -- 0x2c
constant c_AM_A32 : t_am_vec := "001001"; -- 0x09
constant c_AM_A32_SUP : t_am_vec := "001101"; -- 0x0d
constant c_AM_A32_BLT : t_am_vec := "001011"; -- 0x0b
constant c_AM_A32_BLT_SUP : t_am_vec := "001111"; -- 0x0f
constant c_AM_A32_MBLT : t_am_vec := "001000"; -- 0x08
constant c_AM_A32_MBLT_SUP : t_am_vec := "001100"; -- 0x0c
constant c_AM_A32_LCK : t_am_vec := "000101"; -- 0x05
constant c_AM_A64 : t_am_vec := "000001"; -- 0x01
constant c_AM_A64_BLT : t_am_vec := "000011"; -- 0x03
constant c_AM_A64_MBLT : t_am_vec := "000000"; -- 0x00
constant c_AM_A64_LCK : t_am_vec := "000100"; -- 0x04
constant c_AM_2EVME_6U : t_am_vec := "100000"; -- 0x20
constant c_AM_2EVME_3U : t_am_vec := "100001"; -- 0x21
-- Not used, but for completness.
subtype t_xam_vec is std_logic_vector(7 downto 0);
constant c_AM_A32_2EVME : t_xam_vec := "00000001"; -- 0x01
constant c_AM_A64_2EVME : t_xam_vec := "00000010"; -- 0x02
constant c_AM_A32_2ESST : t_xam_vec := "00010001"; -- 0x11
constant c_AM_A64_2ESST : t_xam_vec := "00010010"; -- 0x12
------------------------------------------------------------------------------
-- Types
------------------------------------------------------------------------------
-- CR/CSR parameter arrays
subtype t_vme_func_index is natural range 0 to 7;
type t_ader_array is
array (t_vme_func_index range <>) of std_logic_vector(31 downto 0);
type t_vme64x_in is record
as_n : std_logic;
rst_n : std_logic;
write_n : std_logic;
am : std_logic_vector(5 downto 0);
ds_n : std_logic_vector(1 downto 0);
ga : std_logic_vector(5 downto 0);
lword_n : std_logic;
data : std_logic_vector(31 downto 0);
addr : std_logic_vector(31 downto 1);
iack_n : std_logic;
iackin_n : std_logic;
end record;
type t_vme64x_out is record
iackout_n : std_logic;
dtack_n : std_logic;
dtack_oe : std_logic;
lword_n : std_logic;
data : std_logic_vector(31 downto 0);
data_dir : std_logic;
data_oe_n : std_logic;
addr : std_logic_vector(31 downto 1);
addr_dir : std_logic;
addr_oe_n : std_logic;
retry_n : std_logic;
retry_oe : std_logic;
berr_n : std_logic;
irq_n : std_logic_vector(6 downto 0);
end record;
-- For generics: per decoder values.
type t_vme64x_decoder is record
adem : std_logic_vector(31 downto 0);
amcap : std_logic_vector(63 downto 0);
dawpr : std_logic_vector( 7 downto 0);
end record;
-- Value to disable a decoder.
constant c_vme64x_decoder_disabled : t_vme64x_decoder := (
adem => x"00000000",
amcap => x"00000000_00000000",
dawpr => x"84");
type t_vme64x_decoder_arr is array(0 to 7) of t_vme64x_decoder;
constant c_vme64x_decoders_default : t_vme64x_decoder_arr := (
0 => (adem => x"ff000000",
amcap => x"00000000_0000ff00",
dawpr => x"84"),
1 => (adem => x"fff80000",
amcap => x"ff000000_00000000",
dawpr => x"84"),
others => c_vme64x_decoder_disabled);
------------------------------------------------------------------------------
-- Components declaration
------------------------------------------------------------------------------
-- Refer to the entity declaration (xvme64x_core.vhd) for comments.
component xvme64x_core
generic (
g_CLOCK_PERIOD : natural;
g_DECODE_AM : boolean := true;
g_USER_CSR_EXT : boolean := false;
g_WB_GRANULARITY : t_wishbone_address_granularity;
g_MANUFACTURER_ID : std_logic_vector(23 downto 0);
g_BOARD_ID : std_logic_vector(31 downto 0);
g_REVISION_ID : std_logic_vector(31 downto 0);
g_PROGRAM_ID : std_logic_vector( 7 downto 0);
g_ASCII_PTR : std_logic_vector(23 downto 0) := x"000000";
g_BEG_USER_CR : std_logic_vector(23 downto 0) := x"000000";
g_END_USER_CR : std_logic_vector(23 downto 0) := x"000000";
g_BEG_CRAM : std_logic_vector(23 downto 0) := x"000000";
g_END_CRAM : std_logic_vector(23 downto 0) := x"000000";
g_BEG_USER_CSR : std_logic_vector(23 downto 0) := x"07ff33";
g_END_USER_CSR : std_logic_vector(23 downto 0) := x"07ff5f";
g_BEG_SN : std_logic_vector(23 downto 0) := x"000000";
g_END_SN : std_logic_vector(23 downto 0) := x"000000";
g_DECODER : t_vme64x_decoder_arr := c_vme64x_decoders_default);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
rst_n_o : out std_logic;
vme_i : in t_vme64x_in;
vme_o : out t_vme64x_out;
wb_i : in t_wishbone_master_in;
wb_o : out t_wishbone_master_out;
int_i : in std_logic := '0';
irq_ack_o : out std_logic;
irq_level_i : in std_logic_vector( 2 downto 0) := (others => '0');
irq_vector_i : in std_logic_vector( 7 downto 0) := (others => '0');
user_csr_addr_o : out std_logic_vector(18 downto 2);
user_csr_data_i : in std_logic_vector( 7 downto 0) := (others => '0');
user_csr_data_o : out std_logic_vector( 7 downto 0);
user_csr_we_o : out std_logic;
user_cr_addr_o : out std_logic_vector(18 downto 2);
user_cr_data_i : in std_logic_vector( 7 downto 0) := (others => '0'));
end component xvme64x_core;
end vme64x_pkg;
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/vme_bus.vhd 0000664 0000000 0000000 00000062556 13254235275 0024314 0 ustar 00root root 0000000 0000000 --------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- VME64x Core
-- http://www.ohwr.org/projects/vme64x-core
--------------------------------------------------------------------------------
--
-- unit name: VME_bus
--
-- description:
--
-- This block acts as interface between the VMEbus and the CR/CSR space or
-- WB bus.
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file 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 source 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
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vme64x_pkg.all;
use work.wishbone_pkg.all;
entity vme_bus is
generic (
g_CLOCK_PERIOD : integer;
g_WB_GRANULARITY : t_wishbone_address_granularity
);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-- VME signals
VME_AS_n_i : in std_logic;
VME_LWORD_n_o : out std_logic := '0';
VME_LWORD_n_i : in std_logic;
VME_RETRY_n_o : out std_logic;
VME_RETRY_OE_o : out std_logic;
VME_WRITE_n_i : in std_logic;
VME_DS_n_i : in std_logic_vector(1 downto 0);
VME_DTACK_n_o : out std_logic;
VME_DTACK_OE_o : out std_logic;
VME_BERR_n_o : out std_logic;
VME_ADDR_i : in std_logic_vector(31 downto 1);
VME_ADDR_o : out std_logic_vector(31 downto 1) := (others => '0');
VME_ADDR_DIR_o : out std_logic;
VME_ADDR_OE_N_o : out std_logic;
VME_DATA_i : in std_logic_vector(31 downto 0);
VME_DATA_o : out std_logic_vector(31 downto 0) := (others => '0');
VME_DATA_DIR_o : out std_logic;
VME_DATA_OE_N_o : out std_logic;
VME_AM_i : in std_logic_vector(5 downto 0);
VME_IACKIN_n_i : in std_logic;
VME_IACK_n_i : in std_logic;
VME_IACKOUT_n_o : out std_logic;
-- WB signals
wb_stb_o : out std_logic;
wb_ack_i : in std_logic;
wb_dat_o : out std_logic_vector(31 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_adr_o : out std_logic_vector(31 downto 0);
wb_sel_o : out std_logic_vector(3 downto 0);
wb_we_o : out std_logic;
wb_cyc_o : out std_logic;
wb_err_i : in std_logic;
wb_stall_i : in std_logic;
-- Function decoder
addr_decoder_i : in std_logic_vector(31 downto 1);
addr_decoder_o : out std_logic_vector(31 downto 1);
decode_start_o : out std_logic;
decode_done_i : in std_logic;
am_o : out std_logic_vector( 5 downto 0);
decode_sel_i : in std_logic;
-- CR/CSR space signals:
cr_csr_addr_o : out std_logic_vector(18 downto 2);
cr_csr_data_i : in std_logic_vector( 7 downto 0);
cr_csr_data_o : out std_logic_vector( 7 downto 0);
cr_csr_we_o : out std_logic;
module_enable_i : in std_logic;
bar_i : in std_logic_vector( 4 downto 0);
-- Interrupts
INT_Level_i : in std_logic_vector( 2 downto 0);
INT_Vector_i : in std_logic_vector( 7 downto 0);
irq_pending_i : in std_logic;
irq_ack_o : out std_logic
);
end vme_bus;
architecture rtl of vme_bus is
-- Local data
signal s_locDataIn : std_logic_vector(63 downto 0);
signal s_locDataOut : std_logic_vector(63 downto 0);
-- VME latched signals
signal s_ADDRlatched : std_logic_vector(31 downto 1);
signal s_LWORDlatched_n : std_logic;
signal s_DSlatched_n : std_logic_vector(1 downto 0);
signal s_AMlatched : std_logic_vector(5 downto 0);
signal s_WRITElatched_n : std_logic;
-- Address and data from the VME bus. There are two registers so that the
-- first one can be placed in the IOBs.
signal s_vme_addr_reg : std_logic_vector(31 downto 1);
signal s_vme_data_reg : std_logic_vector(31 downto 0);
signal s_vme_lword_n_reg : std_logic;
signal s_vme_addr_dir : std_logic;
type t_addressingType is (
A24,
A24_BLT,
A24_MBLT,
CR_CSR,
A16,
A32,
A32_BLT,
A32_MBLT,
AM_ERROR
);
type t_transferType is (
SINGLE,
BLT,
MBLT,
TFR_ERROR
);
-- Addressing type (depending on VME_AM_i)
signal s_addressingType : t_addressingType;
signal s_transferType : t_transferType;
type t_mainFSMstates is (
-- Wait until AS is asserted.
IDLE,
-- Reformat address according to AM.
REFORMAT_ADDRESS,
-- Decoding ADDR and AM (selecting card or conf).
DECODE_ACCESS,
-- Wait until DS is asserted.
WAIT_FOR_DS,
-- Wait until DS is stable (and asserted).
LATCH_DS,
-- Decode DS, generate WB request
CHECK_TRANSFER_TYPE,
-- Wait for WB reply
MEMORY_REQ,
-- For read cycle, put data on the bus
DATA_TO_BUS,
-- Assert DTACK
DTACK_LOW,
-- Increment address for block transfers
INCREMENT_ADDR,
-- Check if IACK is for this slave
IRQ_CHECK,
-- Pass IACKIN to IACKOUT
IRQ_PASS,
-- Wait until AS is deasserted
WAIT_END
);
-- Main FSM signals
signal s_mainFSMstate : t_mainFSMstates;
signal s_conf_req : std_logic; -- Global memory request
signal s_dataPhase : std_logic; -- for MBLT
signal s_MBLT_Data : std_logic; -- for MBLT: '1' in Addr
-- Access decode signals
signal s_conf_sel : std_logic; -- CR or CSR is addressed
signal s_card_sel : std_logic; -- WB memory is addressed
signal s_irq_sel : std_logic; -- IACK transaction
signal s_err : std_logic;
-- Calculate the number of LATCH DS states necessary to match the timing
-- rule 2.39 page 113 VMEbus specification ANSI/IEEE STD1014-1987.
-- (max skew for the slave is 20 ns)
constant c_num_latchDS : natural range 1 to 8 :=
(20 + g_CLOCK_PERIOD - 1) / g_CLOCK_PERIOD;
signal s_DS_latch_count : unsigned (2 downto 0);
begin
-- These output signals are connected to the buffers on the board
-- SN74VMEH22501A Function table: (A is fpga, B is VME connector)
-- OEn | DIR | OUTPUT OEAB | OEBYn | OUTPUT
-- H | X | Z L | H | Z
-- L | H | A to B H | H | A to B
-- L | L | B to A L | L | B to Y
-- H | L |A to B, B to Y |
VME_DATA_OE_N_o <= '0'; -- Driven IFF DIR = 1
VME_ADDR_OE_N_o <= '0'; -- Driven IFF DIR = 1
------------------------------------------------------------------------------
-- Access Mode Decoders
------------------------------------------------------------------------------
-- Type of data transfer decoder
-- VME64 ANSI/VITA 1-1994...Table 2-2 "Signal levels during data transfers"
-- Bytes position on VMEbus:
--
-- A24-31 | A16-23 | A08-15 | A00-07 | D24-31 | D16-23 | D08-15 | D00-07
-- | | | | | | BYTE 0 |
-- | | | | | | | BYTE 1
-- | | | | | | BYTE 2 |
-- | | | | | | | BYTE 3
-- | | | | | | BYTE 0 | BYTE 1
-- | | | | | | BYTE 2 | BYTE 3
-- | | | | BYTE 0 | BYTE 1 | BYTE 2 | BYTE 3
-- BYTE 0 | BYTE 1 | BYTE 2 | BYTE 3 | BYTE 4 | BYTE 5 | BYTE 6 | BYTE 7
-- Address modifier decoder
-- Both the supervisor and the user access modes are supported
with s_AMlatched select s_addressingType <=
A24 when c_AM_A24_S_SUP | c_AM_A24_S,
A24_BLT when c_AM_A24_BLT | c_AM_A24_BLT_SUP,
A24_MBLT when c_AM_A24_MBLT | c_AM_A24_MBLT_SUP,
CR_CSR when c_AM_CR_CSR,
A16 when c_AM_A16 | c_AM_A16_SUP,
A32 when c_AM_A32 | c_AM_A32_SUP,
A32_BLT when c_AM_A32_BLT | c_AM_A32_BLT_SUP,
A32_MBLT when c_AM_A32_MBLT | c_AM_A32_MBLT_SUP,
AM_ERROR when others;
-- Transfer type decoder
with s_addressingType select s_transferType <=
SINGLE when A24 | CR_CSR | A16 | A32,
BLT when A24_BLT | A32_BLT,
MBLT when A24_MBLT | A32_MBLT,
TFR_ERROR when others;
------------------------------------------------------------------------------
-- MAIN FSM
------------------------------------------------------------------------------
p_VMEmainFSM : process (clk_i) is
variable addr_word_incr : natural range 0 to 7;
begin
if rising_edge(clk_i) then
if rst_n_i = '0' or VME_AS_n_i = '1' then
-- FSM reset after power up,
-- software reset, manually reset,
-- on rising edge of AS.
s_conf_req <= '0';
decode_start_o <= '0';
-- VME
VME_DTACK_OE_o <= '0';
VME_DTACK_n_o <= '1';
VME_DATA_DIR_o <= '0';
VME_ADDR_DIR_o <= '0';
VME_BERR_n_o <= '1';
VME_ADDR_o <= (others => '0');
VME_LWORD_n_o <= '1';
VME_DATA_o <= (others => '0');
VME_IACKOUT_n_o <= '1';
s_dataPhase <= '0';
s_MBLT_Data <= '0';
s_mainFSMstate <= IDLE;
-- WB
wb_sel_o <= "0000";
wb_cyc_o <= '0';
wb_stb_o <= '0';
s_err <= '0';
s_ADDRlatched <= (others => '0');
s_AMlatched <= (others => '0');
s_vme_addr_reg <= (others => '0');
s_vme_addr_dir <= '0';
s_card_sel <= '0';
s_conf_sel <= '0';
s_irq_sel <= '0';
irq_ack_o <= '0';
else
s_conf_req <= '0';
decode_start_o <= '0';
VME_DTACK_OE_o <= '0';
VME_DTACK_n_o <= '1';
VME_DATA_DIR_o <= '0';
VME_ADDR_DIR_o <= '0';
VME_BERR_n_o <= '1';
VME_IACKOUT_n_o <= '1';
irq_ack_o <= '0';
case s_mainFSMstate is
when IDLE =>
-- Can only be here if VME_AS_n_i has fallen to 0, which starts a
-- cycle.
assert VME_AS_n_i = '0';
-- Store ADDR, AM and LWORD
s_ADDRlatched <= VME_ADDR_i;
s_LWORDlatched_n <= VME_LWORD_n_i;
s_AMlatched <= VME_AM_i;
if VME_IACK_n_i = '1' then
-- VITA-1 Rule 2.11
-- Slaves MUST NOT respond to DTB cycles when IACK* is low.
s_mainFSMstate <= REFORMAT_ADDRESS;
else
-- IACK cycle.
s_mainFSMstate <= IRQ_CHECK;
end if;
when REFORMAT_ADDRESS =>
-- Reformat address according to the mode (A16, A24, A32)
-- FIXME: not needed if ADEM are correctly reduced to not compare
-- MSBs of A16 or A24 addresses.
s_vme_addr_reg <= s_ADDRlatched;
case s_addressingType is
when A16 =>
s_vme_addr_reg (31 downto 16) <= (others => '0'); -- A16
when A24 | A24_BLT | A24_MBLT =>
s_vme_addr_reg (31 downto 24) <= (others => '0'); -- A24
when others =>
null; -- A32
end case;
s_vme_lword_n_reg <= s_LWORDlatched_n;
-- Address is not yet decoded.
s_card_sel <= '0';
s_conf_sel <= '0';
s_irq_sel <= '0';
-- DS latch counter
s_DS_latch_count <= to_unsigned (c_num_latchDS, 3);
-- VITA-1 Rule 2.6
-- A Slave MUST NOT respond with a falling edge on DTACK* during
-- an unaligned transfer cycle, if it does not have UAT
-- capability.
if s_LWORDlatched_n = '0' and s_ADDRlatched(1) = '1' then
-- unaligned.
s_mainFSMstate <= WAIT_END;
else
if s_ADDRlatched(23 downto 19) = bar_i
and s_AMlatched = c_AM_CR_CSR
then
-- conf_sel = '1' it means CR/CSR space addressed
s_conf_sel <= '1';
s_mainFSMstate <= WAIT_FOR_DS;
else
s_mainFSMstate <= DECODE_ACCESS;
decode_start_o <= '1';
end if;
end if;
when DECODE_ACCESS =>
-- Check if this slave board is addressed.
-- Wait for DS in parallel.
if VME_DS_n_i /= "11" then
s_WRITElatched_n <= VME_WRITE_n_i;
if s_DS_latch_count /= 0 then
s_DS_latch_count <= s_DS_latch_count - 1;
end if;
end if;
if decode_done_i = '1' then
if decode_sel_i = '1' and module_enable_i = '1' then
-- card_sel = '1' it means WB application addressed
s_card_sel <= '1';
-- Keep only the local part of the address.
s_vme_addr_reg <= addr_decoder_i;
if VME_DS_n_i = "11" then
s_mainFSMstate <= WAIT_FOR_DS;
else
s_mainFSMstate <= LATCH_DS;
end if;
else
-- Another board will answer; wait here the rising edge on
-- VME_AS_i (done by top if).
s_mainFSMstate <= WAIT_END;
end if;
else
-- Not yet decoded.
s_mainFSMstate <= DECODE_ACCESS;
end if;
when WAIT_FOR_DS =>
-- wait until DS /= "11"
-- Note: before entering this state, s_DS_latch_count must be set.
if VME_DS_n_i /= "11" then
-- VITAL-1 Table 4-1
-- For interrupts ack, the handler MUST NOT drive WRITE* low
s_WRITElatched_n <= VME_WRITE_n_i;
if s_DS_latch_count /= 0 then
s_DS_latch_count <= s_DS_latch_count - 1;
end if;
s_mainFSMstate <= LATCH_DS;
else
s_mainFSMstate <= WAIT_FOR_DS;
end if;
when LATCH_DS =>
-- This state is necessary indeed the VME master can assert the
-- DS lines not at the same time.
-- VITA-1 Rule 2.53a
-- During all read cycles [...], the responding slave MUST NOT
-- drive the D[] lines until DSA* goes low.
VME_DATA_DIR_o <= s_WRITElatched_n;
VME_ADDR_DIR_o <= '0';
if s_transferType = MBLT then
s_dataPhase <= '1';
-- Start with D[31..0] when writing, but D[63..32] when reading.
s_vme_addr_reg(2) <= not s_WRITElatched_n;
else
s_dataPhase <= '0';
end if;
if s_DS_latch_count = 0 or s_transferType = MBLT then
if s_irq_sel = '1' then
s_mainFSMstate <= DATA_TO_BUS;
elsif s_transferType = MBLT and s_MBLT_Data = '0' then
-- MBLT: ack address.
-- (Data are also read but discarded).
s_mainFSMstate <= DTACK_LOW;
else
s_mainFSMstate <= CHECK_TRANSFER_TYPE;
end if;
-- Read DS (which is delayed to avoid metastability).
s_DSlatched_n <= VME_DS_n_i;
-- Read DATA (which are stable)
s_locDataIn(63 downto 33) <= VME_ADDR_i;
s_LWORDlatched_n <= VME_LWORD_n_i;
s_vme_data_reg <= VME_DATA_i;
else
s_mainFSMstate <= LATCH_DS;
s_DS_latch_count <= s_DS_latch_count - 1;
end if;
when CHECK_TRANSFER_TYPE =>
VME_DATA_DIR_o <= s_WRITElatched_n;
VME_ADDR_DIR_o <= '0';
s_dataPhase <= s_dataPhase;
-- VME_ADDR is an output during MBLT *read* data transfer.
if s_transferType = MBLT and s_WRITElatched_n = '1' then
s_vme_addr_dir <= '1';
else
s_vme_addr_dir <= '0';
end if;
s_locDataIn(32) <= s_LWORDlatched_n;
s_locDataIn(31 downto 0) <= s_vme_data_reg;
if s_vme_lword_n_reg = '1' and s_vme_addr_reg(1) = '0' then
-- Word/byte access with A1=0
s_locDataIn(31 downto 16) <= s_vme_data_reg(15 downto 0);
end if;
-- Translate DS+LWORD+ADDR to WB byte selects
if s_vme_lword_n_reg = '0' then
wb_sel_o <= "1111";
else
wb_sel_o <= "0000";
case s_vme_addr_reg(1) is
when '0' =>
wb_sel_o (3 downto 2) <= not s_DSlatched_n;
when '1' =>
wb_sel_o (1 downto 0) <= not s_DSlatched_n;
when others =>
null;
end case;
end if;
-- VITA-1 Rule 2.6
-- A Slave MUST NOT respond with a falling edge on DTACK* during
-- an unaligned transfer cycle, if it does not have UAT
-- capability.
if s_vme_lword_n_reg = '0' and s_DSlatched_n /= "00" then
-- unaligned.
s_mainFSMstate <= WAIT_END;
else
s_mainFSMstate <= MEMORY_REQ;
s_conf_req <= s_conf_sel;
-- Start WB cycle.
wb_cyc_o <= s_card_sel;
wb_stb_o <= s_card_sel;
s_err <= '0';
end if;
when MEMORY_REQ =>
-- To request the memory CR/CSR or WB memory it is sufficient to
-- generate a pulse on s_conf_req signal
VME_DTACK_OE_o <= '1';
VME_DATA_DIR_o <= s_WRITElatched_n;
VME_ADDR_DIR_o <= s_vme_addr_dir;
-- Assert STB if stall was asserted.
wb_stb_o <= s_card_sel and wb_stall_i;
if s_conf_sel = '1'
or (s_card_sel = '1' and (wb_ack_i = '1' or wb_err_i = '1'))
then
-- WB ack
wb_stb_o <= '0';
s_err <= s_card_sel and wb_err_i;
if (s_card_sel and wb_err_i) = '1' then
-- Error
s_mainFSMstate <= DTACK_LOW;
elsif s_WRITElatched_n = '0' then
-- Write cycle.
if s_dataPhase = '1' then
-- MBLT
s_dataPhase <= '0';
s_vme_addr_reg(2) <= '0';
s_locDataIn(31 downto 0) <= s_locDataIn(63 downto 32);
wb_stb_o <= s_card_sel;
s_mainFSMstate <= MEMORY_REQ;
else
s_mainFSMstate <= DTACK_LOW;
end if;
else
-- Read cycle
-- Mux (CS-CSR or WB)
s_locDataOut(63 downto 32) <= s_locDataOut(31 downto 0);
s_locDataOut(31 downto 0) <= (others => '0');
if s_card_sel = '1' then
if s_vme_lword_n_reg = '1' and s_vme_addr_reg(1) = '0' then
-- Word/byte access with A1 = 0
s_locDataOut(15 downto 0) <= wb_dat_i(31 downto 16);
else
s_locDataOut(31 downto 0) <= wb_dat_i;
end if;
else
s_locDataOut(7 downto 0) <= cr_csr_data_i;
end if;
if s_dataPhase = '1' then
-- MBLT
s_dataPhase <= '0';
s_vme_addr_reg(2) <= '1';
wb_stb_o <= s_card_sel;
s_mainFSMstate <= MEMORY_REQ;
else
s_mainFSMstate <= DATA_TO_BUS;
end if;
end if;
else
s_mainFSMstate <= MEMORY_REQ;
end if;
when DATA_TO_BUS =>
VME_DTACK_OE_o <= '1';
VME_DATA_DIR_o <= s_WRITElatched_n;
VME_ADDR_DIR_o <= s_vme_addr_dir;
VME_ADDR_o <= s_locDataOut(63 downto 33);
VME_LWORD_n_o <= s_locDataOut(32);
VME_DATA_o <= s_locDataOut(31 downto 0);
-- VITA-1 Rule 2.54a
-- During all read cycles, the responding Slave MUST NOT drive
-- DTACK* low before it drives D[].
s_mainFSMstate <= DTACK_LOW;
when DTACK_LOW =>
VME_DTACK_OE_o <= '1';
VME_DATA_DIR_o <= s_WRITElatched_n;
VME_ADDR_DIR_o <= s_vme_addr_dir;
-- Set DTACK (or retry or berr)
if s_card_sel = '1' and s_err = '1' then
VME_BERR_n_o <= '0';
else
VME_DTACK_n_o <= '0';
end if;
-- VITA-1 Rule 2.57
-- Once the responding Slave has driven DTACK* or BERR* low, it
-- MUST NOT release them or drive DTACK* high until it detects
-- both DS0* and DS1* high.
if VME_DS_n_i = "11" then
VME_DATA_DIR_o <= '0';
VME_BERR_n_o <= '1';
-- Rescind DTACK.
VME_DTACK_n_o <= '1';
-- DS latch counter
s_DS_latch_count <= to_unsigned (c_num_latchDS, 3);
if s_irq_sel = '1' then
s_mainFSMstate <= WAIT_END;
elsif s_transferType = SINGLE then
-- Cycle should be finished, but allow another access at
-- the same address (RMW).
s_mainFSMstate <= WAIT_FOR_DS;
else
if s_transferType = MBLT and s_MBLT_Data = '0' then
-- MBLT: end of address phase.
s_mainFSMstate <= WAIT_FOR_DS;
s_MBLT_Data <= '1';
else
-- Block
s_mainFSMstate <= INCREMENT_ADDR;
end if;
end if;
else
s_mainFSMstate <= DTACK_LOW;
end if;
when INCREMENT_ADDR =>
VME_DTACK_OE_o <= '1';
VME_ADDR_DIR_o <= s_vme_addr_dir;
if s_vme_lword_n_reg = '0' then
if s_transferType = MBLT then
-- 64 bit
addr_word_incr := 4;
else
-- 32 bit
addr_word_incr := 2;
end if;
else
if s_DSlatched_n (0) = '0' then
-- Next word for D16 or D08(O)
addr_word_incr := 1;
else
addr_word_incr := 0;
end if;
end if;
-- Only increment within the window, don't check the limit.
-- BLT --> limit = 256 bytes (rule 2.12a ANSI/VITA 1-1994)
-- MBLT --> limit = 2048 bytes (rule 2.78 ANSI/VITA 1-1994)
s_vme_addr_reg (11 downto 1) <= std_logic_vector
(unsigned(s_vme_addr_reg (11 downto 1)) + addr_word_incr);
s_mainFSMstate <= WAIT_FOR_DS;
when IRQ_CHECK =>
if VME_IACKIN_n_i = '0' then
if s_ADDRlatched(3 downto 1) = INT_Level_i
and irq_pending_i = '1'
then
-- That's for us
s_locDataOut <= (others => '0');
s_locDataOut (7 downto 0) <= INT_Vector_i;
s_irq_sel <= '1';
irq_ack_o <= '1';
s_mainFSMstate <= WAIT_FOR_DS;
else
-- Pass
VME_IACKOUT_n_o <= '0';
s_mainFSMstate <= IRQ_PASS;
end if;
else
s_mainFSMstate <= IRQ_CHECK;
end if;
when IRQ_PASS =>
-- Will stay here until AS is released.
VME_IACKOUT_n_o <= '0';
s_mainFSMstate <= IRQ_PASS;
when WAIT_END =>
-- Will stay here until AS is released.
s_mainFSMstate <= WAIT_END;
when others =>
-- No-op, wait until AS is released.
s_mainFSMstate <= WAIT_END;
end case;
end if;
end if;
end process;
-- Retry is not supported
VME_RETRY_n_o <= '1';
VME_RETRY_OE_o <= '0';
-- WB Master
with g_WB_GRANULARITY select
wb_adr_o <= "00" & s_vme_addr_reg(31 downto 2) when WORD,
s_vme_addr_reg(31 downto 2) & "00" when BYTE;
wb_we_o <= not s_WRITElatched_n;
wb_dat_o <= s_locDataIn(31 downto 0);
-- Function Decoder
addr_decoder_o <= s_vme_addr_reg;
am_o <= s_AMlatched;
-- CR/CSR In/Out
cr_csr_data_o <= s_locDataIn(7 downto 0);
cr_csr_addr_o <= s_vme_addr_reg(18 downto 2);
cr_csr_we_o <= '1' when s_conf_req = '1' and
s_WRITElatched_n = '0'
else '0';
end rtl;
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/vme_cr_csr_space.vhd 0000664 0000000 0000000 00000057757 13254235275 0026160 0 ustar 00root root 0000000 0000000 --------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- VME64x Core
-- http://www.ohwr.org/projects/vme64x-core
--------------------------------------------------------------------------------
--
-- unit name: vme_cr_csr_space
--
-- author: Pablo Alvarez Sanchez
-- Davide Pedretti
--
-- description:
--
-- Implementation of CR/CSR space.
--
-- width = 1 byte
-- /---------------------------------/
-- _________________________________
-- | | 0x7ffff
-- | Defined and Reserved CSR |
-- | |
-- | Table 10-13 "Defined Control |
-- | Status register Assignments" |
-- | ANSI/VITA 1.1-1997 |
-- | VME64 Extensions |
-- |_________________________________| 0x7fc00
-- |_________________________________|
-- | | 0xXXXXX
-- | User CSR |
-- |_________________________________| 0xXXXXX
-- |_________________________________|
-- | | 0xXXXXX
-- | CRAM |
-- |_________________________________| 0xXXXXX
-- |_________________________________|
-- | | 0xXXXXX
-- | User CR |
-- |_________________________________| 0xXXXXX
-- |_________________________________|
-- | | 0x00fff
-- | Defined and reserved CR |
-- | |
-- | Table 10-12 "Defined |
-- | Configuration ROM Assignments" |
-- | ANSI/VITA 1.1-1997 |
-- | VME64 Extensions |
-- |_________________________________| 0x00000
--
-- Please note that only every fourth location in the CR/CSR space is used,
-- so it is possible read and write the CR/CSR by selecting the data transfer
-- mode D08 (byte 3), D16 (bytes 2 & 3) or D32. If other data transfer modes
-- are used the operation will not be successful.
--
-- If the size of the register is bigger than 1 byte, (e.g. ADER is 4 bytes)
-- these bytes are stored in BIG ENDIAN order.
--
-- How to use the CRAM:
--
-- 1) The Master first reads the CRAM_OWNER register (location 0x7fff3).
-- If it is zero the CRAM is available.
-- 2) The Master writes his ID to the CRAM_OWNER register.
-- 3) If the Master can readback his ID from the CRAM_OWNER register it
-- means that he is the owner of the CRAM and has exclusive access.
-- 4) If other Masters write their ID to the CRAM_OWNER register when it
-- contains a non-zero value, the write operation will not be successful.
-- This allows the first Master that writes a non-zero value to acquire
-- ownership.
-- 5) When a Master has ownership of the CRAM, bit 2 of the Bit Set Register
-- (location 0x7fffb) will be set.
-- 6) The Master can release the ownership by writing '1' to bit 2 of the
-- Bit Clr Register (location 0x7fff7).
--
-- Bit Set Register control bits (location 0x7fffb):
--
-- 7: RESET -----------> When high the module is held in reset.
-- 6: SYSFAIL ENABLE --> When high the VME_SYSFAIL output driver is enabled.
-- 5: FAILED ----------> When high the module has failed.
-- 4: ENABLE ----------> When high the WB accesses are enabled.
-- 3: BERR ------------> When high the module has asserted BERR.
-- 2: CRAM OWNER ------> When high the CRAM is owned.
--
-- The Master can clear these bits by writing '1' in the corresponding bits
-- to the Bit Clr Register (location 0x7fff7).
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file 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 source 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
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vme64x_pkg.all;
entity vme_cr_csr_space is
generic (
g_MANUFACTURER_ID : std_logic_vector(23 downto 0);
g_BOARD_ID : std_logic_vector(31 downto 0);
g_REVISION_ID : std_logic_vector(31 downto 0);
g_PROGRAM_ID : std_logic_vector(7 downto 0);
g_ASCII_PTR : std_logic_vector(23 downto 0);
g_BEG_USER_CR : std_logic_vector(23 downto 0);
g_END_USER_CR : std_logic_vector(23 downto 0);
g_BEG_CRAM : std_logic_vector(23 downto 0);
g_END_CRAM : std_logic_vector(23 downto 0);
g_BEG_USER_CSR : std_logic_vector(23 downto 0);
g_END_USER_CSR : std_logic_vector(23 downto 0);
g_BEG_SN : std_logic_vector(23 downto 0);
g_END_SN : std_logic_vector(23 downto 0);
g_DECODER : t_vme64x_decoder_arr);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
vme_ga_i : in std_logic_vector(5 downto 0);
vme_berr_n_i : in std_logic;
bar_o : out std_logic_vector(4 downto 0);
module_enable_o : out std_logic;
module_reset_o : out std_logic;
addr_i : in std_logic_vector(18 downto 2);
data_i : in std_logic_vector( 7 downto 0);
data_o : out std_logic_vector( 7 downto 0);
we_i : in std_logic;
user_csr_addr_o : out std_logic_vector(18 downto 2);
user_csr_data_i : in std_logic_vector( 7 downto 0);
user_csr_data_o : out std_logic_vector( 7 downto 0);
user_csr_we_o : out std_logic;
user_cr_addr_o : out std_logic_vector(18 downto 2);
user_cr_data_i : in std_logic_vector( 7 downto 0);
ader_o : out t_ader_array);
end vme_cr_csr_space;
architecture rtl of vme_cr_csr_space is
signal s_addr : unsigned(18 downto 2);
signal s_ga_parity : std_logic;
signal s_reg_bar : std_logic_vector(7 downto 0);
signal s_reg_bit_reg : std_logic_vector(7 downto 0);
signal s_reg_cram_owner : std_logic_vector(7 downto 0);
signal s_reg_usr_bit_reg : std_logic_vector(7 downto 0);
-- It is expected to have unconnected bits in this register, since they
-- are and'ed with ADEM bits (so some are always 0).
signal s_reg_ader : t_ader_array(ader_o'range);
-- CR/CSR
signal s_cr_access : std_logic;
signal s_csr_access : std_logic;
signal s_cram_access : std_logic;
signal s_user_cr_access : std_logic;
signal s_user_csr_access : std_logic;
signal s_cr_data : std_logic_vector(7 downto 0);
signal s_csr_data : std_logic_vector(7 downto 0);
-- Function to calculate the size of a CR/CSR area
function f_size (s, e : std_logic_vector) return integer is
begin
return ((to_integer(unsigned(e)) - to_integer(unsigned(s))) / 4) + 1;
end;
-- User CR/CSR and CRAM enabled when size of area greater than 1
constant c_CRAM_SIZE : integer := f_size(g_BEG_CRAM, g_END_CRAM);
constant c_CRAM_ENA : boolean := c_CRAM_SIZE > 1;
constant c_USER_CR_SIZE : integer := f_size(g_BEG_USER_CR, g_END_USER_CR);
constant c_USER_CR_ENA : boolean := c_USER_CR_SIZE > 1;
constant c_USER_CSR_SIZE : integer := f_size(g_BEG_USER_CSR, g_END_USER_CSR);
constant c_USER_CSR_ENA : boolean := c_USER_CSR_SIZE > 1;
-- ADER bits to be stored, in addition to the corresponding ADEM ones.
-- (ie AM + XAM).
constant c_ADER_MASK : std_logic_vector(31 downto 0) := x"0000_00fd";
-- Corresponding ADEM bits.
constant c_ADEM_MASK : std_logic_vector(31 downto 0) := x"ffff_ff00";
-- CRAM
type t_cram is array (c_CRAM_SIZE-1 downto 0) of std_logic_vector(7 downto 0);
signal s_cram : t_cram;
signal s_cram_data : std_logic_vector(7 downto 0);
signal s_cram_waddr : unsigned(18 downto 2);
signal s_cram_raddr : unsigned(18 downto 2);
signal s_cram_we : std_logic;
-- Addresses
subtype crcsr_addr is unsigned(18 downto 2);
constant c_BEG_CR : crcsr_addr := to_unsigned(16#00000# / 4, 17);
constant c_END_CR : crcsr_addr := to_unsigned(16#00fff# / 4, 17);
constant c_BEG_CSR : crcsr_addr := to_unsigned(16#7ff60# / 4, 17);
constant c_END_CSR : crcsr_addr := to_unsigned(16#7ffff# / 4, 17);
constant c_BEG_USER_CR : crcsr_addr := unsigned(g_BEG_USER_CR(18 downto 2));
constant c_END_USER_CR : crcsr_addr := unsigned(g_END_USER_CR(18 downto 2));
constant c_BEG_USER_CSR : crcsr_addr := unsigned(g_BEG_USER_CSR(18 downto 2));
constant c_END_USER_CSR : crcsr_addr := unsigned(g_END_USER_CSR(18 downto 2));
constant c_BEG_CRAM : crcsr_addr := unsigned(g_BEG_CRAM(18 downto 2));
constant c_END_CRAM : crcsr_addr := unsigned(g_END_CRAM(18 downto 2));
-- Indexes in bit set/clr register
constant c_RESET_BIT : integer := 7;
constant c_SYSFAIL_EN_BIT : integer := 6;
constant c_FAILED_BIT : integer := 5;
constant c_ENABLE_BIT : integer := 4;
constant c_BERR_BIT : integer := 3;
constant c_CRAM_OWNER_BIT : integer := 2;
-- Value for unused memory locations
constant c_UNUSED : std_logic_vector(7 downto 0) := x"ff";
------------------------------------------------------------------------------
-- Generate configuration ROM
------------------------------------------------------------------------------
type t_cr_array is array (natural range <>) of std_logic_vector(7 downto 0);
-- Function to generate a CR sub-array from a std_logic_vector
function f_cr_vec (v : std_logic_vector) return t_cr_array is
variable a : t_cr_array(0 to v'length / 8 - 1);
begin
for i in 0 to a'length-1 loop
a(i) := v(v'length - (i*8) - 1 downto v'length - (i*8) - 8);
end loop;
return a;
end function;
-- Function to encode the configuration ROM
function f_cr_encode return t_cr_array is
variable cr : t_cr_array(0 to 511) := (others => x"00");
variable crc : unsigned(7 downto 0) := x"00";
begin
cr(16#001# to 16#003#) := (x"00", x"03", x"ff"); -- Length of CR
cr(16#004#) := x"81"; -- CR DAW
cr(16#005#) := x"81"; -- CSR DAW
cr(16#006#) := x"02"; -- CR/CSR spec id
cr(16#007#) := x"43"; -- ASCII "C"
cr(16#008#) := x"52"; -- ASCII "R"
cr(16#009# to 16#00b#) := f_cr_vec(g_MANUFACTURER_ID); -- Manufacturer ID
cr(16#00c# to 16#00f#) := f_cr_vec(g_BOARD_ID); -- Board ID
cr(16#010# to 16#013#) := f_cr_vec(g_REVISION_ID); -- Revision ID
cr(16#014# to 16#016#) := f_cr_vec(g_ASCII_PTR); -- String ptr
cr(16#01f#) := g_PROGRAM_ID; -- Program ID
cr(16#020# to 16#022#) := f_cr_vec(g_BEG_USER_CR); -- Beg user CR
cr(16#023# to 16#025#) := f_cr_vec(g_END_USER_CR); -- End user CR
cr(16#026# to 16#028#) := f_cr_vec(g_BEG_CRAM); -- Beg CRAM
cr(16#029# to 16#02b#) := f_cr_vec(g_END_CRAM); -- End CRAM
cr(16#02c# to 16#02e#) := f_cr_vec(g_BEG_USER_CSR); -- Beg user CSR
cr(16#02f# to 16#031#) := f_cr_vec(g_END_USER_CSR); -- End user CSR
cr(16#032# to 16#034#) := f_cr_vec(g_BEG_SN); -- Beg serial number
cr(16#035# to 16#037#) := f_cr_vec(g_END_SN); -- End serial number
cr(16#038#) := x"04"; -- Slave param
cr(16#039#) := x"00"; -- User-defined
cr(16#03d#) := x"0e"; -- Interrupt cap
cr(16#03f#) := x"81"; -- CRAM DAW
for i in 0 to 7 loop
cr(16#040# + i) := g_decoder(i).dawpr;
cr(16#048# + i*8 to 16#04f# + i*8) := f_cr_vec(g_decoder(i).amcap);
cr(16#188# + i*4 to 16#18b# + i*4) := f_cr_vec(g_decoder(i).adem);
end loop;
for i in cr'range loop
crc := crc + unsigned(cr(i));
end loop;
cr(16#000#) := std_logic_vector(crc); -- Checksum
return cr;
end;
constant s_cr_rom : t_cr_array(0 to 511) := f_cr_encode;
------------------------------------------------------------------------------
begin
s_addr <= unsigned(addr_i);
------------------------------------------------------------------------------
-- Defined CR
------------------------------------------------------------------------------
s_cr_access <= '1' when s_addr >= c_BEG_CR and
s_addr <= c_END_CR
else '0';
process (clk_i)
begin
if rising_edge(clk_i) then
if s_addr(11) = '0' then
s_cr_data <= s_cr_rom(to_integer(s_addr(10 downto 2)));
else
s_cr_data <= x"00";
end if;
end if;
end process;
------------------------------------------------------------------------------
-- Defined CSR
------------------------------------------------------------------------------
s_csr_access <= '1' when s_addr >= c_BEG_CSR and
s_addr <= c_END_CSR
else '0';
-- If the crate is not driving the GA lines or the parity is even the BAR
-- register is set to 0x00 and the board will not answer CR/CSR accesses.
s_ga_parity <= vme_ga_i(5) xor vme_ga_i(4) xor vme_ga_i(3) xor
vme_ga_i(2) xor vme_ga_i(1) xor vme_ga_i(0);
-- Write
process (clk_i)
-- Write to ADER bytes, if implemented. Take advantage of VITAL-1-1 Rule
-- 10.19
procedure Set_ADER (idx : natural range 0 to 7) is
variable v_byte : integer;
begin
if idx <= ader_o'high then
v_byte := 3 - to_integer(s_addr(3 downto 2));
s_reg_ader(idx)(8*v_byte + 7 downto 8*v_byte) <= data_i;
end if;
end Set_ADER;
variable csr_idx : unsigned(7 downto 4);
variable csr_boff : unsigned(3 downto 2);
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
if s_ga_parity = '1' then
s_reg_bar <= (not vme_ga_i(4 downto 0)) & "000";
else
s_reg_bar <= x"00";
end if;
s_reg_bit_reg <= x"00";
s_reg_cram_owner <= x"00";
s_reg_usr_bit_reg <= x"00";
s_reg_ader <= (others => x"00000000");
else
if we_i = '1' and s_csr_access = '1' then
-- FIXME: the SVEC linux driver assume that this bit is just a
-- pulse, and doesn't clear it. Follow this legacy (and incorrect)
-- behaviour to be compatible with the driver. The reset bit will
-- be cleared at the next CSR write access.
s_reg_bit_reg(c_RESET_BIT) <= '0';
csr_idx := s_addr(7 downto 4);
csr_boff := s_addr(3 downto 2);
case csr_idx is
when x"f" =>
case csr_boff is
when "11" => -- BAR
s_reg_bar <= data_i;
when "10" => -- Bit Set
s_reg_bit_reg <= s_reg_bit_reg or data_i;
when "01" => -- Bit Clr
s_reg_bit_reg <= s_reg_bit_reg and not data_i;
-- VITAL-1-1 Rule 10.27
-- 4) Ownership shall be released by writing any value with
-- bit 2 set (eg 0x04) to the CSR Bit Clear Register
-- located at 0x7fff7. This clears the CRAM_OWNER
-- register and leaves it with a value of zero and also
-- clears the CRAM owned status.
if data_i(c_CRAM_OWNER_BIT) = '1' then
s_reg_cram_owner <= x"00";
end if;
when "00" => -- CRAM_OWNER
-- VITAL-1-1 Rule 10.27
-- 2) Writing to CRAM_OWNER register when it contains a non-
-- zero value shall not change the value of the
-- CRAM_OWNER. That allows the first master that writes
-- a non-zero value to acquire ownership.
if s_reg_cram_owner = x"00" then
s_reg_cram_owner <= data_i;
s_reg_bit_reg(c_CRAM_OWNER_BIT) <= '1';
end if;
when others =>
null;
end case;
when x"e" =>
case csr_boff is
when "11" => -- User Set
s_reg_usr_bit_reg <= s_reg_usr_bit_reg or data_i;
when "10" => -- User Clr
s_reg_usr_bit_reg <= s_reg_usr_bit_reg and not data_i;
when others =>
null;
end case;
-- Decompose ADER so that unimplemented one can be removed.
when x"d" => -- ADER 7
Set_ADER(7);
when x"c" => -- ADER 6
Set_ADER(6);
when x"b" => -- ADER 5
Set_ADER(5);
when x"a" => -- ADER 4
Set_ADER(4);
when x"9" => -- ADER 3
Set_ADER(3);
when x"8" => -- ADER 2
Set_ADER(2);
when x"7" => -- ADER 1
Set_ADER(1);
when x"6" => -- ADER 0
Set_ADER(0);
when others =>
null;
end case;
end if;
if vme_berr_n_i = '0' then
s_reg_bit_reg(c_BERR_BIT) <= '1';
end if;
-- Could handle sysfail (if it was supported).
end if;
end if;
end process;
bar_o <= s_reg_bar(7 downto 3);
module_enable_o <= s_reg_bit_reg(c_ENABLE_BIT);
module_reset_o <= s_reg_bit_reg(c_RESET_BIT);
-- Only keep ADER bits that are used for comparison. Save a little bit of
-- resources.
gen_ader_o: for i in s_reg_ader'range generate
ader_o (i) <=
s_reg_ader (i) and ((g_decoder(i).adem and c_ADEM_MASK) or c_ADER_MASK);
end generate;
-- Read
process (clk_i)
procedure Get_ADER(idx : natural range 0 to 7)
is
variable v_byte : integer;
variable ader : std_logic_vector(31 downto 0);
begin
if idx <= ader_o'high then
v_byte := 3 - to_integer(s_addr(3 downto 2));
ader := s_reg_ader(idx)
and ((g_decoder(idx).adem and c_ADEM_MASK) or c_ADER_MASK);
s_csr_data <= ader(8*v_byte + 7 downto 8*v_byte);
end if;
end Get_ADER;
variable csr_idx : unsigned(7 downto 4);
variable csr_boff : unsigned(3 downto 2);
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
s_csr_data <= x"00";
else
-- VITAL-1-1 Rule 10.14
-- All unimplemented locations in the Defined CSR Area shall read as
-- 0x00
s_csr_data <= x"00";
csr_idx := s_addr(7 downto 4);
csr_boff := s_addr(3 downto 2);
case csr_idx is
when x"f" =>
case csr_boff is
when "11" => -- BAR
s_csr_data <= s_reg_bar;
when "10" => -- Bit Set
s_csr_data <= s_reg_bit_reg;
when "01" => -- Bit Clr
s_csr_data <= s_reg_bit_reg;
when "00" => -- CRAM_OWNER
s_csr_data <= s_reg_cram_owner;
when others =>
null;
end case;
when x"e" =>
case csr_boff is
when "11" => -- User Set
s_csr_data <= s_reg_usr_bit_reg;
when "10" => -- User Clr
s_csr_data <= s_reg_usr_bit_reg;
when others =>
null;
end case;
-- Unroll to disable unused ADER. Not the best readable style.
when x"d" =>
Get_ADER(7);
when x"c" =>
Get_ADER(6);
when x"b" =>
Get_ADER(5);
when x"a" =>
Get_ADER(4);
when x"9" =>
Get_ADER(3);
when x"8" =>
Get_ADER(2);
when x"7" =>
Get_ADER(1);
when x"6" =>
Get_ADER(0);
when others =>
null;
end case;
end if;
end if;
end process;
------------------------------------------------------------------------------
-- CRAM
------------------------------------------------------------------------------
gen_cram_ena: if c_CRAM_ENA = true generate
s_cram_access <= '1' when s_addr >= c_BEG_CRAM and
s_addr <= c_END_CRAM
else '0';
s_cram_we <= we_i and s_cram_access;
s_cram_waddr <= s_addr - c_BEG_CRAM;
s_cram_data <= s_cram(to_integer(s_cram_raddr) mod c_CRAM_SIZE);
process (clk_i)
begin
if rising_edge(clk_i) then
if s_cram_we = '1' then
s_cram(to_integer(s_cram_waddr)) <= data_i;
end if;
s_cram_raddr <= s_cram_waddr;
end if;
end process;
end generate;
gen_cram_dis: if c_CRAM_ENA = false generate
s_cram_access <= '0';
s_cram_raddr <= (others => '0');
s_cram_waddr <= (others => '0');
s_cram_data <= x"00";
end generate;
------------------------------------------------------------------------------
-- User CR
------------------------------------------------------------------------------
gen_user_cr_ena: if c_USER_CR_ENA = true generate
s_user_cr_access <= '1' when s_addr >= c_BEG_USER_CR and
s_addr <= c_END_USER_CR
else '0';
user_cr_addr_o <= std_logic_vector(s_addr - c_BEG_USER_CR);
end generate;
gen_user_cr_dis: if c_USER_CR_ENA = false generate
s_user_cr_access <= '0';
user_cr_addr_o <= (others => '0');
end generate;
------------------------------------------------------------------------------
-- User CSR
------------------------------------------------------------------------------
gen_user_csr_ena: if c_USER_CSR_ENA = true generate
s_user_csr_access <= '1' when s_addr >= c_BEG_USER_CSR and
s_addr <= c_END_USER_CSR
else '0';
user_csr_addr_o <= std_logic_vector(s_addr - c_BEG_USER_CSR);
end generate;
gen_user_csr_dis: if c_USER_CSR_ENA = false generate
s_user_csr_access <= '0';
user_csr_addr_o <= (others => '0');
end generate;
user_csr_data_o <= data_i;
user_csr_we_o <= we_i and s_user_csr_access;
------------------------------------------------------------------------------
-- Read multiplexer
------------------------------------------------------------------------------
process (
s_cr_access, s_cr_data,
s_csr_access, s_csr_data,
s_cram_access, s_cram_data,
s_user_cr_access, user_cr_data_i,
s_user_csr_access, user_csr_data_i)
begin
if s_cr_access = '1' then
data_o <= s_cr_data;
elsif s_csr_access = '1' then
data_o <= s_csr_data;
elsif s_cram_access = '1' then
data_o <= s_cram_data;
elsif s_user_cr_access = '1' then
data_o <= user_cr_data_i;
elsif s_user_csr_access = '1' then
data_o <= user_csr_data_i;
else
data_o <= c_UNUSED;
end if;
end process;
end rtl;
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/vme_funct_match.vhd 0000664 0000000 0000000 00000011423 13254235275 0026001 0 ustar 00root root 0000000 0000000 --------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- VME64x Core
-- http://www.ohwr.org/projects/vme64x-core
--------------------------------------------------------------------------------
--
-- unit name: vme_funct_match
--
-- description:
--
-- VME function decoder. Check if the VME address+AM has to be handled by
-- this VME slave according to ADER and decoder values. Gives back the
-- corresponding WB address.
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file 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 source 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
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vme64x_pkg.all;
entity vme_funct_match is
generic (
g_DECODER : t_vme64x_decoder_arr;
g_DECODE_AM : boolean
);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
-- Input address (to be decoded).
addr_i : in std_logic_vector(31 downto 1);
-- Sub-address of the function (the part not masked by adem).
addr_o : out std_logic_vector(31 downto 1);
decode_start_i : in std_logic;
am_i : in std_logic_vector( 5 downto 0);
ader_i : in t_ader_array;
-- Set when a function is selected.
decode_sel_o : out std_logic;
-- Set when sel_o is valid (decoding is done).
decode_done_o : out std_logic
);
end vme_funct_match;
architecture rtl of vme_funct_match is
-- Function index and ADEM from priority encoder
signal s_function_sel : natural range ader_i'range;
signal s_function_sel_valid : std_logic;
signal s_decode_start_1 : std_logic;
-- Selected function
signal s_function : std_logic_vector(ader_i'range);
signal s_ader_am_valid : std_logic_vector(ader_i'range);
begin
------------------------------------------------------------------------------
-- Address and AM comparators
------------------------------------------------------------------------------
gen_match_loop : for i in ader_i'range generate
-- True in case of match
s_function(i) <=
'1' when (((addr_i(t_ADEM_M) and g_decoder(i).adem(t_ADEM_M))
= ader_i(i)(t_ADEM_M))
and ((am_i = ader_i(i)(t_ADER_AM))
or not g_DECODE_AM))
else '0';
-- True if the AM part of ADER is enabled by AMCAP
s_ader_am_valid(i) <=
g_decoder(i).amcap(to_integer(unsigned(ader_i(i)(t_ADER_AM))));
end generate;
------------------------------------------------------------------------------
-- Function priority encoder
------------------------------------------------------------------------------
process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' or decode_start_i = '0' then
s_decode_start_1 <= '0';
s_function_sel <= 0;
s_function_sel_valid <= '0';
else
s_decode_start_1 <= '1';
for i in ader_i'range loop
if s_function(i) = '1' then
s_function_sel <= i;
s_function_sel_valid <= s_ader_am_valid(i);
exit;
end if;
end loop;
end if;
end if;
end process;
------------------------------------------------------------------------------
-- Address output latch
------------------------------------------------------------------------------
process (clk_i) is
variable mask : std_logic_vector(31 downto 1);
begin
if rising_edge(clk_i) then
if rst_n_i = '0' or s_decode_start_1 = '0' then
addr_o <= (others => '0');
decode_done_o <= '0';
decode_sel_o <= '0';
else
-- s_decode_start_1 is set.
decode_done_o <= '1';
if s_function_sel_valid = '1' then
mask := (others => '0');
mask(t_ADEM_M) := g_decoder(s_function_sel).adem(t_ADEM_M);
addr_o <= addr_i and not mask;
decode_sel_o <= '1';
else
decode_sel_o <= '0';
end if;
end if;
end if;
end process;
end rtl;
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/vme_irq_controller.vhd 0000664 0000000 0000000 00000010736 13254235275 0026552 0 ustar 00root root 0000000 0000000 --------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- VME64x Core
-- http://www.ohwr.org/projects/vme64x-core
--------------------------------------------------------------------------------
--
-- unit name: vme_irq_controller
--
-- description:
--
-- This block implements the interrupt controller. It passes the interrupt
-- pulse from WB to the corresponding IRQ signal on the VME bus, until
-- the interrupt is acknowledged by the VME master.
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file 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 source 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
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vme64x_pkg.all;
entity vme_irq_controller is
generic (
g_RETRY_TIMEOUT : integer range 1024 to 16777215
);
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
INT_Level_i : in std_logic_vector (2 downto 0);
INT_Req_i : in std_logic;
-- Set when an irq is pending (not yet acknowledged).
irq_pending_o : out std_logic;
irq_ack_i : in std_logic;
VME_IRQ_n_o : out std_logic_vector (7 downto 1)
);
end vme_irq_controller;
architecture rtl of vme_irq_controller is
type t_retry_state is (WAIT_IRQ, WAIT_RETRY);
signal retry_state : t_retry_state;
signal retry_count : unsigned(23 downto 0);
signal retry_mask : std_logic;
signal s_irq_pending : std_logic;
begin
irq_pending_o <= s_irq_pending;
-- Interrupts are automatically masked for g_RETRY_TIMEOUT (i.e. 1 ms) once
-- they are acknowledged by the interrupt handler until they are deasserted
-- by the interrupter.
p_retry_fsm : process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
retry_mask <= '1';
retry_state <= WAIT_IRQ;
else
case retry_state is
when WAIT_IRQ =>
if s_irq_pending = '1' and INT_Req_i = '1' then
retry_state <= WAIT_RETRY;
retry_count <= (others => '0');
retry_mask <= '0';
else
retry_mask <= '1';
end if;
when WAIT_RETRY =>
if INT_Req_i = '0' then
retry_state <= WAIT_IRQ;
else
retry_count <= retry_count + 1;
if retry_count = g_RETRY_TIMEOUT then
retry_state <= WAIT_IRQ;
end if;
end if;
end case;
end if;
end if;
end process;
p_main : process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
VME_IRQ_n_o <= (others => '1');
s_irq_pending <= '0';
else
if s_irq_pending = '0' then
VME_IRQ_n_o <= (others => '1');
if INT_Req_i = '1' and retry_mask = '1' then
s_irq_pending <= '1';
-- Explicit decoding
case INT_Level_i is
when "001" => VME_IRQ_n_o <= "1111110";
when "010" => VME_IRQ_n_o <= "1111101";
when "011" => VME_IRQ_n_o <= "1111011";
when "100" => VME_IRQ_n_o <= "1110111";
when "101" => VME_IRQ_n_o <= "1101111";
when "110" => VME_IRQ_n_o <= "1011111";
when "111" => VME_IRQ_n_o <= "0111111";
when others =>
-- Incorrect value for INT_Level_i, ignore it.
VME_IRQ_n_o <= "1111111";
s_irq_pending <= '0';
end case;
end if;
else
if irq_ack_i = '1' then
s_irq_pending <= '0';
end if;
end if;
end if;
end if;
end process;
end rtl;
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/vme_user_csr.vhd 0000664 0000000 0000000 00000007533 13254235275 0025342 0 ustar 00root root 0000000 0000000 --------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- VME64x Core
-- http://www.ohwr.org/projects/vme64x-core
--------------------------------------------------------------------------------
--
-- unit name: vme_user_csr
--
-- description:
--
-- This module implements the user CSR registers that were added to the
-- reserved area of the defined CSR in previous versions of this core.
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file 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 source 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
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vme64x_pkg.all;
entity vme_user_csr is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
addr_i : in std_logic_vector(18 downto 2);
data_i : in std_logic_vector( 7 downto 0);
data_o : out std_logic_vector( 7 downto 0);
we_i : in std_logic;
irq_vector_o : out std_logic_vector( 7 downto 0);
irq_level_o : out std_logic_vector( 2 downto 0)
);
end VME_User_CSR;
architecture rtl of VME_User_CSR is
signal s_irq_vector : std_logic_vector(7 downto 0);
signal s_irq_level : std_logic_vector(2 downto 0);
-- Value for unused memory locations
constant c_UNUSED : std_logic_vector(7 downto 0) := x"ff";
-- Addresses
constant c_IRQ_VECTOR : integer := 16#0002f# / 4;
constant c_IRQ_LEVEL : integer := 16#0002b# / 4;
constant c_ENDIAN : integer := 16#00023# / 4;
-- Now unused.
-- constant c_TIME0_NS : integer := 16#0001f# / 4;
-- constant c_TIME1_NS : integer := 16#0001b# / 4;
-- constant c_TIME2_NS : integer := 16#00017# / 4;
-- constant c_TIME3_NS : integer := 16#00013# / 4;
-- constant c_TIME4_NS : integer := 16#0000f# / 4;
-- constant c_BYTES0 : integer := 16#0000b# / 4;
-- constant c_BYTES1 : integer := 16#00007# / 4;
constant c_WB32BITS : integer := 16#00003# / 4;
begin
-- Write
process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
s_irq_vector <= x"00";
s_irq_level <= "000";
else
if we_i = '1' then
case to_integer(unsigned(addr_i)) is
when c_IRQ_VECTOR => s_irq_vector <= data_i;
when c_IRQ_LEVEL => s_irq_level <= data_i(2 downto 0);
when others => null;
end case;
end if;
end if;
end if;
end process;
irq_vector_o <= s_irq_vector;
irq_level_o <= s_irq_level;
-- Read
process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
data_o <= x"00";
else
case to_integer(unsigned(addr_i)) is
when c_IRQ_VECTOR => data_o <= s_irq_vector;
when c_IRQ_LEVEL => data_o <= "00000" & s_irq_level;
when c_ENDIAN => data_o <= x"00";
when c_WB32BITS => data_o <= x"01";
when others => data_o <= c_UNUSED;
end case;
end if;
end if;
end process;
end rtl;
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/rtl/xvme64x_core.vhd 0000664 0000000 0000000 00000043206 13254235275 0025174 0 ustar 00root root 0000000 0000000 --------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- VME64x Core
-- http://www.ohwr.org/projects/vme64x-core
--------------------------------------------------------------------------------
--
-- unit name: xvme64x_core (xvme64x_core.vhd)
--
-- description:
--
-- This core implements an interface to transfer data between the VMEbus and
-- the WBbus. This core is a Slave in the VME side and Master in the WB side.
--
-- All the output signals on the WB bus are registered.
-- The Input signals from the WB bus aren't registered indeed the WB is a
-- synchronous protocol and some registers in the WB side will introduce a
-- delay that make impossible reproduce the WB PIPELINED protocol.
-- The main component of this core is the VME_bus on the left in the block
-- diagram. Inside this component you can find the main finite state machine
-- that coordinates all the synchronisms.
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file 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 source 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
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.wishbone_pkg.all;
use work.vme64x_pkg.all;
entity xvme64x_core is
generic (
-- Clock period (ns). Used for DS synchronization. A value is required.
g_CLOCK_PERIOD : natural;
-- Consider AM field of ADER to decode addresses. This is what the VME64x
-- standard says. However, for compatibility with previous implementations
-- (or to reduce resources), it is possible for a decoder to allow all AM
-- declared in the AMCAP.
g_DECODE_AM : boolean := true;
-- Use external user CSR
g_USER_CSR_EXT : boolean := false;
-- Address granularity on the WB bus. Value can be:
-- WORD: VME address bits 31:2 are translated to WB address bits 29:0,
-- the WB data represents bytes for VME address bits 1:0.
-- BYTE: VME address bits 31:2 are translated to WB address bits 31:2,
-- WB address bits 1:0 are always 0.
g_WB_GRANULARITY : t_wishbone_address_granularity;
-- Manufacturer ID: IEEE OUID
-- e.g. CERN is 0x080030
g_MANUFACTURER_ID : std_logic_vector(23 downto 0);
-- Board ID: Per manufacturer, each board shall have an unique ID
-- e.g. SVEC = 408 (CERN IDs: http://cern.ch/boardid)
g_BOARD_ID : std_logic_vector(31 downto 0);
-- Revision ID: user defined revision code
g_REVISION_ID : std_logic_vector(31 downto 0);
-- Program ID: Defined per VME64:
-- 0x00 = Not used
-- 0x01 = No program, ID ROM only
-- 0x02-0x4F = Manufacturer defined
-- 0x50-0x7F = User defined
-- 0x80-0xEF = Reserved for future use
-- 0xF0-0xFE = Reserved for Boot Firmware (P1275)
-- 0xFF = Not to be used
g_PROGRAM_ID : std_logic_vector( 7 downto 0);
-- Pointer to a user defined ASCII string.
g_ASCII_PTR : std_logic_vector(23 downto 0) := x"000000";
-- User CR/CSR, CRAM & serial number pointers
g_BEG_USER_CR : std_logic_vector(23 downto 0) := x"000000";
g_END_USER_CR : std_logic_vector(23 downto 0) := x"000000";
g_BEG_CRAM : std_logic_vector(23 downto 0) := x"000000";
g_END_CRAM : std_logic_vector(23 downto 0) := x"000000";
g_BEG_USER_CSR : std_logic_vector(23 downto 0) := x"07ff33";
g_END_USER_CSR : std_logic_vector(23 downto 0) := x"07ff5f";
g_BEG_SN : std_logic_vector(23 downto 0) := x"000000";
g_END_SN : std_logic_vector(23 downto 0) := x"000000";
-- Function decoder parameters.
g_DECODER : t_vme64x_decoder_arr := c_vme64x_decoders_default);
port (
-- Main clock and reset.
clk_i : in std_logic;
rst_n_i : in std_logic;
-- Reset for wishbone core.
rst_n_o : out std_logic;
-- VME slave interface.
vme_i : in t_vme64x_in;
vme_o : out t_vme64x_out;
-- Wishbone interface.
wb_i : in t_wishbone_master_in;
wb_o : out t_wishbone_master_out;
-- Interrupt input from the master side.
-- Previously it was part of the wishbone interface, but is now separate
-- as interrupt is not defined by wishbone.
int_i : in std_logic := '0';
-- When the IRQ controller acknowledges the Interrupt cycle it sends a
-- pulse to the IRQ Generator.
irq_ack_o : out std_logic;
-- User CSR
-- The following signals are used when g_USER_CSR_EXT = true
-- otherwise they are connected to the internal user CSR.
irq_level_i : in std_logic_vector( 2 downto 0) := (others => '0');
irq_vector_i : in std_logic_vector( 7 downto 0) := (others => '0');
user_csr_addr_o : out std_logic_vector(18 downto 2);
user_csr_data_i : in std_logic_vector( 7 downto 0) := (others => '0');
user_csr_data_o : out std_logic_vector( 7 downto 0);
user_csr_we_o : out std_logic;
-- User CR
user_cr_addr_o : out std_logic_vector(18 downto 2);
user_cr_data_i : in std_logic_vector( 7 downto 0) := (others => '0'));
end xvme64x_core;
architecture rtl of xvme64x_core is
-- Compute the index of the last function decoder used. Assume sequential
-- use of decoders (ie decoders 0 to N - 1 are used, and decoders N to 7
-- are not used; holes are supported but not efficiently).
function compute_last_ader (decoder : t_vme64x_decoder_arr)
return t_vme_func_index is
begin
for i in decoder'reverse_range loop
if decoder(i).adem /= x"0000_0000" then
return i;
end if;
end loop;
assert false report "no ADEM defined" severity failure;
return 0;
end compute_last_ader;
constant c_last_ader : natural := compute_last_ader (g_DECODER);
signal s_reset_n : std_logic;
signal s_VME_IRQ_n_o : std_logic_vector( 7 downto 1);
signal s_irq_ack : std_logic;
signal s_irq_pending : std_logic;
-- CR/CSR
signal s_cr_csr_addr : std_logic_vector(18 downto 2);
signal s_cr_csr_data_o : std_logic_vector( 7 downto 0);
signal s_cr_csr_data_i : std_logic_vector( 7 downto 0);
signal s_cr_csr_we : std_logic;
signal s_ader : t_ader_array(0 to c_last_ader);
signal s_module_reset : std_logic;
signal s_module_enable : std_logic;
signal s_bar : std_logic_vector( 4 downto 0);
signal s_vme_berr_n : std_logic;
signal s_irq_vector : std_logic_vector( 7 downto 0);
signal s_irq_level : std_logic_vector( 2 downto 0);
signal s_user_csr_addr : std_logic_vector(18 downto 2);
signal s_user_csr_data_i : std_logic_vector( 7 downto 0);
signal s_user_csr_data_o : std_logic_vector( 7 downto 0);
signal s_user_csr_we : std_logic;
-- Function decoders
signal s_addr_decoder_i : std_logic_vector(31 downto 1);
signal s_addr_decoder_o : std_logic_vector(31 downto 1);
signal s_decode_start : std_logic;
signal s_decode_done : std_logic;
signal s_decode_sel : std_logic;
signal s_am : std_logic_vector( 5 downto 0);
-- Oversampled input signals
signal s_VME_RST_n : std_logic;
signal s_VME_AS_n : std_logic;
signal s_VME_WRITE_n : std_logic;
signal s_VME_DS_n : std_logic_vector(1 downto 0);
signal s_VME_IACK_n : std_logic;
signal s_VME_IACKIN_n : std_logic;
-- List of supported AM.
constant c_AMCAP_ALLOWED : std_logic_vector(63 downto 0) :=
(16#38# to 16#3f# => '1', -- A24
16#2d# | 16#29# => '1', -- A16
16#08# to 16#0f# => '1', -- A32
others => '0');
begin
assert g_CLOCK_PERIOD > 0 report "g_CLOCK_PERIOD generic must be set"
severity failure;
-- Check for invalid bits in ADEM/AMCAP
gen_gchecks: for i in 7 downto 0 generate
constant adem : std_logic_vector(31 downto 0) := g_decoder(i).adem;
constant amcap : std_logic_vector(63 downto 0) := g_decoder(i).amcap;
begin
assert adem(c_ADEM_FAF) = '0' report "FAF bit set in ADEM"
severity failure;
assert adem(c_ADEM_DFS) = '0' report "DFS bit set in ADEM"
severity failure;
assert adem(c_ADEM_EFM) = '0' report "EFM bit set in ADEM"
severity failure;
assert (amcap and c_AMCAP_ALLOWED) = amcap
report "bit set in AMCAP for not supported AM"
severity failure;
end generate;
------------------------------------------------------------------------------
-- Metastability
------------------------------------------------------------------------------
-- Input oversampling: oversampling the input data is
-- necessary to avoid metastability problems, but of course the transfer rate
-- will be slow down a little.
-- NOTE: the reset value is '0', which means that all signals are active
-- at reset. But not for a long time and so is s_VME_RST_n.
inst_vme_rst_resync: entity work.gc_sync_register
generic map (g_width => 1)
port map (clk_i => clk_i,
rst_n_a_i => rst_n_i,
d_i(0) => vme_i.rst_n,
q_o(0) => s_vme_rst_n);
inst_vme_as_resync: entity work.gc_sync_register
generic map (g_width => 1)
port map (clk_i => clk_i,
rst_n_a_i => rst_n_i,
d_i(0) => vme_i.as_n,
q_o(0) => s_vme_as_n);
inst_vme_write_resync: entity work.gc_sync_register
generic map (g_width => 1)
port map (clk_i => clk_i,
rst_n_a_i => rst_n_i,
d_i(0) => vme_i.write_n,
q_o(0) => s_vme_write_n);
-- The two bits of DS are synchronized by the vme_bus FSM. Instantiate two
-- synchronizers to make clear that they should be considered as independant
-- signals until they are handled by the FSM.
inst_vme_ds0_resync: entity work.gc_sync_register
generic map (g_width => 1)
port map (clk_i => clk_i,
rst_n_a_i => rst_n_i,
d_i(0) => vme_i.ds_n(0),
q_o(0) => s_vme_ds_n(0));
inst_vme_ds1_resync: entity work.gc_sync_register
generic map (g_width => 1)
port map (clk_i => clk_i,
rst_n_a_i => rst_n_i,
d_i(0) => vme_i.ds_n(1),
q_o(0) => s_vme_ds_n(1));
inst_vme_iack_resync: entity work.gc_sync_register
generic map (g_width => 1)
port map (clk_i => clk_i,
rst_n_a_i => rst_n_i,
d_i(0) => vme_i.iack_n,
q_o(0) => s_vme_iack_n);
inst_vme_iackin_resync: entity work.gc_sync_register
generic map (g_width => 1)
port map (clk_i => clk_i,
rst_n_a_i => rst_n_i,
d_i(0) => vme_i.iackin_n,
q_o(0) => s_VME_IACKIN_n);
------------------------------------------------------------------------------
-- VME Bus
------------------------------------------------------------------------------
inst_vme_bus : entity work.vme_bus
generic map (
g_CLOCK_PERIOD => g_CLOCK_PERIOD,
g_WB_GRANULARITY => g_WB_GRANULARITY)
port map (
clk_i => clk_i,
rst_n_i => s_reset_n,
-- VME
VME_AS_n_i => s_VME_AS_n,
VME_LWORD_n_o => vme_o.lword_n,
VME_LWORD_n_i => vme_i.lword_n,
VME_RETRY_n_o => vme_o.retry_n,
VME_RETRY_OE_o => vme_o.retry_oe,
VME_WRITE_n_i => s_VME_WRITE_n,
VME_DS_n_i => s_VME_DS_n,
VME_DTACK_n_o => vme_o.dtack_n,
VME_DTACK_OE_o => vme_o.dtack_oe,
VME_BERR_n_o => s_vme_berr_n,
VME_ADDR_i => vme_i.addr,
VME_ADDR_o => vme_o.addr,
VME_ADDR_DIR_o => vme_o.addr_dir,
VME_ADDR_OE_N_o => vme_o.addr_oe_n,
VME_DATA_i => vme_i.data,
VME_DATA_o => vme_o.data,
VME_DATA_DIR_o => vme_o.data_dir,
VME_DATA_OE_N_o => vme_o.data_oe_n,
VME_AM_i => vme_i.am,
VME_IACKIN_n_i => s_VME_IACKIN_n,
VME_IACK_n_i => s_VME_IACK_n,
VME_IACKOUT_n_o => vme_o.iackout_n,
-- WB signals
wb_stb_o => wb_o.stb,
wb_ack_i => wb_i.ack,
wb_dat_o => wb_o.dat,
wb_dat_i => wb_i.dat,
wb_adr_o => wb_o.adr,
wb_sel_o => wb_o.sel,
wb_we_o => wb_o.we,
wb_cyc_o => wb_o.cyc,
wb_err_i => wb_i.err,
wb_stall_i => wb_i.stall,
-- Function decoder
addr_decoder_i => s_addr_decoder_o,
addr_decoder_o => s_addr_decoder_i,
decode_start_o => s_decode_start,
decode_done_i => s_decode_done,
am_o => s_am,
decode_sel_i => s_decode_sel,
-- CR/CSR signals
cr_csr_addr_o => s_cr_csr_addr,
cr_csr_data_i => s_cr_csr_data_o,
cr_csr_data_o => s_cr_csr_data_i,
cr_csr_we_o => s_cr_csr_we,
module_enable_i => s_module_enable,
bar_i => s_bar,
INT_Level_i => s_irq_level,
INT_Vector_i => s_irq_vector,
irq_pending_i => s_irq_pending,
irq_ack_o => s_irq_ack);
s_reset_n <= rst_n_i and s_VME_RST_n;
rst_n_o <= s_reset_n and (not s_module_reset);
vme_o.berr_n <= s_vme_berr_n;
inst_vme_funct_match : entity work.vme_funct_match
generic map (
g_decoder => g_decoder,
g_DECODE_AM => g_DECODE_AM
)
port map (
clk_i => clk_i,
rst_n_i => s_reset_n,
addr_i => s_addr_decoder_i,
addr_o => s_addr_decoder_o,
decode_start_i => s_decode_start,
am_i => s_am,
ader_i => s_ader,
decode_sel_o => s_decode_sel,
decode_done_o => s_decode_done
);
------------------------------------------------------------------------------
-- Output
------------------------------------------------------------------------------
irq_ack_o <= s_irq_ack;
------------------------------------------------------------------------------
-- Interrupter
------------------------------------------------------------------------------
inst_vme_irq_controller : entity work.vme_irq_controller
generic map (
g_RETRY_TIMEOUT => 1000000 / g_CLOCK_PERIOD -- 1ms timeout
)
port map (
clk_i => clk_i,
rst_n_i => s_reset_n,
INT_Level_i => s_irq_level,
INT_Req_i => int_i,
irq_pending_o => s_irq_pending,
irq_ack_i => s_irq_ack,
VME_IRQ_n_o => vme_o.irq_n
);
------------------------------------------------------------------------------
-- CR/CSR space
------------------------------------------------------------------------------
inst_vme_cr_csr_space : entity work.vme_cr_csr_space
generic map (
g_MANUFACTURER_ID => g_MANUFACTURER_ID,
g_BOARD_ID => g_BOARD_ID,
g_REVISION_ID => g_REVISION_ID,
g_PROGRAM_ID => g_PROGRAM_ID,
g_ASCII_PTR => g_ASCII_PTR,
g_BEG_USER_CR => g_BEG_USER_CR,
g_END_USER_CR => g_END_USER_CR,
g_BEG_CRAM => g_BEG_CRAM,
g_END_CRAM => g_END_CRAM,
g_BEG_USER_CSR => g_BEG_USER_CSR,
g_END_USER_CSR => g_END_USER_CSR,
g_BEG_SN => g_BEG_SN,
g_END_SN => g_END_SN,
g_decoder => g_decoder
)
port map (
clk_i => clk_i,
rst_n_i => s_reset_n,
vme_ga_i => vme_i.ga,
vme_berr_n_i => s_vme_berr_n,
bar_o => s_bar,
module_enable_o => s_module_enable,
module_reset_o => s_module_reset,
addr_i => s_cr_csr_addr,
data_i => s_cr_csr_data_i,
data_o => s_cr_csr_data_o,
we_i => s_cr_csr_we,
user_csr_addr_o => s_user_csr_addr,
user_csr_data_i => s_user_csr_data_i,
user_csr_data_o => s_user_csr_data_o,
user_csr_we_o => s_user_csr_we,
user_cr_addr_o => user_cr_addr_o,
user_cr_data_i => user_cr_data_i,
ader_o => s_ader
);
-- User CSR space
gen_int_user_csr : if g_USER_CSR_EXT = false generate
inst_vme_user_csr : entity work.vme_user_csr
port map (
clk_i => clk_i,
rst_n_i => s_reset_n,
addr_i => s_user_csr_addr,
data_i => s_user_csr_data_o,
data_o => s_user_csr_data_i,
we_i => s_user_csr_we,
irq_vector_o => s_irq_vector,
irq_level_o => s_irq_level
);
end generate;
gen_ext_user_csr : if g_USER_CSR_EXT = true generate
s_user_csr_data_i <= user_csr_data_i;
s_irq_vector <= irq_vector_i;
s_irq_level <= irq_level_i(2 downto 0);
end generate;
user_csr_addr_o <= s_user_csr_addr;
user_csr_data_o <= s_user_csr_data_o;
user_csr_we_o <= s_user_csr_we;
assert wb_i.rty = '0' report "rty not supported";
end rtl;
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/sim/ 0000775 0000000 0000000 00000000000 13254235275 0022122 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/sim/vme64x_bfm/ 0000775 0000000 0000000 00000000000 13254235275 0024077 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/sim/vme64x_bfm/components/ 0000775 0000000 0000000 00000000000 13254235275 0026264 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/sim/vme64x_bfm/components/sn74vmeh22501.v 0000664 0000000 0000000 00000001457 13254235275 0030527 0 ustar 00root root 0000000 0000000 `timescale 1ns/1ns
module sn74vmeh22501 (
input oeab1,
oeby1_n,
a1,
output y1,
inout b1,
input oeab2,
oeby2_n,
a2,
output y2,
inout b2,
input oe_n,
input dir,
clkab,
le,
clkba,
inout [1:8] a3,
inout [1:8] b3);
assign b1 = oeab1 ? a1 : 1'bz;
assign y1 = oeby1_n ? 1'bz : b1;
assign b2 = oeab2 ? a2 : 1'bz;
assign y2 = oeby2_n ? 1'bz : b2;
reg [1:8] b3LFF;
always @(posedge clkab) if (~le) b3LFF <= #1 a3;
always @* if (le) b3LFF = a3;
assign b3 = (~oe_n && dir) ? b3LFF : 8'hz;
reg [1:8] a3LFF;
always @(posedge clkba) if (~le) a3LFF <= #1 b3;
always @* if (le) a3LFF = b3;
assign a3 = (~oe_n && ~dir) ? a3LFF : 8'hz;
endmodule
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/sim/vme64x_bfm/svec_vme_buffers.svh 0000664 0000000 0000000 00000011621 13254235275 0030145 0 ustar 00root root 0000000 0000000 `include "components/sn74vmeh22501.v"
`include "vme64x_bfm.svh"
module bidir_buf(
a,
b,
dir, /* 0: a->b, 1: b->a */
oe_n );
parameter g_width = 1;
inout [g_width-1:0] a,b;
input dir, oe_n;
assign b = (!dir && !oe_n) ? a : 'bz;
assign a = (dir && !oe_n) ? b : 'bz;
endmodule // bidir_buf
module svec_vme_buffers (
output VME_AS_n_o,
output VME_RST_n_o,
output VME_WRITE_n_o,
output [5:0] VME_AM_o,
output [1:0] VME_DS_n_o,
output [5:0] VME_GA_o,
input VME_BERR_i,
input VME_DTACK_n_i,
input VME_RETRY_n_i,
input VME_RETRY_OE_i,
inout VME_LWORD_n_b,
inout [31:1] VME_ADDR_b,
inout [31:0] VME_DATA_b,
output VME_BBSY_n_o,
input [6:0] VME_IRQ_n_i,
output VME_IACKIN_n_o,
input VME_IACKOUT_n_i,
output VME_IACK_n_o,
input VME_DTACK_OE_i,
input VME_DATA_DIR_i,
input VME_DATA_OE_N_i,
input VME_ADDR_DIR_i,
input VME_ADDR_OE_N_i,
IVME64X.slave slave
);
pullup(slave.as_n);
pullup(slave.rst_n);
pullup(slave.irq_n[0]);
pullup(slave.irq_n[1]);
pullup(slave.irq_n[2]);
pullup(slave.irq_n[3]);
pullup(slave.irq_n[4]);
pullup(slave.irq_n[5]);
pullup(slave.irq_n[6]);
pullup(slave.iack_n);
pullup(slave.dtack_n);
pullup(slave.retry_n);
pullup(slave.ds_n[1]);
pullup(slave.ds_n[0]);
pullup(slave.lword_n);
pullup(slave.berr_n);
pullup(slave.write_n);
pulldown(slave.bbsy_n);
pullup(slave.iackin_n);
pullup(slave.iackout_n);
genvar i;
generate
for(i=0;i<6;i++)
assign slave.irq_n[i] = (VME_IRQ_n_i[i] ? 1'b0 : 1'bz);
endgenerate
assign VME_RST_n_o = slave.rst_n;
assign VME_AS_n_o = slave.as_n;
assign VME_GA_o = slave.ga;
assign VME_WRITE_n_o = slave.write_n;
assign VME_AM_o = slave.am;
assign VME_DS_n_o = slave.ds_n;
assign VME_BBSY_n_o = slave.bbsy_n;
assign VME_IACKIN_n_o = slave.iackin_n;
assign VME_IACK_n_o = slave.iack_n;
bidir_buf #(1) b0 (slave.lword_n, VME_LWORD_n_b, VME_ADDR_DIR_i, VME_ADDR_OE_N_i);
bidir_buf #(31) b1 (slave.addr, VME_ADDR_b, VME_ADDR_DIR_i, VME_ADDR_OE_N_i);
bidir_buf #(33) b2 (slave.data, VME_DATA_b, VME_DATA_DIR_i, VME_DATA_OE_N_i);
pulldown(VME_BERR_i);
pulldown(VME_ADDR_DIR_i);
pulldown(VME_ADDR_OE_N_i);
pulldown(VME_DATA_DIR_i);
pulldown(VME_DATA_OE_N_i);
assign slave.dtack_n = VME_DTACK_n_i;
assign slave.berr_n = ~VME_BERR_i;
assign slave.retry_n = VME_RETRY_n_i;
assign slave.iackout_n = VME_IACKOUT_n_i;
endmodule
`define DECLARE_VME_BUFFERS(iface) \
wire VME_AS_n;\
wire VME_RST_n;\
wire VME_WRITE_n;\
wire [5:0] VME_AM;\
wire [1:0] VME_DS_n;\
wire VME_BERR;\
wire VME_DTACK_n;\
wire VME_RETRY_n;\
wire VME_RETRY_OE;\
wire VME_LWORD_n;\
wire [31:1]VME_ADDR;\
wire [31:0]VME_DATA;\
wire VME_BBSY_n;\
wire [6:0]VME_IRQ_n;\
wire VME_IACKIN_n,VME_IACK_n;\
wire VME_IACKOUT_n;\
wire VME_DTACK_OE;\
wire VME_DATA_DIR;\
wire VME_DATA_OE_N;\
wire VME_ADDR_DIR;\
wire VME_ADDR_OE_N;\
svec_vme_buffers U_VME_Bufs ( \
.VME_AS_n_o(VME_AS_n),\
.VME_RST_n_o(VME_RST_n),\
.VME_WRITE_n_o(VME_WRITE_n),\
.VME_AM_o(VME_AM),\
.VME_DS_n_o(VME_DS_n),\
.VME_BERR_i(VME_BERR),\
.VME_DTACK_n_i(VME_DTACK_n),\
.VME_RETRY_n_i(VME_RETRY_n),\
.VME_RETRY_OE_i(VME_RETRY_OE),\
.VME_LWORD_n_b(VME_LWORD_n),\
.VME_ADDR_b(VME_ADDR),\
.VME_DATA_b(VME_DATA),\
.VME_BBSY_n_o(VME_BBSY_n),\
.VME_IRQ_n_i(VME_IRQ_n),\
.VME_IACK_n_o(VME_IACK_n),\
.VME_IACKIN_n_o(VME_IACKIN_n),\
.VME_IACKOUT_n_i(VME_IACKOUT_n),\
.VME_DTACK_OE_i(VME_DTACK_OE),\
.VME_DATA_DIR_i(VME_DATA_DIR),\
.VME_DATA_OE_N_i(VME_DATA_OE_N),\
.VME_ADDR_DIR_i(VME_ADDR_DIR),\
.VME_ADDR_OE_N_i(VME_ADDR_OE_N),\
.slave(iface)\
);
function automatic bit[5:0] _gen_ga(int slot);
bit[4:0] slot_id = slot;
return {^slot_id, ~slot_id};
endfunction // _gen_ga
`define WIRE_VME_PINS(slot_id) \
.VME_AS_n_i(VME_AS_n),\
.VME_RST_n_i(VME_RST_n),\
.VME_WRITE_n_i(VME_WRITE_n),\
.VME_AM_i(VME_AM),\
.VME_DS_n_i(VME_DS_n),\
.VME_GA_i(_gen_ga(slot_id)),\
.VME_BERR_o(VME_BERR),\
.VME_DTACK_n_o(VME_DTACK_n),\
.VME_RETRY_n_o(VME_RETRY_n),\
.VME_RETRY_OE_o(VME_RETRY_OE),\
.VME_LWORD_n_b(VME_LWORD_n),\
.VME_ADDR_b(VME_ADDR),\
.VME_DATA_b(VME_DATA),\
.VME_BBSY_n_i(VME_BBSY_n),\
.VME_IRQ_n_o(VME_IRQ_n),\
.VME_IACK_n_i(VME_IACK_n),\
.VME_IACKIN_n_i(VME_IACKIN_n),\
.VME_IACKOUT_n_o(VME_IACKOUT_n),\
.VME_DTACK_OE_o(VME_DTACK_OE),\
.VME_DATA_DIR_o(VME_DATA_DIR),\
.VME_DATA_OE_N_o(VME_DATA_OE_N),\
.VME_ADDR_DIR_o(VME_ADDR_DIR),\
.VME_ADDR_OE_N_o(VME_ADDR_OE_N)
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/sim/vme64x_bfm/vme64x_bfm.svh 0000664 0000000 0000000 00000026520 13254235275 0026603 0 ustar 00root root 0000000 0000000 `ifndef __VME64X_BFM_SVH
`define __VME64X_BFM_SVH 1
`timescale 1ns/1ps
`include "simdrv_defs.svh"
`define assert_wait(name, condition, timeout) \
begin\
time t=$time;\
while(!(condition)) begin\
#1ns;\
if($time - t > timeout) begin\
$display("Wait timeout : ", `"name`"); \
// $stop;\
break;\
end\
end\
end
interface IVME64X ( input sys_rst_n_i );
wire as_n;
wire rst_n;
wire write_n;
wire [5:0] am;
wire [1:0] ds_n;
wire [5:0] ga;
wire berr_n, dtack_n;
wire retry_n;
wire lword_n;
wire [31:1] addr;
wire [31:0] data;
wire bbsy_n;
wire [6:0] irq_n;
wire iackin_n, iackout_n, iack_n;
logic q_as_n = 1'bz;
logic q_rst_n = 1'bz;
logic q_write_n = 1'bz;
logic [5:0] q_am = 6'bz;
logic [1:0] q_ds_n = 2'bz;
logic [5:0] q_ga = 6'bz;
logic q_berr_n = 1'bz, q_dtack_n = 1'bz;
logic q_retry_n = 1'bz;
logic q_lword_n = 1'bz;
logic [31:1] q_addr = 31'bz;
logic [31:0] q_data = 32'bz;
logic q_bbsy_n = 1'bz;
logic [6:0] q_irq_n = 7'bz;
logic q_iackin_n = 1'bz, q_iackout_n = 1'bz, q_iack_n = 1'bz;
/* SystemVerilog does not allow pullups inside interfaces or on logic type */
assign as_n = q_as_n;
assign rst_n = q_rst_n;
assign write_n = q_write_n;
assign am = q_am;
assign ds_n = q_ds_n;
assign ga = q_ga;
assign berr_n = q_berr_n;
assign dtack_n = q_dtack_n;
assign retry_n = q_retry_n;
assign lword_n = q_lword_n;
assign addr = q_addr;
assign data = q_data;
assign bbsy_n = q_bbsy_n;
assign irq_n = q_irq_n;
assign iackin_n = q_iackin_n;
assign iackout_n = q_iackout_n;
assign iack_n = q_iack_n;
// VME Master
modport tb
(
output as_n,
output rst_n,
output write_n,
output am,
output ds_n,
output ga,
output bbsy_n,
output iackin_n,
output iack_n,
input berr_n,
input irq_n,
input iackout_n,
inout addr,
inout data,
inout lword_n,
inout retry_n,
inout dtack_n,
input q_as_n,
input q_rst_n,
input q_write_n,
input q_am,
input q_ds_n,
input q_ga,
input q_bbsy_n,
input q_iackin_n,
input q_iack_n,
input q_berr_n,
input q_irq_n,
input q_iackout_n,
input q_addr,
input q_data,
input q_lword_n,
input q_retry_n,
input q_dtack_n
);
modport master
(
output as_n,
output rst_n,
output write_n,
output am,
output ds_n,
output ga,
output bbsy_n,
output iackin_n,
output iack_n,
input berr_n,
input irq_n,
input iackout_n,
inout addr,
inout data,
inout lword_n,
inout retry_n,
inout dtack_n);
// VME Slave
modport slave
(
input as_n,
input rst_n,
input write_n,
input am,
input ds_n,
input ga,
input bbsy_n,
input iackin_n,
input iack_n,
output berr_n,
output irq_n,
output iackout_n,
inout addr,
inout data,
inout lword_n,
inout retry_n,
inout dtack_n
);
initial forever begin
@(posedge sys_rst_n_i);
#100ns;
q_rst_n = 0;
#100ns;
q_rst_n = 1;
end
endinterface // IVME64x
const uint64_t CSR_BAR = 'h7FFFF;
const uint64_t CSR_BIT_SET_REG = 'h7FFFB;
const uint64_t CSR_BIT_CLR_REG = 'h7FFF7;
const uint64_t CSR_CRAM_OWNER = 'h7FFF3;
const uint64_t CSR_USR_BIT_SET_REG = 'h7FFEF;
const uint64_t CSR_USR_BIT_CLR_REG = 'h7FFEB;
typedef enum { DONT_CARE = 'h100,
A16 = 'h200,
A24 = 'h300,
A32 = 'h400,
A64 = 'h500
} vme_addr_size_t;
typedef enum {
SINGLE = 'h10, CR_CSR='h20, MBLT='h30, BLT='h40, LCK='h50, TwoeVME='h60, TwoeSST='h70, IACK = 'h80 } vme_xfer_type_t;
typedef enum { D08Byte0='h1, D08Byte1='h2, D08Byte2='h3, D08Byte3='h4, D16Byte01='h5, D16Byte23='h6, D32='h7 } vme_data_type_t ;
class CBusAccessor_VME64x extends CBusAccessor;
const bit [3:0] dt_map [vme_data_type_t] =
'{
D08Byte0 : 4'b0101,
D08Byte1 : 4'b1001,
D08Byte2 : 4'b0111,
D08Byte3 : 4'b1011,
D16Byte01 : 4'b0001,
D16Byte23 : 4'b0011,
D32 : 4'b0000};
protected bit [7:0] m_ba;
protected bit [4:0] m_ga;
virtual IVME64X.tb vme;
function new(virtual IVME64X.tb _vme);
vme = _vme;
m_ga = 6'b010111;
vme.q_ga = m_ga;
endfunction // new
protected task acknowledge_irq(int level, ref int vector);
`assert_wait(tmo_rws_bus_free, vme.dtack_n && vme.berr_n, 10us)
release_bus();
#40ns;
vme.q_addr[3:1] = level;
vme.q_iackin_n = 1'b0;
vme.q_iack_n = 1'b0;
vme.q_am = 'h29;
#100ns;
vme.q_as_n = 1'b0;
#100ns;
vme.q_ds_n[0] = 1'b0;
`assert_wait(tmo_rws_bus_idle, !vme.dtack_n || !vme.berr_n, 4us)
if(!vme.berr_n)
$error("[rw_simple_generic]: VME bus error.");
vector = vme.data;
vme.q_iackin_n = 1'b1;
vme.q_iack_n = 1'b1;
#100ns;
release_bus();
endtask
protected task set_address(uint64_t addr_in, vme_addr_size_t asize, vme_xfer_type_t xtype);
bit[63:0] a = addr_in;
bit [31:0] a_out;
const bit [5:0] am_map [int] =
'{
A32 | CR_CSR : 6'b101111,
A24 | CR_CSR : 6'b101111,
A16 | SINGLE: 6'b101001,
A16 | LCK : 6'b101100,
A24 | SINGLE: 6'b111001,
A24 | BLT : 6'b111011,
A24 | MBLT : 6'b111000,
A24 | LCK : 6'b110010,
A32 | SINGLE: 6'b001001,
A32 | BLT : 6'b001011,
A32 | MBLT : 6'b001000,
A32 | LCK : 6'b000101,
A64 | SINGLE: 6'b000001,
A64 | BLT : 6'b000011,
A64 | MBLT : 6'b000000,
A64 | LCK : 6'b001000,
A32 | TwoeVME : 6'b100000,
A64 | TwoeVME : 6'b100000,
A32 | TwoeSST : 6'b100000,
A64 | TwoeSST : 6'b100000};
vme.q_am = am_map[asize|xtype];
if(xtype == CR_CSR)
a_out = {8'h0, ~m_ga[4:0], a[18:0]};
else case(asize)
A16:
a_out = {16'h0, a[15:2], 2'b00};
A24:
a_out = {8'h0, a[23:2], 2'b00};
A32:
a_out = { a[31:2], 2'b00};
endcase // case (xtype)
vme.q_addr[31:2] = a_out[31:2];
endtask // set_address
protected task release_bus();
vme.q_as_n = 1'bz;
vme.q_write_n = 1'bz;
vme.q_ds_n = 2'bzz;
vme.q_lword_n = 1'bz;
vme.q_addr = 0;
vme.q_data = 32'bz;
endtask // release_bus
/* Simple generic VME read/write: single, BLT and CSR xfers */
protected task rw_generic(bit write, uint64_t _addr, ref uint64_t _data[], input vme_addr_size_t asize, input vme_xfer_type_t xtype, vme_data_type_t dtype);
bit[3:0] dt;
int i;
`assert_wait(tmo_rws_bus_free, vme.dtack_n && vme.berr_n, 10us)
release_bus();
#40ns;
set_address(_addr, asize, xtype);
dt = dt_map[dtype];
vme.q_lword_n = dt[0];
vme.q_addr[1] = dt[1];
vme.q_write_n = !write;
#100ns;
vme.q_as_n = 0;
#40ns;
// $display("RWG %x\n", _data.size());
for(i=0;i<_data.size();i++)
begin
if(write)
vme.q_data = (dtype == D08Byte0 || dtype == D08Byte2) ? (_data[i] << 8) : (_data[i]);
#100ns;
vme.q_ds_n = dt[3:2];
`assert_wait(tmo_rws_bus_idle, !vme.dtack_n || !vme.berr_n, 4us)
if(!vme.berr_n)
$error("[rw_simple_generic]: VME bus error.");
if(!write)
_data[i] = (dtype == D08Byte0 || dtype == D08Byte2) ? (vme.data >> 8) : (vme.data);
#40ns;
end // for (i=0;i<_data.size();i++)
release_bus();
endtask // rw_generic
protected task extract_xtype(int s, ref vme_xfer_type_t xtype, vme_addr_size_t asize, vme_data_type_t dtype);
xtype = vme_xfer_type_t'( s & 'h0f0);
asize = vme_addr_size_t'( s & 'hf00);
dtype = vme_data_type_t'( s & 'h00f);
endtask // extract_xtype
protected int m_default_modifiers = A32 | SINGLE | D32;
task set_default_modifiers(int mods);
m_default_modifiers = mods;
endtask // set_default_modifiers
task writem(uint64_t addr[], uint64_t data[], input int size = m_default_modifiers, ref int result);
int i;
vme_addr_size_t asize;
vme_data_type_t dtype;
vme_xfer_type_t xtype;
extract_xtype(size, xtype, asize, dtype);
if(xtype == SINGLE || xtype == CR_CSR)
for(i=0;i=0;i--)
if(!vme.irq_n[i])
begin
level = i+1;
break;
end
$display("vme64x_bfm: got irq level %d", level);
acknowledge_irq(level, vector);
$display("vme64x_bfm: vector %x", vector);
done = 1;
end
endtask // handle_irqs
endclass // CBusAccessor_VME64x
`endif // `ifndef __VME64X_BFM_SVH
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/ 0000775 0000000 0000000 00000000000 13254235275 0023311 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/Makefile 0000664 0000000 0000000 00000010773 13254235275 0024761 0 ustar 00root root 0000000 0000000 # This Makefile can be called by the Continuous Integration (CI) tool to execute all
# testbenches added for CI
#
# Author: Adam Wujek, CERN 2017
TB_DIRS=simple_tb/modelsim
test_results_xml=test_results.xml
.PHONY: $(TB_DIRS)
all: $(TB_DIRS) summary summary_total summary_xml
$(TB_DIRS):
@echo $@
@echo "Run HDL-MAKE"
cd "$@"; \
$(HDLMAKE_PATH)/hdl-make 2>&1
@echo "Run make"
$(MAKE) -C $@ $(TARGET)
@echo "Run vsim"
cd "$@" ;\
d="$@";\
d=$${d////_}; \
./run_all.sh | tee transcript."$$d".txt; \
echo "vsim returned $$?"
summary: $(TB_DIRS)
@echo "-------------------------------------------------------------------"
@echo "Summary:"
@for d in $(TB_DIRS); do \
d_=$${d////_}; \
if [ -f $$d/transcript."$$d_".txt ]; then \
echo "Warnings for $$d:"; \
cat $$d/transcript."$$d_".txt | grep Warning; \
if [ $$? -eq 1 ]; then echo "None"; fi ;\
echo "Errors for $$d:"; \
cat $$d/transcript."$$d_".txt | grep Error; \
if [ $$? -eq 1 ]; then echo "None"; fi ;\
echo "Fatals for $$d:"; \
cat $$d/transcript."$$d_".txt | grep Fatal; \
if [ $$? -eq 1 ]; then echo "None"; fi ;\
else \
echo "No transcript file for $$d"; \
fi \
done
# Run tasks all before summary_total, because if there is a failure summary_total breaks the make execution
summary_total: summary summary_xml
@echo "-------------------------------------------------------------------"
@echo ""
@echo "Summary total:"
@echo "+---------------------------------------------------+----------+----------+----------+"
@echo "| Test bench | Warnings | Errors | Fatals |"
@echo "+---------------------------------------------------+----------+----------+----------+"
@is_error=0;\
for d in $(TB_DIRS); do \
d_=$${d////_}; \
if [ -f $$d/transcript."$$d_".txt ]; then \
printf "| %-50s" $$d; \
printf "| %8d " `cat $$d/transcript."$$d_".txt | grep Warning | wc -l`; \
error_n=`cat $$d/transcript."$$d_".txt | grep Error | wc -l`; \
printf "| %8d " $$error_n;\
if [ $$error_n -gt 0 ]; then is_error=1; fi ;\
fatal_n=`cat $$d/transcript."$$d_".txt | grep Fatal | wc -l`; \
printf "| %8d |\n" $$fatal_n;\
if [ $$fatal_n -gt 0 ]; then is_error=1; fi ;\
else \
printf "| %-30s" $$d; \
echo "| No transcript file! |"; is_error=1; \
fi \
done ;\
echo "+---------------------------------------------------+----------+----------+----------+";\
if [ $$is_error -gt 0 ]; then exit 1; fi ;
summary_xml: summary
@echo '' > $(test_results_xml)
@echo '' >> $(test_results_xml)
@for d in $(TB_DIRS); do \
d_=$${d////_}; \
is_test_error=0;\
error_n=0;\
fatal_n=0;\
echo -n " > $(test_results_xml) ;\
if [ -f $$d/transcript."$$d_".txt ]; then \
error_n=`cat $$d/transcript."$$d_".txt | grep Error | wc -l`; \
fatal_n=`cat $$d/transcript."$$d_".txt | grep Fatal | wc -l`; \
if [ $$error_n -gt 0 ] || [ $$fatal_n -gt 0 ]; then is_test_error=1; fi ;\
echo -n $$is_test_error >> $(test_results_xml);\
else \
is_test_error=2; \
echo -n "1" >> $(test_results_xml); \
fi; \
echo "\" disabled=\"0\" errors=\"0\" time=\"0\">" >> $(test_results_xml) ;\
echo " " >> $(test_results_xml) ;\
if [ $$is_test_error -eq 1 ]; then \
if [ $$error_n -gt 0 ]; then \
echo " > $(test_results_xml) ;\
cat $$d/transcript."$$d_".txt | grep Error >> $(test_results_xml);\
echo " ]]>" >> $(test_results_xml) ;\
fi;\
if [ $$fatal_n -gt 0 ]; then \
echo " > $(test_results_xml) ;\
cat $$d/transcript."$$d_".txt | grep Fatal >> $(test_results_xml);\
echo " ]]>" >> $(test_results_xml) ;\
fi;\
fi ;\
if [ $$is_test_error -eq 2 ]; then \
echo " " >> $(test_results_xml) ;\
echo "" >> $(test_results_xml) ;\
echo " " >> $(test_results_xml) ;\
fi ;\
echo " " >> $(test_results_xml) ;\
echo " " >> $(test_results_xml) ;\
done ;\
echo "" >> $(test_results_xml)
clean:
@for d in $(TB_DIRS); do \
if [ -f $$d/Makefile ]; then \
$(MAKE) -C $$d $@; \
rm -f $$d/Makefile; \
fi \
done
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/simple_tb/ 0000775 0000000 0000000 00000000000 13254235275 0025267 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/simple_tb/Manifest.py 0000664 0000000 0000000 00000000150 13254235275 0027403 0 ustar 00root root 0000000 0000000 files = [
"top_tb.vhd",
]
modules = {
"local": [ "../../rtl", "../../ip_cores/general-cores" ],
}
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/simple_tb/modelsim/ 0000775 0000000 0000000 00000000000 13254235275 0027100 5 ustar 00root root 0000000 0000000 vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/simple_tb/modelsim/.gitignore 0000664 0000000 0000000 00000000047 13254235275 0031071 0 ustar 00root root 0000000 0000000 *
!.gitignore
!Manifest.py
!run_all.sh
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/simple_tb/modelsim/Manifest.py 0000664 0000000 0000000 00000000210 13254235275 0031211 0 ustar 00root root 0000000 0000000 action = "simulation"
sim_tool = "modelsim"
sim_top = "top_tb"
# for general-cores
target = None
modules = {
"local": [ ".." ],
}
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/simple_tb/modelsim/run.do 0000664 0000000 0000000 00000000535 13254235275 0030233 0 ustar 00root root 0000000 0000000
echo "###########################################################################"
echo "running scenario 1, change gg_scenario in the script to run other scenarios"
echo "###########################################################################"
vsim -gg_scenario=1 top_tb
do wave.do
radix -hexadecimal
run 5us
wave zoomfull
radix -hexadecimal
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/simple_tb/modelsim/run_all.sh 0000775 0000000 0000000 00000000542 13254235275 0031074 0 ustar 00root root 0000000 0000000 #!/bin/sh
set -e
for i in 1 2 3 4 5 6 7 8 9; do
echo
echo "Scenario $i"
vsim -quiet -gg_scenario=$i -c -do "set NumericStdNoWarnings 1; run 5us; quit" top_tb | tee sim.log
# check log
if grep -F '# ** ' sim.log | grep -E -v 'Note|Warning'; then
echo "Simulation failed!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
exit 1
fi
done
echo "OK!"
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/simple_tb/modelsim/wave.do 0000664 0000000 0000000 00000012016 13254235275 0030366 0 ustar 00root root 0000000 0000000 onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/clk_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/rst_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_AS_n_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_LWORD_n_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_LWORD_n_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_RETRY_n_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_RETRY_OE_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_WRITE_n_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_DS_n_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_DTACK_n_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_DTACK_OE_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_BERR_n_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_ADDR_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_ADDR_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_ADDR_DIR_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_ADDR_OE_N_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_DATA_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_DATA_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_DATA_DIR_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_DATA_OE_N_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_AM_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_IACKIN_n_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_IACK_n_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/VME_IACKOUT_n_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/stb_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/ack_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/dat_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/dat_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/adr_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/sel_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/we_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/cyc_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/err_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/stall_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/addr_decoder_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/addr_decoder_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/decode_start_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/decode_done_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/am_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/decode_sel_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/cr_csr_addr_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/cr_csr_data_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/cr_csr_data_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/cr_csr_we_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/module_enable_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/bar_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/INT_Level_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/INT_Vector_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/irq_pending_i
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/irq_ack_o
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_locDataIn
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_locDataOut
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_ADDRlatched
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_LWORDlatched_n
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_DSlatched_n
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_AMlatched
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_WRITElatched_n
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_vme_addr_reg
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_vme_data_reg
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_vme_lword_n_reg
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_vme_addr_dir
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_addressingType
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_transferType
add wave -noupdate -height 16 /top_tb/vme64xcore/Inst_VME_bus/s_mainFSMstate
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_conf_req
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_dataPhase
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_MBLT_Data
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_conf_sel
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_card_sel
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_irq_sel
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_err
add wave -noupdate /top_tb/vme64xcore/Inst_VME_bus/s_DS_latch_count
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {5417751726 ps} 0}
configure wave -namecolwidth 150
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 0
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {0 ps} {21356173874 ps}
vme64x-core-73232ebd0c03bb48b74764816ef1dbb06e3505db/hdl/testbench/simple_tb/top_tb.vhd 0000664 0000000 0000000 00000125126 13254235275 0027270 0 ustar 00root root 0000000 0000000 --------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- VME64x Core test bench
-- http://www.ohwr.org/projects/vme64x-core
--------------------------------------------------------------------------------
--
-- unit name: top_tb
--
-- author: Tristan Gingold
--
-- description:
--
-- Implement a VME master and test various scenarios. Set the g_SCENARIO
-- generic to select the test. See descriptions in the file.
--
--
-- dependencies:
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file 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 source 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
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
entity top_tb is
generic (g_SCENARIO : natural range 0 to 9 := 6);
end;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_textio.all;
use std.textio.all;
use work.vme64x_pkg.all;
use work.wishbone_pkg.all;
architecture behaviour of top_tb is
subtype cfg_addr_t is std_logic_vector (19 downto 0);
subtype byte_t is std_logic_vector (7 downto 0);
subtype word_t is std_logic_vector (15 downto 0);
subtype lword_t is std_logic_vector (31 downto 0);
subtype qword_t is std_logic_vector (63 downto 0);
type word_array_t is array (natural range <>) of word_t;
type lword_array_t is array (natural range <>) of lword_t;
type qword_array_t is array (natural range <>) of qword_t;
subtype vme_am_t is std_logic_vector (5 downto 0);
function hex1 (v : std_logic_vector (3 downto 0)) return character is
begin
case v is
when x"0" => return '0';
when x"1" => return '1';
when x"2" => return '2';
when x"3" => return '3';
when x"4" => return '4';
when x"5" => return '5';
when x"6" => return '6';
when x"7" => return '7';
when x"8" => return '8';
when x"9" => return '9';
when x"a" => return 'a';
when x"b" => return 'b';
when x"c" => return 'c';
when x"d" => return 'd';
when x"e" => return 'e';
when x"f" => return 'f';
when "ZZZZ" => return 'Z';
when "XXXX" => return 'X';
when others => return '?';
end case;
end hex1;
function hex2 (v : byte_t) return string is
begin
return hex1 (v(7 downto 4)) & hex1 (v(3 downto 0));
end hex2;
function hex6 (v : std_logic_vector (23 downto 0)) return string is
variable res : string (6 downto 1);
begin
for i in res'range loop
res (i) := hex1 (v (i * 4 - 1 downto i * 4 - 4));
end loop;
return res;
end hex6;
function hex8 (v : std_logic_vector (31 downto 0)) return string is
variable res : string (8 downto 1);
begin
for i in res'range loop
res (i) := hex1 (v (i * 4 - 1 downto i * 4 - 4));
end loop;
return res;
end hex8;
function hex (v : std_logic_vector) return string
is
constant ndigits : natural := v'length / 4;
subtype av_t is std_logic_vector (ndigits * 4 - 1 downto 0);
alias av : av_t is v;
variable res : string (ndigits downto 1);
begin
for i in res'range loop
res (i) := hex1 (av (i * 4 - 1 downto i * 4 - 4));
end loop;
return res;
end hex;
-- Decode DAWPR byte
function Disp_DAWPR (v : byte_t) return string is
begin
case v is
when x"81" => return "D08(O)";
when x"82" => return "D08(EO)";
when x"83" => return "D16 + D08";
when x"84" => return "D32 + D16 + D08";
when x"85" => return "MD32 + D16 + D08";
when others => return "??";
end case;
end Disp_DAWPR;
function Image_AM (am : natural range 0 to 63) return string is
begin
case am is
when 16#3f# => return "A24S-BLT";
when 16#3e# => return "A24S-PRG";
when 16#3d# => return "A24S-DAT";
when 16#3c# => return "A24S-MBL";
when 16#3b# => return "A24U-BLT";
when 16#3a# => return "A24U-PRG";
when 16#39# => return "A24U-DAT";
when 16#38# => return "A24U-MBL";
when 16#37# => return "A40x-BLT";
when 16#36# => return "Resvd-46";
when 16#35# => return "A40x-LCK";
when 16#34# => return "A40x-TFR";
when 16#33# => return "Resvd-33";
when 16#32# => return "A24x-LCK";
when 16#31# => return "Resvd-31";
when 16#30# => return "Resvd-30";
when 16#2f# => return "CR-CSR ";
when 16#2e# => return "Resvd-2e";
when 16#2d# => return "A16S ";
when 16#2c# => return "A16x-LCK";
when 16#2b# => return "Resvd-2b";
when 16#2a# => return "Resvd-2a";
when 16#29# => return "A16U ";
when 16#28# => return "Resvd-28";
when 16#27# downto 16#20# => return "Resvd-2x";
when 16#1f# downto 16#10# => return "UD-1x";
when 16#0f# => return "A32S-BLT";
when 16#0e# => return "A32S-PRG";
when 16#0d# => return "A32S-DAT";
when 16#0c# => return "A32S-MBL";
when 16#0b# => return "A32U-BLT";
when 16#0a# => return "A32U-PRG";
when 16#09# => return "A32U-DAT";
when 16#08# => return "A32U-MBL";
when 16#07# => return "Resvd-07";
when 16#06# => return "Resvd-06";
when 16#05# => return "A32x-LCK";
when 16#04# => return "A64x-LCK";
when 16#03# => return "A64x-BLT";
when 16#02# => return "Resvd-02";
when 16#01# => return "A64x-TFR";
when 16#00# => return "A64x-MBL";
end case;
end Image_AM;
procedure Disp_AMCAP (cap : std_logic_vector (63 downto 0)) is
begin
if cap = (cap'range => '0') then
write (output, " -");
else
for i in cap'range loop
if cap (i) = '1' then
write (output, " ");
write (output, Image_AM (i));
end if;
end loop;
end if;
end Disp_AMCAP;
-- Clock
constant g_CLOCK_PERIOD : natural := 10; -- in ns
-- VME core
signal clk_i : std_logic;
signal rst_n_i : std_logic;
signal rst_n_o : std_logic;
signal VME_AS_n_i : std_logic;
signal VME_RST_n_i : std_logic;
signal VME_WRITE_n_i : std_logic;
signal VME_AM_i : std_logic_vector(5 downto 0);
signal VME_DS_n_i : std_logic_vector(1 downto 0);
signal VME_GA_i : std_logic_vector(5 downto 0);
signal VME_BERR_n_o : std_logic;
signal VME_DTACK_n_o : std_logic;
signal VME_RETRY_n_o : std_logic;
signal VME_LWORD_n_i : std_logic;
signal VME_LWORD_n_o : std_logic;
signal VME_ADDR_i : std_logic_vector(31 downto 1);
signal VME_ADDR_o : std_logic_vector(31 downto 1);
signal VME_DATA_i : std_logic_vector(31 downto 0);
signal VME_DATA_o : std_logic_vector(31 downto 0);
signal VME_IRQ_n_o : std_logic_vector(6 downto 0);
signal VME_IACKIN_n_i : std_logic;
signal VME_IACK_n_i : std_logic;
signal VME_IACKOUT_n_o : std_logic;
signal VME_DTACK_OE_o : std_logic;
signal VME_DATA_DIR_o : std_logic;
signal VME_DATA_OE_N_o : std_logic;
signal VME_ADDR_DIR_o : std_logic;
signal VME_ADDR_OE_N_o : std_logic;
signal VME_RETRY_OE_o : std_logic;
signal DAT_i : std_logic_vector(31 downto 0);
signal DAT_o : std_logic_vector(31 downto 0);
signal ADR_o : std_logic_vector(31 downto 0);
signal CYC_o : std_logic;
signal ERR_i : std_logic;
signal SEL_o : std_logic_vector(3 downto 0);
signal STB_o : std_logic;
signal ACK_i : std_logic;
signal WE_o : std_logic;
signal STALL_i : std_logic;
signal rty_i : std_logic := '0';
signal irq_level_i : std_logic_vector(2 downto 0) := (others => '0');
signal irq_vector_i : std_logic_vector(7 downto 0) := (others => '0');
signal user_csr_addr_o : std_logic_vector(18 downto 2);
signal user_csr_data_i : std_logic_vector(7 downto 0) := (others => '0');
signal user_csr_data_o : std_logic_vector(7 downto 0);
signal user_csr_we_o : std_logic;
signal user_cr_addr_o : std_logic_vector(18 downto 2);
signal user_cr_data_i : std_logic_vector( 7 downto 0) := (others => '0');
signal irq_ack_o : std_logic;
signal irq_i : std_logic;
constant slave_ga : std_logic_vector (4 downto 0) := b"0_1101";
signal bus_timer : std_logic;
signal end_tb : boolean := false;
begin
set_ga: block
begin
VME_GA_i (4 downto 0) <= not slave_ga;
VME_GA_i (5) <= (slave_ga (4) xor slave_ga (3) xor slave_ga (2)
xor slave_ga (1) xor slave_ga (0));
end block;
vme64xcore: entity work.vme64x_core
generic map (g_CLOCK_PERIOD => g_CLOCK_PERIOD,
g_DECODE_AM => (g_SCENARIO /= 9),
g_WB_GRANULARITY => WORD,
g_USER_CSR_EXT => false,
g_MANUFACTURER_ID => c_CERN_ID,
g_BOARD_ID => c_SVEC_ID,
g_REVISION_ID => c_SVEC_REVISION_ID,
g_PROGRAM_ID => c_SVEC_PROGRAM_ID,
g_ASCII_PTR => x"000000",
g_BEG_USER_CR => x"000000",
g_END_USER_CR => x"000000",
g_BEG_CRAM => x"000000",
g_END_CRAM => x"000000",
g_BEG_USER_CSR => x"07ff33",
g_END_USER_CSR => x"07ff5f",
g_BEG_SN => x"000000",
g_END_SN => x"000000",
g_decoder_0_adem => x"ff000000",
g_decoder_0_amcap => x"00000000_0000ff00",
g_decoder_0_dawpr => x"84",
g_decoder_1_adem => x"fff80000",
g_decoder_1_amcap => x"ff000000_00000000",
g_decoder_1_dawpr => x"84",
g_decoder_2_adem => x"00000000",
g_decoder_2_amcap => x"00000000_00000000",
g_decoder_2_dawpr => x"84",
g_decoder_3_adem => x"00000000",
g_decoder_3_amcap => x"00000000_00000000",
g_decoder_3_dawpr => x"84",
g_decoder_4_adem => x"00000000",
g_decoder_4_amcap => x"00000000_00000000",
g_decoder_4_dawpr => x"84",
g_decoder_5_adem => x"00000000",
g_decoder_5_amcap => x"00000000_00000000",
g_decoder_5_dawpr => x"84",
g_decoder_6_adem => x"00000000",
g_decoder_6_amcap => x"00000000_00000000",
g_decoder_6_dawpr => x"84",
g_decoder_7_adem => x"00000000",
g_decoder_7_amcap => x"00000000_00000000",
g_decoder_7_dawpr => x"84")
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
rst_n_o => rst_n_o,
VME_AS_n_i => VME_AS_n_i,
VME_RST_n_i => VME_RST_n_i,
VME_WRITE_n_i => VME_WRITE_n_i,
VME_AM_i => VME_AM_i,
VME_DS_n_i => VME_DS_n_i,
VME_GA_i => VME_GA_i,
VME_BERR_n_o => VME_BERR_n_o,
VME_DTACK_n_o => VME_DTACK_n_o,
VME_RETRY_n_o => VME_RETRY_n_o,
VME_LWORD_n_i => VME_LWORD_n_i,
VME_LWORD_n_o => VME_LWORD_n_o,
VME_ADDR_i => VME_ADDR_i,
VME_ADDR_o => VME_ADDR_o,
VME_DATA_i => VME_DATA_i,
VME_DATA_o => VME_DATA_o,
VME_IRQ_n_o => VME_IRQ_n_o,
VME_IACKIN_n_i => VME_IACKIN_n_i,
VME_IACK_n_i => VME_IACK_n_i,
VME_IACKOUT_n_o => VME_IACKOUT_n_o,
VME_DTACK_OE_o => VME_DTACK_OE_o,
VME_DATA_DIR_o => VME_DATA_DIR_o,
VME_DATA_OE_N_o => VME_DATA_OE_N_o,
VME_ADDR_DIR_o => VME_ADDR_DIR_o,
VME_ADDR_OE_N_o => VME_ADDR_OE_N_o,
VME_RETRY_OE_o => VME_RETRY_OE_o,
wb_DAT_i => DAT_i,
wb_DAT_o => DAT_o,
wb_ADR_o => ADR_o,
wb_CYC_o => CYC_o,
wb_ERR_i => ERR_i,
wb_SEL_o => SEL_o,
wb_STB_o => STB_o,
wb_ACK_i => ACK_i,
wb_WE_o => WE_o,
wb_STALL_i => STALL_i,
wb_rty_i => rty_i,
wb_int_i => '0',
int_i => irq_i,
irq_level_i => irq_level_i,
irq_vector_i => irq_vector_i,
user_csr_addr_o => user_csr_addr_o,
user_csr_data_i => user_csr_data_i,
user_csr_data_o => user_csr_data_o,
user_csr_we_o => user_csr_we_o,
user_cr_addr_o => user_cr_addr_o,
user_cr_data_i => user_cr_data_i,
irq_ack_o => irq_ack_o);
clk_gen: process
begin
clk_i <= '0';
wait for (g_CLOCK_PERIOD / 2) * 1 ns;
clk_i <= '1';
wait for (g_CLOCK_PERIOD / 2) * 1 ns;
if end_tb then
wait;
end if;
end process;
-- Bus timer. See VME spec 2.3.3 Bus Timer
bus_timer_proc : process (clk_i)
type state_t is (IDLE, WAIT_DS, COUNTING, WAIT_END, ERR);
variable state : state_t;
variable count : natural;
begin
if rising_edge (clk_i) then
if VME_RST_n_i = '0' then
state := IDLE;
bus_timer <= '0';
else
bus_timer <= '0';
case state is
when IDLE =>
if VME_AS_n_i = '0' then
state := WAIT_DS;
end if;
when WAIT_DS =>
count := 20;
if VME_DS_n_i /= "11" then
state := COUNTING;
end if;
when COUNTING =>
if VME_DS_n_i = "11" then
state := WAIT_END;
else
if count = 0 then
state := ERR;
else
count := count - 1;
end if;
end if;
when WAIT_END =>
if VME_AS_n_i = '1' then
state := IDLE;
end if;
when ERR =>
bus_timer <= '1';
-- VITAL 1 Rule 2.60
-- Once it has driven BERR* low, the bus timer MUST NOT release
-- BERR* until it detected both DS0* and DS1* high.
if VME_DS_n_i = "11" then
state := IDLE;
end if;
end case;
end if;
end if;
end process;
-- WB slave: a simple sram
-- WBaddr VMEaddr
-- 0-0x3ff 0-0xfff sram
-- 0x2000 0x8000 counter
-- 0x2001 0x8004 BERR
wb_p : process (clk_i)
constant sram_addr_wd : natural := 10;
type sram_array is array (0 to 2**sram_addr_wd - 1)
of std_logic_vector (31 downto 0);
variable sram : sram_array := (0 => x"0000_0000",
1 => x"0000_0001",
2 => x"0000_0002",
3 => x"0000_0003",
4 => x"0000_0004",
5 => x"0000_0500",
6 => x"0006_0000",
7 => x"0700_0000",
others => x"8765_4321");
variable idx : natural;
variable int_cnt : natural;
begin
if rising_edge (clk_i) then
if rst_n_o = '0' then
ERR_i <= '0';
STALL_i <= '0';
ACK_i <= '0';
int_cnt := 0;
else
ACK_i <= '0';
ERR_i <= '0';
-- Interrupt timer
irq_i <= '0';
if int_cnt > 0 then
int_cnt := int_cnt - 1;
if int_cnt = 0 then
irq_i <= '1';
end if;
end if;
if STB_o = '1' then
ACK_i <= '1';
idx := to_integer (unsigned (ADR_o (sram_addr_wd - 1 downto 0)));
if ADR_o (13) = '1' then
if ADR_o (0) = '0' then
if WE_o = '0' then
-- Read counter
DAT_i <= std_logic_vector (to_unsigned (int_cnt, 32));
else
-- Write counter
if SEL_o (0) = '1' then
int_cnt := to_integer(unsigned(DAT_o(7 downto 0)));
end if;
end if;
else
-- BERR
ACK_i <= '0';
ERR_i <= '1';
end if;
else
if WE_o = '0' then
-- Read SRAM
DAT_i <= sram (idx);
else
-- Write SRAM
for i in 3 downto 0 loop
if SEL_o(i) = '1' then
sram(idx)(8*i + 7 downto 8*i) := DAT_o (8*i + 7 downto 8*i);
end if;
end loop;
end if;
end if;
end if;
end if;
end if;
end process;
VME_IACKIN_n_i <= VME_IACK_n_i;
tb: process
constant c_log : boolean := false;
-- Convert a CR/CSR address to the VME address: insert GA.
-- The ADDR is on 20 bits (so the x"" notation can be used), but as
-- ADDR(19) is stipped, it must be '0'.
function to_vme_cfg_addr (addr : cfg_addr_t)
return std_logic_vector is
begin
assert addr (19) = '0' report "a19 is discarded" severity error;
return x"00" & slave_ga & addr (18 downto 0);
end to_vme_cfg_addr;
procedure read_setup_addr (addr : std_logic_vector (31 downto 0);
am : vme_am_t) is
begin
VME_ADDR_i <= addr (31 downto 1);
VME_AM_i <= am;
VME_IACK_n_i <= '1';
wait for 35 ns;
VME_AS_n_i <= '0';
VME_WRITE_n_i <= '1';
if not (VME_DTACK_OE_o = '0' and VME_BERR_n_o = '1') then
wait until VME_DTACK_OE_o = '0' and VME_BERR_n_o = '1';
end if;
end read_setup_addr;
procedure read_wait_dtack is
begin
wait until (VME_DTACK_OE_o = '1' and VME_DTACK_n_o = '0')
or bus_timer = '1';
if bus_timer = '0' then
assert VME_DATA_DIR_o = '1' report "bad data_dir_o";
assert VME_DATA_OE_N_o = '0' report "bad data_oe_n_o";
end if;
end read_wait_dtack;
procedure read_release is
begin
-- Release
VME_AS_n_i <= '1';
VME_DS_n_i <= "11";
end read_release;
procedure read8 (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
variable data : out byte_t)
is
variable res : byte_t;
begin
if c_log then
write (output, "read8 at 0x" & hex (addr) & " ["
& Image_AM (to_integer (unsigned (am))) & " ]" & LF);
end if;
VME_LWORD_n_i <= '1';
read_setup_addr (addr, am);
if addr (0) = '0' then
VME_DS_n_i <= "01";
else
VME_DS_n_i <= "10";
end if;
read_wait_dtack;
if bus_timer = '0' then
if addr (0) = '0' then
res := VME_DATA_o (15 downto 8);
else
res := VME_DATA_o (7 downto 0);
end if;
else
res := (others => 'X');
end if;
data := res;
read_release;
if c_log then
write (output, " => 0x" & hex(res) & LF);
end if;
end read8;
procedure read16 (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
variable data : out word_t)
is
variable res : word_t;
begin
if c_log then
write (output, "read16 at 0x" & hex (addr) & " ["
& Image_AM (to_integer (unsigned (am))) & " ]" & LF);
end if;
VME_LWORD_n_i <= '1';
read_setup_addr (addr, am);
assert addr (0) = '0' report "unaligned read16" severity error;
VME_DS_n_i <= "00";
read_wait_dtack;
if bus_timer = '0' then
res := VME_DATA_o (15 downto 0);
else
res := (others => 'X');
end if;
data := res;
read_release;
if c_log then
write (output, " => 0x" & hex(res) & LF);
end if;
end read16;
procedure read32 (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
variable data : out lword_t)
is
variable res : lword_t;
begin
if c_log then
write (output, "read32 at 0x" & hex (addr) & " ["
& Image_AM (to_integer (unsigned (am))) & " ]" & LF);
end if;
VME_LWORD_n_i <= '0';
read_setup_addr (addr, am);
assert addr (1 downto 0) = "00" report "unaligned read32" severity error;
VME_DS_n_i <= "00";
read_wait_dtack;
if bus_timer = '0' then
res := VME_DATA_o (31 downto 0);
else
res := (others => 'X');
end if;
data := res;
read_release;
if c_log then
write (output, " => 0x" & hex(res) & LF);
end if;
end read32;
procedure read8_conf (addr : cfg_addr_t;
variable data : out byte_t) is
begin
read8 (to_vme_cfg_addr (addr), c_AM_CR_CSR, data);
end read8_conf;
procedure read8_conf_mb (addr : cfg_addr_t;
variable data : out std_logic_vector)
is
variable ad : cfg_addr_t := addr;
constant bsize : natural := data'length / 8;
subtype d_type is std_logic_vector (bsize * 8 - 1 downto 0);
alias d : d_type is data;
begin
assert data'length mod 8 = 0 report "data is not a multiple of bytes"
severity error;
for i in bsize - 1 downto 0 loop
read8_conf (ad, d (i * 8 + 7 downto i * 8));
ad := cfg_addr_t (unsigned(ad) + 4);
end loop;
end read8_conf_mb;
procedure read_blt_end_cycle is
begin
VME_DS_n_i <= "11";
wait until (VME_DTACK_OE_o = '0' or VME_DTACK_n_o = '1')
and VME_BERR_n_o = '1';
end read_blt_end_cycle;
procedure read32_blt (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
variable data : out lword_array_t) is
begin
VME_LWORD_n_i <= '0';
read_setup_addr (addr, am);
assert addr (1 downto 0) = "00"
report "unaligned read32_blt" severity error;
for i in data'range loop
VME_DS_n_i <= "00";
read_wait_dtack;
if bus_timer = '0' then
data (i) := VME_DATA_o (31 downto 0);
else
data (i) := (others => 'X');
end if;
if i /= data'right then
read_blt_end_cycle;
end if;
end loop;
read_release;
end read32_blt;
procedure read16_blt (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
variable data : out word_array_t) is
begin
VME_LWORD_n_i <= '1';
read_setup_addr (addr, am);
assert addr (0) = '0' report "unaligned read16_blt" severity error;
for i in data'range loop
VME_DS_n_i <= "00";
read_wait_dtack;
if bus_timer = '0' then
data (i) := VME_DATA_o (15 downto 0);
else
data (i) := (others => 'X');
end if;
if i /= data'right then
read_blt_end_cycle;
end if;
end loop;
read_release;
end read16_blt;
procedure read64_mblt (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
variable data : out qword_array_t) is
begin
VME_LWORD_n_i <= '0';
read_setup_addr (addr, am);
VME_DS_n_i <= "00";
read_wait_dtack;
read_blt_end_cycle;
assert addr (2 downto 0) = "000"
report "unaligned read64_mblt" severity error;
for i in data'range loop
VME_DS_n_i <= "00";
read_wait_dtack;
if bus_timer = '0' then
data (i) := VME_ADDR_o & VME_LWORD_n_o & VME_DATA_o;
else
data (i) := (others => 'X');
VME_DS_n_i <= "11";
exit;
end if;
if i /= data'right then
read_blt_end_cycle;
end if;
end loop;
read_release;
end read64_mblt;
procedure write_setup_addr (addr : std_logic_vector (31 downto 0);
lword_n : std_logic;
am : vme_am_t) is
begin
if not (VME_DTACK_OE_o = '0' and VME_BERR_n_o = '1') then
wait until VME_DTACK_OE_o = '0' and VME_BERR_n_o = '1';
end if;
VME_ADDR_i <= addr(31 downto 1);
VME_AM_i <= am;
VME_LWORD_n_i <= lword_n;
VME_IACK_n_i <= '1';
wait for 35 ns;
VME_AS_n_i <= '0';
VME_WRITE_n_i <= '0';
end write_setup_addr;
procedure write_wait_dtack_pulse is
begin
wait until VME_DTACK_OE_o = '1' and VME_DTACK_n_o = '0';
VME_DS_n_i <= "11";
wait until VME_DTACK_OE_o = '0' or VME_DTACK_n_o = '1';
end write_wait_dtack_pulse;
procedure write_wait_dtack is
begin
write_wait_dtack_pulse;
VME_AS_n_i <= '1';
end write_wait_dtack;
procedure write8 (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
data : byte_t) is
begin
write_setup_addr (addr, '1', am);
if addr (0) = '0' then
VME_DS_n_i <= "01";
VME_DATA_i (15 downto 8) <= data;
else
VME_DS_n_i <= "10";
VME_DATA_i (7 downto 0) <= data;
end if;
write_wait_dtack;
end write8;
procedure write16 (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
data : word_t) is
begin
assert addr(0) = '0' report "unaligned write16" severity error;
write_setup_addr (addr, '1', am);
VME_DS_n_i <= "00";
VME_DATA_i (15 downto 0) <= data;
write_wait_dtack;
end write16;
procedure write32 (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
data : lword_t) is
begin
assert addr(1 downto 0) = "00"
report "unaligned write16" severity error;
write_setup_addr (addr, '0', am);
VME_DS_n_i <= "00";
VME_DATA_i (31 downto 0) <= data;
write_wait_dtack;
end write32;
procedure write32_blt (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
data : lword_array_t) is
begin
assert addr(1 downto 0) = "00"
report "unaligned write32" severity error;
write_setup_addr (addr, '0', am);
for i in data'range loop
VME_DS_n_i <= "00";
VME_DATA_i (31 downto 0) <= data (i);
write_wait_dtack_pulse;
end loop;
VME_AS_n_i <= '1';
end write32_blt;
procedure write64_mblt (addr : std_logic_vector (31 downto 0);
am : vme_am_t;
data : qword_array_t) is
begin
assert addr(2 downto 0) = "000"
report "unaligned write64" severity error;
write_setup_addr (addr, '0', am);
VME_DS_n_i <= "00";
write_wait_dtack_pulse;
for i in data'range loop
VME_DS_n_i <= "00";
VME_DATA_i (31 downto 0) <= data (i)(31 downto 0);
VME_LWORD_n_i <= data (i)(32);
VME_ADDR_i <= data(i)(63 downto 33);
write_wait_dtack_pulse;
end loop;
VME_AS_n_i <= '1';
end write64_mblt;
procedure write8_conf (addr : cfg_addr_t;
data : byte_t)
is
variable li : line;
begin
if c_log then
write (li, string'("write8_conf at 0x"));
hwrite (li, addr);
write (li, string'(" <= "));
hwrite (li, data);
writeline (output, li);
end if;
write8(to_vme_cfg_addr (addr), c_AM_CR_CSR, data);
end write8_conf;
procedure ack_int (vec : out byte_t) is
begin
if VME_IRQ_n_o = "1111111" then
vec := (others => 'X');
return;
end if;
for i in 6 downto 0 loop
if VME_IRQ_n_o (i) = '0' then
VME_ADDR_i (3 downto 1) <= std_logic_vector (to_unsigned (i + 1, 3));
exit;
end if;
end loop;
VME_IACK_n_i <= '0';
VME_WRITE_n_i <= '1';
wait for 35 ns;
VME_AS_n_i <= '0';
if not (VME_DTACK_OE_o = '0' and VME_BERR_n_o = '1') then
wait until VME_DTACK_OE_o = '0' and VME_BERR_n_o = '1';
end if;
VME_DS_n_i <= "10";
read_wait_dtack;
if bus_timer = '0' then
vec := VME_DATA_o (7 downto 0);
else
vec := (others => 'X');
end if;
read_release;
VME_IACK_n_i <= '1';
end ack_int;
procedure Dump_CR
is
variable d : byte_t;
variable b3 : std_logic_vector (23 downto 0);
variable w : std_logic_vector (31 downto 0);
variable b8 : std_logic_vector (63 downto 0);
variable b32 : std_logic_vector (255 downto 0);
begin
read8_conf (x"0_0003", d);
write (output, "CR checksum: 0x" & hex2 (d) & LF);
read8_conf (x"0_0013", d);
assert d = x"81" report "invalid data width at 0x13" severity error;
write (output, "CR data width: 0x" & hex2 (d) & LF);
read8_conf (x"0_0017", d);
assert d = x"81" report "invalid data width at 0x17" severity error;
write (output, "CSR data width: 0x" & hex2 (d) & LF);
read8_conf (x"0_001b", d);
assert d = x"02" report "invalid spec ID at 0x1b" severity error;
write (output, "CR/CSR version: 0x" & hex2 (d) & LF);
read8_conf (x"0_001f", d);
assert d = x"43" report "invalid valid CR byte at 0x1f" severity error;
write (output, "CR valid 'C': 0x" & hex2 (d) & LF);
read8_conf (x"0_0023", d);
assert d = x"52" report "invalid valid CR byte at 0x23" severity error;
write (output, "CR valid 'R': 0x" & hex2 (d) & LF);
read8_conf_mb (x"0_0027", b3);
write (output, "CR Manu ID: 0x" & hex6 (b3) & LF);
read8_conf_mb (x"0_0033", w);
write (output, "CR Board ID: 0x" & hex8 (w) & LF);
read8_conf_mb (x"0_0043", w);
write (output, "CR Rev ID: 0x" & hex8 (w) & LF);
read8_conf_mb (x"0_0053", b3);
write (output, "CR ASCII ptr: 0x" & hex6 (b3) & LF);
read8_conf (x"0_007F", d);
write (output, "CR Program ID: 0x" & hex2 (d) & LF);
-- VME64x
read8_conf_mb (x"0_0083", b3);
write (output, "CR BEG_USER_CR: 0x" & hex6 (b3) & LF);
read8_conf_mb (x"0_008F", b3);
write (output, "CR END_USER_CR: 0x" & hex6 (b3) & LF);
read8_conf_mb (x"0_009B", b3);
write (output, "CR BEG_CRAM: 0x" & hex6 (b3) & LF);
read8_conf_mb (x"0_00A7", b3);
write (output, "CR END_CRAM: 0x" & hex6 (b3) & LF);
read8_conf_mb (x"0_00B3", b3);
write (output, "CR BEG_USER_CSR: 0x" & hex6 (b3) & LF);
read8_conf_mb (x"0_00B3", b3);
write (output, "CR END_USER_CSR: 0x" & hex6 (b3) & LF);
read8_conf_mb (x"0_00CB", b3);
write (output, "CR BEG_SN: 0x" & hex6 (b3) & LF);
read8_conf_mb (x"0_00D7", b3);
write (output, "CR END_SN: 0x" & hex6 (b3) & LF);
read8_conf (x"0_00E3", d);
write (output, "CR Slave charac: 0x" & hex2 (d) & LF);
read8_conf (x"0_00E7", d);
write (output, "CR user-def: 0x" & hex2 (d) & LF);
read8_conf (x"0_00EB", d);
write (output, "CR master chara: 0x" & hex2 (d) & LF);
read8_conf (x"0_00EF", d);
write (output, "CR user-def: 0x" & hex2 (d) & LF);
read8_conf (x"0_00F3", d);
write (output, "CR INT hand cap: 0x" & hex2 (d) & LF);
read8_conf (x"0_00F7", d);
write (output, "CR INT cap: 0x" & hex2 (d) & LF);
read8_conf (x"0_00FF", d);
write (output, "CR CRAM acc wd: 0x" & hex2 (d) & LF);
for i in 0 to 7 loop
read8_conf (std_logic_vector (unsigned'(x"0_0103") + i * 4), d);
write (output, "CR FN" & natural'image (i) & " DAW: 0x"
& hex2 (d) & " [" & Disp_DAWPR (d) & ']' & LF);
end loop;
for i in 0 to 7 loop
read8_conf_mb (std_logic_vector (unsigned'(x"0_0123") + i * 32), b8);
write (output, "CR FN" & natural'image (i) & " AMCAP: 0x"
& hex (b8) & " [");
Disp_AMCAP (b8);
write (output, " ]" & LF);
end loop;
read8_conf_mb (x"0_0223", b32);
write (output, "CR FN0 XAMCAP: 0x" & hex (b32) & LF);
read8_conf_mb (x"0_02a3", b32);
write (output, "CR FN1 XAMCAP: 0x" & hex (b32) & LF);
-- ...
read8_conf_mb (x"0_0623", w);
write (output, "CR FN0 ADEM: 0x" & hex (w) & LF);
read8_conf_mb (x"0_0633", w);
write (output, "CR FN1 ADEM: 0x" & hex (w) & LF);
-- ...
read8_conf_mb (x"7_FF63", w);
write (output, "CR FN0 ADER: 0x" & hex (w) & LF);
read8_conf_mb (x"7_FF73", w);
write (output, "CR FN1 ADER: 0x" & hex (w) & LF);
read8_conf (x"0_06af", d);
write (output, "CR master DAWPR: 0x" & hex2 (d) & LF);
read8_conf_mb (x"0_06b3", b8);
write (output, "CR master AMCAP: 0x" & hex (b8) & LF);
read8_conf_mb (x"0_06d3", b32);
write (output, "CR mastr XAMCAP: 0x" & hex (b32) & LF);
end Dump_CR;
variable d8 : byte_t;
variable d16 : word_t;
variable d32 : lword_t;
variable v64 : qword_array_t (0 to 16);
variable v32 : lword_array_t (0 to 16);
variable v16 : word_array_t (0 to 16);
begin
-- Each scenario starts with a reset.
-- VME reset
rst_n_i <= '0';
VME_RST_n_i <= '0';
VME_AS_n_i <= '1';
VME_ADDR_i <= (others => '1');
VME_AM_i <= (others => '1');
VME_DS_n_i <= "11";
for i in 1 to 2 loop
wait until rising_edge (clk_i);
end loop;
VME_RST_n_i <= '1';
rst_n_i <= '1';
for i in 1 to 8 loop
wait until rising_edge (clk_i);
end loop;
case g_SCENARIO is
when 0 =>
-- Disp CR/CSR
-- Read CSR
read8_conf (x"7_FFFF", d8);
assert d8 = slave_ga & "000"
report "bad CR/CSR BAR value" severity error;
read8_conf (x"7_FFFB", d8);
write (output, "CSR bit reg: 0x" & hex (d8) & LF);
read8_conf (x"7_FFEF", d8);
write (output, "CSR usr bit reg: 0x" & hex (d8) & LF);
-- READ CR
Dump_CR;
when 1 =>
-- WB data access
-- Check ADER is 0
read8_conf (x"7_ff63", d8);
assert d8 = x"00" report "bad initial ADER0 value" severity error;
-- Set ADER
write8_conf (x"7_ff63", x"56");
write8_conf (x"7_ff6f", c_AM_A32 & "00");
read8_conf (x"7_ff63", d8);
assert d8 = x"56" report "bad ADER0 value" severity error;
-- Try to read (but card is not yet enabled)
read8 (x"56_00_00_00", c_AM_A32, d8);
assert d8 = "XXXXXXXX" report "unexpected reply" severity error;
-- Enable card
write8_conf (x"7_fffb", b"0001_0000");
read8_conf (x"7_fffb", d8);
assert d8 = b"0001_0000" report "module must be enabled"
severity error;
report "read data: " & hex (d8);
-- WB read
read8 (x"56_00_00_00", c_AM_A32, d8);
assert d8 = x"00" report "bad read at 000" severity error;
read8 (x"56_00_00_07", c_AM_A32, d8);
assert d8 = x"01" report "bad read at 007" severity error;
report "read data: " & hex (d8);
read16 (x"56_00_00_12", c_AM_A32, d16);
assert d16 = x"0004" report "bad read at 012" severity error;
read32 (x"56_00_00_14", c_AM_A32, d32);
assert d32 = x"0000_0500" report "bad read at 014" severity error;
-- WB write
write8 (x"56_00_00_14", c_AM_A32, x"1f");
read32 (x"56_00_00_14", c_AM_A32, d32);
assert d32 = x"1f00_0500" report "bad read at 014 (2)" severity error;
write16 (x"56_00_00_16", c_AM_A32, x"abcd");
read32 (x"56_00_00_14", c_AM_A32, d32);
assert d32 = x"1f00_abcd" report "bad read at 014 (3)" severity error;
read32 (x"56_00_00_18", c_AM_A32, d32);
assert d32 = x"0006_0000" report "bad read at 018 (1)" severity error;
write32 (x"56_00_00_18", c_AM_A32, x"2345_6789");
read32 (x"56_00_00_18", c_AM_A32, d32);
assert d32 = x"2345_6789" report "bad read at 018 (2)" severity error;
when 2 =>
-- Test interrupts
-- Set ADER
write8_conf (x"7_ff63", x"67");
write8_conf (x"7_ff6f", c_AM_A32 & "00");
-- Enable card
write8_conf (x"7_fffb", b"0001_0000");
-- Set IRQ level
write8_conf (x"7_ff5b", x"03");
write8 (x"67_00_80_03", c_AM_A32, x"02");
wait for 2 * g_CLOCK_PERIOD * 1 ns;
assert VME_IRQ_n_o = "1111011" report "IRQ incorrectly reported"
severity error;
ack_int (d8);
assert d8 = x"00" report "incorrect vector" severity error;
assert VME_IRQ_n_o = "1111111" report "IRQ not disabled after ack"
severity error;
-- Set IRQ vector
write8_conf (x"7_ff5f", x"a3");
write8 (x"67_00_80_03", c_AM_A32, x"20");
assert VME_IRQ_n_o = "1111111" report "IRQ not expected"
severity error;
wait for 32 * g_CLOCK_PERIOD * 1 ns;
assert VME_IRQ_n_o = "1111011" report "IRQ incorrectly reported"
severity error;
ack_int (d8);
assert d8 = x"a3" report "incorrect vector" severity error;
assert VME_IRQ_n_o = "1111111" report "IRQ not disabled after ack"
severity error;
when 3 =>
-- Test block transfers
-- Set ADER
write8_conf (x"7_ff63", x"64");
write8_conf (x"7_ff6f", c_AM_A32_BLT & "00");
-- Enable card
write8_conf (x"7_fffb", b"0001_0000");
read32_blt (x"64_00_00_10", c_AM_A32_BLT, v32 (0 to 4));
assert v32 (0) = x"0000_0004"
and v32 (1) = x"0000_0500"
and v32 (2) = x"0006_0000"
and v32 (3) = x"0700_0000"
and v32 (4) = x"8765_4321"
report "incorrect BLT data 32" severity error;
if false then
-- D16 BLT not supported
read16_blt (x"64_00_00_14", c_AM_A32_BLT, v16 (0 to 5));
assert v16 (0) = x"0000"
and v16 (1) = x"0500"
and v16 (2) = x"0006"
and v16 (3) = x"0000"
and v16 (4) = x"0700"
and v16 (5) = x"0000"
report "incorrect BLT data 16" severity error;
end if;
v32 (0 to 3) := (x"00_11_22_33",
x"44_55_66_77",
x"88_99_aa_bb",
x"cc_dd_ee_ff");
write32_blt (x"64_00_01_00", c_AM_A32_BLT, v32 (0 to 3));
read32_blt (x"64_00_01_00", c_AM_A32_BLT, v32 (0 to 4));
assert v32 (0 to 4) = (x"00_11_22_33",
x"44_55_66_77",
x"88_99_aa_bb",
x"cc_dd_ee_ff",
x"87_65_43_21")
report "incorrect BLT data 32 r/w" severity error;
when 4 =>
-- A24 tests
-- A24 with weird MSBs in address
-- Set ADER
write8_conf (x"7_ff73", x"00");
write8_conf (x"7_ff77", x"20");
write8_conf (x"7_ff7f", c_AM_A24_S & "00");
-- Enable card
write8_conf (x"7_fffb", b"0001_0000");
read32 (x"00_20_00_10", c_AM_A24_S, d32);
assert d32 = x"0000_0004"
report "incorrect read 32" severity error;
read32 (x"13_20_00_14", c_AM_A24_S, d32);
assert d32 = x"0000_0500"
report "incorrect read 32" severity error;
when 5 =>
-- Test err_i => BERR
-- Set ADER
write8_conf (x"7_ff73", x"00");
write8_conf (x"7_ff77", x"20");
write8_conf (x"7_ff7f", c_AM_A24_S & "00");
-- Enable card
write8_conf (x"7_fffb", b"0001_0000");
read32 (x"00_20_80_04", c_AM_A24_S, d32);
assert d32 = (31 downto 0 => 'X')
report "incorrect read 32" severity error;
when 6 =>
-- Test MBLT
-- Set ADER
write8_conf (x"7_ff63", x"64");
write8_conf (x"7_ff6f", c_AM_A32_MBLT & "00");
-- Enable card
write8_conf (x"7_fffb", b"0001_0000");
read64_mblt (x"64_00_00_10", c_AM_A32_MBLT, v64 (0 to 1));
assert v64 (0) = x"0000_0004_0000_0500"
and v64 (1) = x"0006_0000_0700_0000"
report "incorrect MBLT data 64" severity error;
v64 (0 to 3) := (x"00_11_22_33_44_55_66_77",
x"88_99_aa_bb_cc_dd_ee_ff",
x"01_23_45_67_89_ab_cd_ef",
x"fe_dc_ba_98_76_54_32_10");
write64_mblt (x"64_00_01_00", c_AM_A32_MBLT, v64 (0 to 3));
read64_mblt (x"64_00_01_00", c_AM_A32_MBLT, v64 (0 to 3));
assert v64 (0 to 3) = (x"00_11_22_33_44_55_66_77",
x"88_99_aa_bb_cc_dd_ee_ff",
x"01_23_45_67_89_ab_cd_ef",
x"fe_dc_ba_98_76_54_32_10")
report "incorrect MBLT data 64 r/w" severity error;
when 7 =>
-- Delayed DS
-- Set ADER
write8_conf (x"7_ff63", x"67");
write8_conf (x"7_ff6f", c_AM_A32 & "00");
-- Enable card
write8_conf (x"7_fffb", b"0001_0000");
-- Read 16 at 0x0100
VME_LWORD_n_i <= '1';
read_setup_addr (x"67_00_01_00", c_AM_A32);
wait for 50 ns;
VME_DS_n_i <= "0X";
wait for 20 ns; -- Constraint 13.
VME_DS_n_i <= "00";
read_wait_dtack;
if bus_timer = '0' then
d16 := VME_DATA_o (15 downto 0);
else
d16 := (others => 'X');
end if;
read_release;
assert d16 = x"8765" report "bad read16 with delayed DS"
severity error;
when 8 | 9 =>
-- Check AM decoders (8: DECODE_AM = true, 9: DECODE_AM = false)
-- Set ADER
write8_conf (x"7_ff63", x"56");
write8_conf (x"7_ff6f", c_AM_A32 & "00");
read8_conf (x"7_ff63", d8);
assert d8 = x"56" report "bad ADER0 value" severity error;
-- Enable card
write8_conf (x"7_fffb", b"0001_0000");
-- WB read
read8 (x"56_00_00_00", c_AM_A32, d8);
assert d8 = x"00" report "bad read at 000" severity error;
-- Try to read with a wrong AM.
read8 (x"56_00_00_00", c_AM_A32_SUP, d8);
if g_SCENARIO = 8 then
assert d8 = "XXXXXXXX" report "unexpected reply" severity error;
else
assert d8 = x"00"
report "bad read at 000 (no AM decode)" severity error;
end if;
-- However, the A24 decoder is not enabled.
read8 (x"56_00_00_00", c_AM_A24_S, d8);
assert d8 = "XXXXXXXX" report "unexpected reply" severity error;
-- TODO: check IACK propagation.
end case;
wait for 4 * g_CLOCK_PERIOD * 1 ns;
end_tb <= true;
assert false report "end of simulation" severity note;
wait;
end process;
end behaviour;