pax_global_header 0000666 0000000 0000000 00000000064 12572445207 0014522 g ustar 00root root 0000000 0000000 52 comment=d99f18e06730a7640247d0e20f6cb1eaf5631348
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/ 0000775 0000000 0000000 00000000000 12572445207 0020021 5 ustar 00root root 0000000 0000000 x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/.gitmodules 0000664 0000000 0000000 00000000237 12572445207 0022200 0 ustar 00root root 0000000 0000000 [submodule "x393"]
path = x393
url = https://github.com/Elphel/x393.git
[submodule "gtxe2_gpl"]
path = gtxe2_gpl
url = https://github.com/Elphel/gtxe2_gpl
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/LICENSE 0000664 0000000 0000000 00000104506 12572445207 0021034 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, 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
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/README.md 0000664 0000000 0000000 00000001437 12572445207 0021305 0 ustar 00root root 0000000 0000000 # x393_sata
SATA controller for x393 camera
Board: Zynq 7z30
FPGA: Kintex-7
# Current step:
Testing basic functionallity of a host.
Trying out pio access.
Fullfilling device-side drivers and monitors via tasks.
Tests are mostly manual, relied on a common sense and waveforms instpection. Still, complatible both with gtx-gpl and unisims/gtx
# Going to do afterwards:
Test dma functionallity of the host.
Make cocotb testbench - gtx-gpl only - random payload high-level verification testing purposes.
Create a base of regression tests, containing lower-level tests - both gtx-gpl and unisims/gtx.
Improve an implementation of DMA control module.
Finally decide what to do with a driver and modify application level (actally, write it from scrap) correspodning to driver's interfaces.
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/device/ 0000775 0000000 0000000 00000000000 12572445207 0021260 5 ustar 00root root 0000000 0000000 x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/device/dev_phy.v 0000664 0000000 0000000 00000073276 12572445207 0023124 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: dev_phy
* Date: 2015-07-11
* Author: Alexey
* Description: sata device phy level
*
* Copyright (c) 2015 Elphel, Inc.
* dev_phy.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dev_phy.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/*
* Has minor differences from host's phy. After host would be rewritten all differences
* shall be eliminated.
* Despite having phy-level, the device for now is planned to be simulation purposes only.
*/
module sata_phy(
input wire RXP0_IN, // Receiver input
input wire RXN0_IN, // Receiver input
input wire GTXRESET_IN, // Main reset
input wire CLKIN_150, // external 150 mhz clock input
// Input from Link Layer
input wire [31:0] tx_datain,
input wire [3:0] tx_charisk_in,
output wire DCMLOCKED_OUT, // DCM locked
output wire PLLLKDET_OUT_N, // PLL Lock Detect
output wire TXP0_OUT,
output wire TXN0_OUT,
output wire LINKUP,
output wire LINKUP_led,
output wire GEN2_led,
output wire align_en_out,
output wire sata_user_clk,
// Outputs to Link Layer
output wire [31:0] rx_dataout,
output wire [3:0] rx_charisk_out,
output wire [7:0] CurrentState_out,
output wire rxelecidle_out,
// Rudiments
input wire [35:0] sata_phy_ila_control,
input wire [35:0] oob_control_ila_control
);
parameter CHIPSCOPE = "FALSE";
wire [31:0] txdata;
wire txcharisk;
wire [63:0] rxdata;
wire [7:0] rxcharisk;
wire [31:0] rxdata_out;
wire [3:0] rxcharisk_out;
wire linkup;
wire linkup_led;
wire rxcomwakedet;
wire rxcominitdet;
wire cplllock;
wire txcominit;
wire txcomwake;
wire rxreset;
wire rxelecidle;
wire txelecidle;
wire rxbyteisaligned;
OOB_control oob_control(
.oob_control_ila_control (36'h0),
//-------- GTX Ports --------/
.clk (sata_user_clk),
.reset (GTXRESET_IN),
.rxreset (/*rxreset*/),
.rx_locked (cplllock),
// OOB generation and detection signals from GTX
.txcominit (txcominit),
.txcomwake (txcomwake),
.cominitdet (rxcominitdet),
.comwakedet (rxcomwakedet),
.rxelecidle (rxelecidle),
.txelecidle_out (txelecidle),
.rxbyteisaligned (rxbyteisaligned),
.tx_dataout (txdata), // outgoing GTX data
.tx_charisk_out (txcharisk), // GTX charisk out
.rx_datain (rxdata[31:0]), // incoming GTX data
.rx_charisk_in (rxcharisk[3:0]), // GTX charisk in
.gen2 (1'b1), // for SATA Generation 2
//----- USER DATA PORTS---------//
.tx_datain (tx_datain), // User datain port
.tx_charisk_in (tx_charisk_in), // User charisk in port
.rx_dataout (rxdata_out), // User dataout port
.rx_charisk_out (rxcharisk_out), // User charisk out port
.linkup (linkup),
.linkup_led_out (linkup_led),
.align_en_out (align_en_out),
.CurrentState_out (CurrentState_out)
);
wire cplllockdetclk; // TODO
wire drpclk; // TODO
wire cpllreset;
wire gtrefclk;
wire rxresetdone;
wire txresetdone;
wire txreset;
wire txuserrdy;
wire rxuserrdy;
wire txusrclk;
wire txusrclk2;
wire rxusrclk;
wire rxusrclk2;
wire txp;
wire txn;
wire rxp;
wire rxn;
wire txoutclk;
wire txpmareset_done;
wire rxeyereset_done;
// tx reset sequence; waves @ ug476 p67
localparam TXPMARESET_TIME = 5'h1;
reg [2:0] txpmareset_cnt;
assign txpmareset_done = txpmareset_cnt == TXPMARESET_TIME;
always @ (posedge gtrefclk)
txpmareset_cnt <= txreset ? 3'h0 : txpmareset_done ? txpmareset_cnt : txpmareset_cnt + 1'b1;
// rx reset sequence; waves @ ug476 p77
localparam RXPMARESET_TIME = 5'h11;
localparam RXCDRPHRESET_TIME = 5'h1;
localparam RXCDRFREQRESET_TIME = 5'h1;
localparam RXDFELPMRESET_TIME = 7'hf;
localparam RXISCANRESET_TIME = 5'h1;
localparam RXEYERESET_TIME = 7'h0 + RXPMARESET_TIME + RXCDRPHRESET_TIME + RXCDRFREQRESET_TIME + RXDFELPMRESET_TIME + RXISCANRESET_TIME;
reg [6:0] rxeyereset_cnt;
assign rxeyereset_done = rxeyereset_cnt == RXEYERESET_TIME;
always @ (posedge gtrefclk)
rxeyereset_cnt <= rxreset ? 3'h0 : rxeyereset_done ? rxeyereset_cnt : rxeyereset_cnt + 1'b1;
/*
* Resets
*/
wire usrpll_locked;
assign cpllreset = GTXRESET_IN;
assign rxreset = ~cplllock | cpllreset;
assign txreset = ~cplllock | cpllreset;
assign rxuserrdy = usrpll_locked & cplllock & ~cpllreset & ~rxreset & rxeyereset_done;
assign txuserrdy = usrpll_locked & cplllock & ~cpllreset & ~txreset & txpmareset_done;
/*
* USRCLKs generation. USRCLK @ 150MHz, same as TXOUTCLK; USRCLK2 @ 75Mhz -> sata_clk === sclk
* It's recommended to use MMCM instead of PLL, whatever
*/
wire usrpll_fb_clk;
wire usrclk;
wire usrclk2;
assign txusrclk = usrclk;
assign txusrclk2 = usrclk2;
assign rxusrclk = usrclk;
assign rxusrclk2 = usrclk2;
PLLE2_ADV #(
.BANDWIDTH ("OPTIMIZED"),
.CLKFBOUT_MULT (8),
.CLKFBOUT_PHASE (0.000),
.CLKIN1_PERIOD (6.666),
.CLKIN2_PERIOD (0.000),
.CLKOUT0_DIVIDE (8),
.CLKOUT0_DUTY_CYCLE (0.500),
.CLKOUT0_PHASE (0.000),
.CLKOUT1_DIVIDE (16),
.CLKOUT1_DUTY_CYCLE (0.500),
.CLKOUT1_PHASE (0.000),
/* .CLKOUT2_DIVIDE = 1,
.CLKOUT2_DUTY_CYCLE = 0.500,
.CLKOUT2_PHASE = 0.000,
.CLKOUT3_DIVIDE = 1,
.CLKOUT3_DUTY_CYCLE = 0.500,
.CLKOUT3_PHASE = 0.000,
.CLKOUT4_DIVIDE = 1,
.CLKOUT4_DUTY_CYCLE = 0.500,
.CLKOUT4_PHASE = 0.000,
.CLKOUT5_DIVIDE = 1,
.CLKOUT5_DUTY_CYCLE = 0.500,
.CLKOUT5_PHASE = 0.000,*/
.COMPENSATION ("ZHOLD"),
.DIVCLK_DIVIDE (1),
.IS_CLKINSEL_INVERTED (1'b0),
.IS_PWRDWN_INVERTED (1'b0),
.IS_RST_INVERTED (1'b0),
.REF_JITTER1 (0.010),
.REF_JITTER2 (0.010),
.STARTUP_WAIT ("FALSE")
)
usrclk_pll(
.CLKFBOUT (usrpll_fb_clk),
.CLKOUT0 (usrclk),
.CLKOUT1 (usrclk2),
.CLKOUT2 (),
.CLKOUT3 (),
.CLKOUT4 (),
.CLKOUT5 (),
.DO (),
.DRDY (),
.LOCKED (usrpll_locked),
.CLKFBIN (usrpll_fb_clk),
.CLKIN1 (txoutclk),
.CLKIN2 (1'b0),
.CLKINSEL (1'b1),
.DADDR (7'h0),
.DCLK (drpclk),
.DEN (1'b0),
.DI (16'h0),
.DWE (1'b0),
.PWRDWN (1'b0),
.RST (~cplllock)
);
/*
* Padding for an external input clock @ 150 MHz
* TODO !!! Temporary moved to sata_top
*/
assign gtrefclk = CLKIN_150;
/*localparam [1:0] CLKSWING_CFG = 2'b11;
IBUFDS_GTE2 #(
.CLKRCV_TRST ("TRUE"),
.CLKCM_CFG ("TRUE"),
.CLKSWING_CFG (CLKSWING_CFG)
)
ext_clock_buf(
.I (REFCLK_PAD_P_IN),
.IB (REFCLK_PAD_N_IN),
.CEB (1'b0),
.O (gtrefclk),
.ODIV2 ()
);
*/
GTXE2_CHANNEL #(
.SIM_RECEIVER_DETECT_PASS ("TRUE"),
.SIM_TX_EIDLE_DRIVE_LEVEL ("X"),
.SIM_RESET_SPEEDUP ("FALSE"),
.SIM_CPLLREFCLK_SEL (3'b001),
.SIM_VERSION ("4.0"),
.ALIGN_COMMA_DOUBLE ("FALSE"),
.ALIGN_COMMA_ENABLE (10'b1111111111),
.ALIGN_COMMA_WORD (1),
.ALIGN_MCOMMA_DET ("TRUE"),
.ALIGN_MCOMMA_VALUE (10'b1010000011),
.ALIGN_PCOMMA_DET ("TRUE"),
.ALIGN_PCOMMA_VALUE (10'b0101111100),
.SHOW_REALIGN_COMMA ("TRUE"),
.RXSLIDE_AUTO_WAIT (7),
.RXSLIDE_MODE ("OFF"),
.RX_SIG_VALID_DLY (10),
.RX_DISPERR_SEQ_MATCH ("TRUE"),
.DEC_MCOMMA_DETECT ("TRUE"),
.DEC_PCOMMA_DETECT ("TRUE"),
.DEC_VALID_COMMA_ONLY ("FALSE"),
.CBCC_DATA_SOURCE_SEL ("DECODED"),
.CLK_COR_SEQ_2_USE ("FALSE"),
.CLK_COR_KEEP_IDLE ("FALSE"),
.CLK_COR_MAX_LAT (9),
.CLK_COR_MIN_LAT (7),
.CLK_COR_PRECEDENCE ("TRUE"),
.CLK_COR_REPEAT_WAIT (0),
.CLK_COR_SEQ_LEN (1),
.CLK_COR_SEQ_1_ENABLE (4'b1111),
.CLK_COR_SEQ_1_1 (10'b0100000000),
.CLK_COR_SEQ_1_2 (10'b0000000000),
.CLK_COR_SEQ_1_3 (10'b0000000000),
.CLK_COR_SEQ_1_4 (10'b0000000000),
.CLK_CORRECT_USE ("FALSE"),
.CLK_COR_SEQ_2_ENABLE (4'b1111),
.CLK_COR_SEQ_2_1 (10'b0100000000),
.CLK_COR_SEQ_2_2 (10'b0000000000),
.CLK_COR_SEQ_2_3 (10'b0000000000),
.CLK_COR_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_KEEP_ALIGN ("FALSE"),
.CHAN_BOND_MAX_SKEW (1),
.CHAN_BOND_SEQ_LEN (1),
.CHAN_BOND_SEQ_1_1 (10'b0000000000),
.CHAN_BOND_SEQ_1_2 (10'b0000000000),
.CHAN_BOND_SEQ_1_3 (10'b0000000000),
.CHAN_BOND_SEQ_1_4 (10'b0000000000),
.CHAN_BOND_SEQ_1_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_1 (10'b0000000000),
.CHAN_BOND_SEQ_2_2 (10'b0000000000),
.CHAN_BOND_SEQ_2_3 (10'b0000000000),
.CHAN_BOND_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_SEQ_2_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_USE ("FALSE"),
.FTS_DESKEW_SEQ_ENABLE (4'b1111),
.FTS_LANE_DESKEW_CFG (4'b1111),
.FTS_LANE_DESKEW_EN ("FALSE"),
.ES_CONTROL (6'b000000),
.ES_ERRDET_EN ("FALSE"),
.ES_EYE_SCAN_EN ("TRUE"),
.ES_HORZ_OFFSET (12'h000),
.ES_PMA_CFG (10'b0000000000),
.ES_PRESCALE (5'b00000),
.ES_QUALIFIER (80'h00000000000000000000),
.ES_QUAL_MASK (80'h00000000000000000000),
.ES_SDATA_MASK (80'h00000000000000000000),
.ES_VERT_OFFSET (9'b000000000),
.RX_DATA_WIDTH (20),
.OUTREFCLK_SEL_INV (2'b11),
.PMA_RSV (32'h00018480),
.PMA_RSV2 (16'h2050),
.PMA_RSV3 (2'b00),
.PMA_RSV4 (32'h00000000),
.RX_BIAS_CFG (12'b000000000100),
.DMONITOR_CFG (24'h000A00),
.RX_CM_SEL (2'b11),
.RX_CM_TRIM (3'b010),
.RX_DEBUG_CFG (12'b000000000000),
.RX_OS_CFG (13'b0000010000000),
.TERM_RCAL_CFG (5'b10000),
.TERM_RCAL_OVRD (1'b0),
.TST_RSV (32'h00000000),
.RX_CLK25_DIV (6),
.TX_CLK25_DIV (6),
.UCODEER_CLR (1'b0),
.PCS_PCIE_EN ("FALSE"),
.PCS_RSVD_ATTR (48'h0100),
.RXBUF_ADDR_MODE ("FAST"),
.RXBUF_EIDLE_HI_CNT (4'b1000),
.RXBUF_EIDLE_LO_CNT (4'b0000),
.RXBUF_EN ("TRUE"),
.RX_BUFFER_CFG (6'b000000),
.RXBUF_RESET_ON_CB_CHANGE ("TRUE"),
.RXBUF_RESET_ON_COMMAALIGN ("FALSE"),
.RXBUF_RESET_ON_EIDLE ("FALSE"),
.RXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.RXBUFRESET_TIME (5'b00001),
.RXBUF_THRESH_OVFLW (61),
.RXBUF_THRESH_OVRD ("FALSE"),
.RXBUF_THRESH_UNDFLW (4),
.RXDLY_CFG (16'h001F),
.RXDLY_LCFG (9'h030),
.RXDLY_TAP_CFG (16'h0000),
.RXPH_CFG (24'h000000),
.RXPHDLY_CFG (24'h084020),
.RXPH_MONITOR_SEL (5'b00000),
.RX_XCLK_SEL ("RXREC"),
.RX_DDI_SEL (6'b000000),
.RX_DEFER_RESET_BUF_EN ("TRUE"),
.RXCDR_CFG (72'h03000023ff10200020),
.RXCDR_FR_RESET_ON_EIDLE (1'b0),
.RXCDR_HOLD_DURING_EIDLE (1'b0),
.RXCDR_PH_RESET_ON_EIDLE (1'b0),
.RXCDR_LOCK_CFG (6'b010101),
.RXCDRFREQRESET_TIME (RXCDRFREQRESET_TIME),
.RXCDRPHRESET_TIME (RXCDRPHRESET_TIME),
.RXISCANRESET_TIME (RXISCANRESET_TIME),
.RXPCSRESET_TIME (5'b00001),
.RXPMARESET_TIME (RXPMARESET_TIME),
.RXOOB_CFG (7'b0000110),
.RXGEARBOX_EN ("FALSE"),
.GEARBOX_MODE (3'b000),
.RXPRBS_ERR_LOOPBACK (1'b0),
.PD_TRANS_TIME_FROM_P2 (12'h03c),
.PD_TRANS_TIME_NONE_P2 (8'h3c),
.PD_TRANS_TIME_TO_P2 (8'h64),
.SAS_MAX_COM (64),
.SAS_MIN_COM (36),
.SATA_BURST_SEQ_LEN (4'b0111),
.SATA_BURST_VAL (3'b110),
.SATA_EIDLE_VAL (3'b110),
.SATA_MAX_BURST (8),
.SATA_MAX_INIT (21),
.SATA_MAX_WAKE (7),
.SATA_MIN_BURST (4),
.SATA_MIN_INIT (12),
.SATA_MIN_WAKE (4),
.TRANS_TIME_RATE (8'h0E),
.TXBUF_EN ("TRUE"),
.TXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.TXDLY_CFG (16'h001F),
.TXDLY_LCFG (9'h030),
.TXDLY_TAP_CFG (16'h0000),
.TXPH_CFG (16'h0780),
.TXPHDLY_CFG (24'h084020),
.TXPH_MONITOR_SEL (5'b00000),
.TX_XCLK_SEL ("TXOUT"),
.TX_DATA_WIDTH (40),
.TX_DEEMPH0 (5'b00000),
.TX_DEEMPH1 (5'b00000),
.TX_EIDLE_ASSERT_DELAY (3'b110),
.TX_EIDLE_DEASSERT_DELAY (3'b100),
.TX_LOOPBACK_DRIVE_HIZ ("FALSE"),
.TX_MAINCURSOR_SEL (1'b0),
.TX_DRIVE_MODE ("DIRECT"),
.TX_MARGIN_FULL_0 (7'b1001110),
.TX_MARGIN_FULL_1 (7'b1001001),
.TX_MARGIN_FULL_2 (7'b1000101),
.TX_MARGIN_FULL_3 (7'b1000010),
.TX_MARGIN_FULL_4 (7'b1000000),
.TX_MARGIN_LOW_0 (7'b1000110),
.TX_MARGIN_LOW_1 (7'b1000100),
.TX_MARGIN_LOW_2 (7'b1000010),
.TX_MARGIN_LOW_3 (7'b1000000),
.TX_MARGIN_LOW_4 (7'b1000000),
.TXGEARBOX_EN ("FALSE"),
.TXPCSRESET_TIME (5'b00001),
.TXPMARESET_TIME (TXPMARESET_TIME),
.TX_RXDETECT_CFG (14'h1832),
.TX_RXDETECT_REF (3'b100),
.CPLL_CFG (24'hBC07DC),
.CPLL_FBDIV (4),
.CPLL_FBDIV_45 (5),
.CPLL_INIT_CFG (24'h00001E),
.CPLL_LOCK_CFG (16'h01E8),
.CPLL_REFCLK_DIV (1),
.RXOUT_DIV (2),
.TXOUT_DIV (2),
.SATA_CPLL_CFG ("VCO_3000MHZ"),
.RXDFELPMRESET_TIME (RXDFELPMRESET_TIME),
.RXLPM_HF_CFG (14'b00000011110000),
.RXLPM_LF_CFG (14'b00000011110000),
.RX_DFE_GAIN_CFG (23'h020FEA),
.RX_DFE_H2_CFG (12'b000000000000),
.RX_DFE_H3_CFG (12'b000001000000),
.RX_DFE_H4_CFG (11'b00011110000),
.RX_DFE_H5_CFG (11'b00011100000),
.RX_DFE_KL_CFG (13'b0000011111110),
.RX_DFE_LPM_CFG (16'h0954),
.RX_DFE_LPM_HOLD_DURING_EIDLE (1'b0),
.RX_DFE_UT_CFG (17'b10001111000000000),
.RX_DFE_VP_CFG (17'b00011111100000011),
.RX_CLKMUX_PD (1'b1),
.TX_CLKMUX_PD (1'b1),
.RX_INT_DATAWIDTH (0),
.TX_INT_DATAWIDTH (0),
.TX_QPI_STATUS_EN (1'b0),
.RX_DFE_KL_CFG2 (32'h301148AC),
.RX_DFE_XYD_CFG (13'b0000000000000),
.TX_PREDRIVER_MODE (1'b0)
)
dut(
.CPLLFBCLKLOST (),
.CPLLLOCK (cplllock),
.CPLLLOCKDETCLK (cplllockdetclk),
.CPLLLOCKEN (1'b1),
.CPLLPD (1'b0),
.CPLLREFCLKLOST (),
.CPLLREFCLKSEL (3'b001),
.CPLLRESET (cpllreset),
.GTRSVD (1'b0),
.PCSRSVDIN (1'b0),
.PCSRSVDIN2 (1'b0),
.PMARSVDIN (1'b0),
.PMARSVDIN2 (1'b0),
.TSTIN (1'b1),
.TSTOUT (),
.CLKRSVD (4'b0000),
.GTGREFCLK (1'b0),
.GTNORTHREFCLK0 (1'b0),
.GTNORTHREFCLK1 (1'b0),
.GTREFCLK0 (gtrefclk),
.GTREFCLK1 (1'b0),
.GTSOUTHREFCLK0 (1'b0),
.GTSOUTHREFCLK1 (1'b0),
.DRPADDR (9'b0),
.DRPCLK (drpclk),
.DRPDI (16'b0),
.DRPDO (),
.DRPEN (1'b0),
.DRPRDY (),
.DRPWE (1'b0),
.GTREFCLKMONITOR (),
.QPLLCLK (gtrefclk),
.QPLLREFCLK (gtrefclk),
.RXSYSCLKSEL (2'b00),
.TXSYSCLKSEL (2'b00),
.DMONITOROUT (),
.TX8B10BEN (1'b1),
.LOOPBACK (3'd0),
.PHYSTATUS (),
.RXRATE (3'd0),
.RXVALID (),
.RXPD (2'b00),
.TXPD (2'b00),
.SETERRSTATUS (1'b0),
.EYESCANRESET (1'b0),//rxreset), // p78
.RXUSERRDY (rxuserrdy),
.EYESCANDATAERROR (),
.EYESCANMODE (1'b0),
.EYESCANTRIGGER (1'b0),
.RXCDRFREQRESET (1'b0),
.RXCDRHOLD (1'b0),
.RXCDRLOCK (),
.RXCDROVRDEN (1'b0),
.RXCDRRESET (1'b0),
.RXCDRRESETRSV (1'b0),
.RXCLKCORCNT (),
.RX8B10BEN (1'b1),
.RXUSRCLK (rxusrclk),
.RXUSRCLK2 (rxusrclk2),
.RXDATA (rxdata),
.RXPRBSERR (),
.RXPRBSSEL (3'd0),
.RXPRBSCNTRESET (1'b0),
.RXDFEXYDEN (1'b1),
.RXDFEXYDHOLD (1'b0),
.RXDFEXYDOVRDEN (1'b0),
.RXDISPERR (),
.RXNOTINTABLE (),
.GTXRXP (rxp),
.GTXRXN (rxn),
.RXBUFRESET (1'b0),
.RXBUFSTATUS (),
.RXDDIEN (1'b0),
.RXDLYBYPASS (1'b1),
.RXDLYEN (1'b0),
.RXDLYOVRDEN (1'b0),
.RXDLYSRESET (1'b0),
.RXDLYSRESETDONE (),
.RXPHALIGN (1'b0),
.RXPHALIGNDONE (),
.RXPHALIGNEN (1'b0),
.RXPHDLYPD (1'b0),
.RXPHDLYRESET (1'b0),
.RXPHMONITOR (),
.RXPHOVRDEN (1'b0),
.RXPHSLIPMONITOR (),
.RXSTATUS (),
.RXBYTEISALIGNED (rxbyteisaligned),
.RXBYTEREALIGN (),
.RXCOMMADET (),
.RXCOMMADETEN (1'b1),
.RXMCOMMAALIGNEN (1'b1),
.RXPCOMMAALIGNEN (1'b1),
.RXCHANBONDSEQ (),
.RXCHBONDEN (1'b0),
.RXCHBONDLEVEL (3'd0),
.RXCHBONDMASTER (1'b0),
.RXCHBONDO (),
.RXCHBONDSLAVE (1'b0),
.RXCHANISALIGNED (),
.RXCHANREALIGN (),
.RXLPMHFHOLD (1'b0),
.RXLPMHFOVRDEN (1'b0),
.RXLPMLFHOLD (1'b0),
.RXDFEAGCHOLD (1'b0),
.RXDFEAGCOVRDEN (1'b0),
.RXDFECM1EN (1'b0),
.RXDFELFHOLD (1'b0),
.RXDFELFOVRDEN (1'b1),
.RXDFELPMRESET (rxreset),
.RXDFETAP2HOLD (1'b0),
.RXDFETAP2OVRDEN (1'b0),
.RXDFETAP3HOLD (1'b0),
.RXDFETAP3OVRDEN (1'b0),
.RXDFETAP4HOLD (1'b0),
.RXDFETAP4OVRDEN (1'b0),
.RXDFETAP5HOLD (1'b0),
.RXDFETAP5OVRDEN (1'b0),
.RXDFEUTHOLD (1'b0),
.RXDFEUTOVRDEN (1'b0),
.RXDFEVPHOLD (1'b0),
.RXDFEVPOVRDEN (1'b0),
// .RXDFEVSEN (1'b0),
.RXLPMLFKLOVRDEN (1'b0),
.RXMONITOROUT (),
.RXMONITORSEL (2'b01),
.RXOSHOLD (1'b0),
.RXOSOVRDEN (1'b0),
.RXRATEDONE (),
.RXOUTCLK (),
.RXOUTCLKFABRIC (),
.RXOUTCLKPCS (),
.RXOUTCLKSEL (3'b010),
.RXDATAVALID (),
.RXHEADER (),
.RXHEADERVALID (),
.RXSTARTOFSEQ (),
.RXGEARBOXSLIP (1'b0),
.GTRXRESET (rxreset),
.RXOOBRESET (1'b0),
.RXPCSRESET (1'b0),
.RXPMARESET (1'b0),//rxreset), // p78
.RXLPMEN (1'b0),
.RXCOMSASDET (),
.RXCOMWAKEDET (rxcomwakedet),
.RXCOMINITDET (rxcominitdet),
.RXELECIDLE (rxelecidle),
.RXELECIDLEMODE (2'b00),
.RXPOLARITY (1'b0),
.RXSLIDE (1'b0),
.RXCHARISCOMMA (),
.RXCHARISK (rxcharisk),
.RXCHBONDI (5'b00000),
.RXRESETDONE (rxresetdone),
.RXQPIEN (1'b0),
.RXQPISENN (),
.RXQPISENP (),
.TXPHDLYTSTCLK (1'b0),
.TXPOSTCURSOR (5'b00000),
.TXPOSTCURSORINV (1'b0),
.TXPRECURSOR (5'd0),
.TXPRECURSORINV (1'b0),
.TXQPIBIASEN (1'b0),
.TXQPISTRONGPDOWN (1'b0),
.TXQPIWEAKPUP (1'b0),
.CFGRESET (1'b0),
.GTTXRESET (txreset),
.PCSRSVDOUT (),
.TXUSERRDY (txuserrdy),
.GTRESETSEL (1'b0),
.RESETOVRD (1'b0),
.TXCHARDISPMODE (8'd0),
.TXCHARDISPVAL (8'd0),
.TXUSRCLK (txusrclk),
.TXUSRCLK2 (txusrclk2),
.TXELECIDLE (txelecidle),
.TXMARGIN (3'd0),
.TXRATE (3'd0),
.TXSWING (1'b0),
.TXPRBSFORCEERR (1'b0),
.TXDLYBYPASS (1'b1),
.TXDLYEN (1'b0),
.TXDLYHOLD (1'b0),
.TXDLYOVRDEN (1'b0),
.TXDLYSRESET (1'b0),
.TXDLYSRESETDONE (),
.TXDLYUPDOWN (1'b0),
.TXPHALIGN (1'b0),
.TXPHALIGNDONE (),
.TXPHALIGNEN (1'b0),
.TXPHDLYPD (1'b0),
.TXPHDLYRESET (1'b0),
.TXPHINIT (1'b0),
.TXPHINITDONE (),
.TXPHOVRDEN (1'b0),
.TXBUFSTATUS (),
.TXBUFDIFFCTRL (3'b100),
.TXDEEMPH (1'b0),
.TXDIFFCTRL (4'b1000),
.TXDIFFPD (1'b0),
.TXINHIBIT (1'b0),
.TXMAINCURSOR (7'b0000000),
.TXPISOPD (1'b0),
.TXDATA ({32'h0, txdata}),
.GTXTXN (txn),
.GTXTXP (txp),
.TXOUTCLK (txoutclk),
.TXOUTCLKFABRIC (),
.TXOUTCLKPCS (),
.TXOUTCLKSEL (3'b010),
.TXRATEDONE (),
.TXCHARISK ({7'b0, txcharisk}),
.TXGEARBOXREADY (),
.TXHEADER (3'd0),
.TXSEQUENCE (7'd0),
.TXSTARTSEQ (1'b0),
.TXPCSRESET (1'b0),
.TXPMARESET (1'b0),
.TXRESETDONE (txresetdone),
.TXCOMFINISH (),
.TXCOMINIT (txcominit),
.TXCOMSAS (1'b0),
.TXCOMWAKE (txcomwake),
.TXPDELECIDLEMODE (1'b0),
.TXPOLARITY (1'b0),
.TXDETECTRX (1'b0),
.TX8B10BBYPASS (8'd0),
.TXPRBSSEL (3'd0),
.TXQPISENN (),
.TXQPISENP ()/*,
.TXSYNCMODE (1'b0),
.TXSYNCALLIN (1'b0),
.TXSYNCIN (1'b0)*/
);
/*
* Interfaces
*/
assign DCMLOCKED_OUT = usrpll_locked;
assign PLLLKDET_OUT_N = cplllock;
assign rxn = RXN0_IN;
assign rxp = RXP0_IN;
assign TXN0_OUT = txn;
assign TXP0_OUT = txp;
assign cplllockdetclk = CLKIN_150;
assign drpclk = CLKIN_150;
assign LINKUP = linkup;
assign LINKUP_led = linkup_led;
assign rx_dataout = rxdata_out;
assign rx_charisk_out = rxcharisk_out;
assign rxelecidle_out = rxelecidle;
assign GEN2_led = 1'b0;
assign sata_user_clk = usrclk2;
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/device/device_tasks.v 0000664 0000000 0000000 00000000424 12572445207 0024113 0 ustar 00root root 0000000 0000000 wire [31:0] phy2dev_data;
wire [3:0] phy2dev_charisk;
wire [3:0] phy2dev_err;
wire dev_clk;
wire dev_rst;
reg [31:0] dev2phy_data;
reg [3:0] dev2phy_charisk;
force dev.dev2phy_data =
force dev.dev2phy_charisk =
task
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/device/oob_ctrl_dev.v 0000664 0000000 0000000 00000013731 12572445207 0024115 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: oob_ctrl
* Date: 2015-07-11
* Author: Alexey
* Description: module to start oob sequences and to handle errors
*
* Copyright (c) 2015 Elphel, Inc.
* oob_ctrl.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* oob_ctrl.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`include "oob.v"
module oob_ctrl_dev #(
parameter DATA_BYTE_WIDTH = 4,
parameter CLK_SPEED_GRADE = 2 // 1 - 75 Mhz, 2 - 150Mhz, 4 - 300Mhz
)
(
// sata clk = usrclk2
input wire clk,
// reset oob
input wire rst,
// gtx is ready = all resets are done
input wire gtx_ready,
// oob responces
input wire rxcominitdet_in,
input wire rxcomwakedet_in,
input wire rxelecidle_in,
// oob issues
output wire txcominit,
output wire txcomwake,
output wire txelecidle,
// input data stream (if any data during OOB setting => ignored)
input wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_in,
input wire [DATA_BYTE_WIDTH - 1:0] txcharisk_in,
// output data stream to gtx
output wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_out,
output wire [DATA_BYTE_WIDTH - 1:0] txcharisk_out,
// input data from gtx
input wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_in,
input wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_in,
// bypassed data from gtx
output wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_out,
output wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_out,
// obvious
input wire rxbyteisaligned,
// shows if channel is ready
output wire phy_ready
);
// oob sequence needs to be issued
wire oob_start;
// connection established, all further data is valid
wire oob_done;
// doc p265, link is established after 3back-to-back non-ALIGNp
wire link_up;
wire link_down;
// the device itself sends cominit
wire cominit_req;
// allow to respond to cominit
wire cominit_allow;
// status information to handle by a control block if any exists
// incompatible host-device speed grades (host cannot lock to alignp)
wire oob_incompatible; // TODO
// timeout in an unexpected place
wire oob_error;
// noone responds to our cominits
wire oob_silence;
// obvious
wire oob_busy;
// for the resync sake
reg rxbyteisaligned_r;
reg rxbyteisaligned_rr;
always @ (posedge clk)
begin
rxbyteisaligned_rr <= rxbyteisaligned_r;
rxbyteisaligned_r <= rxbyteisaligned;
end
// 1 - link is up and running, 0 - probably not
reg link_state;
// 1 - connection is being established OR already established, 0 - is not
reg oob_state;
assign phy_ready = link_state & gtx_ready & rxbyteisaligned_rr;
always @ (posedge clk)
link_state <= (link_state | link_up) & ~link_down & ~rst;
always @ (posedge clk)
oob_state <= (oob_state | oob_start | cominit_req & cominit_allow) & ~oob_error & ~oob_silence & link_down & ~rst;
// decide when to issue oob: always when gtx is ready
assign oob_start = gtx_ready & ~oob_state & ~oob_busy;
// set line to idle state before if we're waiting for a device to answer AND while oob sequence
wire txelecidle_inner;
assign txelecidle = ~oob_state | txelecidle_inner;
// let devices always begin oob sequence, if only it's not a glitch
assign cominit_allow = cominit_req & link_state;
oob_dev #(
.DATA_BYTE_WIDTH (DATA_BYTE_WIDTH),
.CLK_SPEED_GRADE (CLK_SPEED_GRADE)
)
oob_dev
(
// sata clk = usrclk2
.clk (clk),
// reset oob
.rst (rst),
// oob responces
.rxcominitdet_in (rxcominitdet_in),
.rxcomwakedet_in (rxcomwakedet_in),
.rxelecidle_in (rxelecidle_in),
// oob issues
.txcominit (txcominit),
.txcomwake (txcomwake),
.txelecidle (txelecidle_inner),
// input data stream (if any data during OOB setting => ignored)
.txdata_in (txdata_in),
.txcharisk_in (txcharisk_in),
// output data stream to gtx
.txdata_out (txdata_out),
.txcharisk_out (txcharisk_out),
// input data from gtx
.rxdata_in (rxdata_in),
.rxcharisk_in (rxcharisk_in),
// bypassed data from gtx
.rxdata_out (rxdata_out),
.rxcharisk_out (rxcharisk_out),
// oob sequence needs to be issued
.oob_start (oob_start),
// connection established, all further data is valid
.oob_done (oob_done),
// doc p265, link is established after 3back-to-back non-ALIGNp
.link_up (link_up),
.link_down (link_down),
// the device itself sends cominit
.cominit_req (cominit_req),
// allow to respond to cominit
.cominit_allow (cominit_allow),
// status information to handle by a control block if any exists
// incompatible host-device speed grades (host cannot lock to alignp)
.oob_incompatible (oob_incompatible),
// timeout in an unexpected place
.oob_error (oob_error),
// noone responds to our cominits
.oob_silence (oob_silence),
// oob can't handle new start request
.oob_busy (oob_busy)
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/device/oob_dev.v 0000664 0000000 0000000 00000037102 12572445207 0023067 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: oob
* Date: 2015-07-11
* Author: Alexey
* Description: sata oob unit implementation
*
* Copyright (c) 2015 Elphel, Inc.
* oob.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* oob.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/*
* For now both device and host shall be set up to SATA2 speeds.
* Need to think how to change speed grades on fly (either to broaden
* data iface width or to change RXRATE/TXRATE)
*/
// All references to doc = to SerialATA_Revision_2_6_Gold.pdf
module oob_dev #(
parameter DATA_BYTE_WIDTH = 4,
parameter CLK_SPEED_GRADE = 2 // 1 - 75 Mhz, 2 - 150Mhz, 4 - 300Mhz
)
(
// sata clk = usrclk2
input wire clk,
// reset oob
input wire rst,
input wire gtx_ready,
// oob responces
input wire rxcominitdet_in,
input wire rxcomwakedet_in,
input wire rxelecidle_in,
// oob issues
output reg txcominit,
output reg txcomwake,
output reg txelecidle,
output wire txpcsreset_req,
input wire recal_tx_done,
// output data stream to gtx
output wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_out,
output wire [DATA_BYTE_WIDTH - 1:0] txcharisk_out,
// input data from gtx
input wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_in,
input wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_in,
output wire link_up
);
localparam STATE_RESET = 0;
localparam STATE_COMINIT = 1;
localparam STATE_AWAITCOMWAKE = 2;
localparam STATE_AWAITNOCOMWAKE = 3;
localparam STATE_CALIBRATE = 4;
localparam STATE_COMWAKE = 5;
localparam STATE_RECAL = 55;
localparam STATE_SENDALIGN = 6;
localparam STATE_READY = 7;
localparam STATE_PARTIAL = 8;
localparam STATE_SLUMBER = 9;
localparam STATE_REDUCESPEED = 10;
localparam STATE_ERROR = 11;
reg [9:0] state;
wire retry_interval_elapsed;
wire wait_interval_elapsed;
wire nocomwake;
wire [31:0] align;
wire [31:0] sync;
assign align = {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}; // {D27.3, D10.2, D10.2, K28.5}
assign sync = {8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}; // {D21.5, D21.5, D21.4, K28.3}
reg [31:0] nocomwake_timer;
assign nocomwake = nocomwake_timer == 32'd38;
always @ (posedge clk)
nocomwake_timer <= rst | rxcomwakedet_in ? 32'h0 : nocomwake ? nocomwake_timer : nocomwake_timer + 1'b1;
reg [31:0] retry_timer;
assign retry_interval_elapsed = retry_timer == 32'd1000;
always @ (posedge clk)
retry_timer <= rst | ~(state == STATE_AWAITCOMWAKE) ? 32'h0 : retry_timer + 1'b1;
reg [31:0] wait_timer;
assign wait_interval_elapsed = wait_timer == 32'd4096;
always @ (posedge clk)
wait_timer <= rst | ~(state == STATE_SENDALIGN) ? 32'h0 : wait_timer + 1'b1;
reg [31:0] data;
reg [3:0] isk;
assign link_up = state == STATE_READY;
assign txdata_out = data;
assign txcharisk_out = isk;
// buf inputs from gtx
reg rxcominitdet;
reg rxcomwakedet;
reg rxelecidle;
reg [31:0] rxdata;
reg [3:0] rxcharisk;
always @ (posedge clk)
begin
rxcominitdet <= rxcominitdet_in;
rxcomwakedet <= rxcomwakedet_in;
rxelecidle <= rxelecidle_in;
rxdata <= rxdata_in;
rxcharisk <= rxcharisk_in;
end
reg [9:0] txelecidle_cnt;
assign aligndet = ~|(rxdata ^ {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}) & ~|(rxcharisk ^ 4'h1); // {D27.3, D10.2, D10.2, K28.5}
assign syncdet = ~|(rxdata ^ {8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}) & ~|(rxcharisk ^ 4'h1); // {D21.5, D21.5, D21.4, K28.3}
assign txpcsreset_req = state == STATE_RECAL & (txelecidle_cnt == 10'd160);
always @ (posedge clk)
if (rst | (~gtx_ready & ~(state == STATE_RECAL)))
begin
state <= STATE_RESET;
txelecidle <= 1'b1;
txcominit <= 1'b0;
txcomwake <= 1'b0;
txelecidle_cnt <= 10'h0;
end
else
case (state)
STATE_RESET:
begin
if (rxcominitdet) begin
txelecidle_cnt <= 10'h0;
state <= STATE_COMINIT;
txelecidle <= 1'b1;
txcominit <= 1'b0;
txcomwake <= 1'b0;
end
end
STATE_COMINIT:
begin
state <= STATE_AWAITCOMWAKE;
txcominit <= 1'b1;
end
STATE_AWAITCOMWAKE:
begin
txcominit <= 1'b0;
if (rxcomwakedet)
state <= STATE_AWAITNOCOMWAKE;
else
if (retry_interval_elapsed)
state <= STATE_RESET;
else
state <= STATE_AWAITCOMWAKE;
end
STATE_AWAITNOCOMWAKE:
begin
if (nocomwake)
begin
state <= STATE_CALIBRATE;
end
end
STATE_CALIBRATE:
begin
state <= STATE_COMWAKE;
end
STATE_COMWAKE:
begin
txcomwake <= 1'b1;
state <= STATE_RECAL;
txelecidle_cnt <= 10'h0;
end
STATE_RECAL:
begin
data <= align;
isk <= 4'h1;
txcomwake <= 1'b0;
// txcomwake period = 213.333 ns times let's say 10 pulses => 2133.333 ns = 160 cycles of 75Mhz
if (txelecidle_cnt == 10'd160) begin
txelecidle <= 1'b0;
end
else begin
txelecidle_cnt <= txelecidle_cnt + 1'b1;
end
if (recal_tx_done) begin
state <= STATE_SENDALIGN;
end
end
STATE_SENDALIGN:
begin
data <= align;
isk <= 4'h1;
if (aligndet)
state <= STATE_READY;
else
if (wait_interval_elapsed)
state <= STATE_ERROR;
else
state <= STATE_SENDALIGN;
end
STATE_READY:
begin
txelecidle <= 1'b0;
data <= sync;
isk <= 4'h1;
if (rxelecidle_in)
state <= STATE_ERROR;
end
STATE_ERROR:
begin
txelecidle <= 1'b0;
state <= STATE_RESET;
end
endcase
/*
// 873.8 us error timer
// = 2621400 SATA2 serial ticks (period = 0.000333 us)
// = 131070 ticks @ 150Mhz
// = 65535 ticks @ 75Mhz
localparam [19:0] CLK_TO_TIMER_CONTRIB = CLK_SPEED_GRADE == 1 ? 20'h4 :
CLK_SPEED_GRADE == 2 ? 20'h2 :
CLK_SPEED_GRADE == 4 ? 20'h1 : 20'h1;
`ifdef SIMULATION
localparam [19:0] TIMER_LIMIT = 19'd200;
`else
localparam [19:0] TIMER_LIMIT = 19'd262140;
`endif
reg [19:0] timer;
wire timer_clr;
wire timer_fin;
// latching inputs from gtx
reg rxcominitdet;
reg rxcomwakedet;
reg rxelecidle;
reg [DATA_BYTE_WIDTH*8 - 1:0] rxdata;
reg [DATA_BYTE_WIDTH - 1:0] rxcharisk;
// primitives detection
wire detected_alignp;
wire detected_syncp;
// fsm, doc p265,266
wire state_idle;
reg state_wait_cominit;
reg state_wait_comwake;
reg state_wait_align;
reg state_wait_synp;
reg state_wait_linkup;
reg state_error;
wire set_wait_cominit;
wire set_wait_comwake;
wire set_wait_align;
wire set_wait_synp;
wire set_wait_linkup;
wire set_error;
wire clr_wait_cominit;
wire clr_wait_comwake;
wire clr_wait_align;
wire clr_wait_synp;
wire clr_wait_linkup;
wire clr_error;
assign state_idle = ~state_wait_cominit & ~state_wait_comwake & ~state_wait_align & ~state_wait_synp & ~state_wait_linkup & ~state_error;
always @ (posedge clk)
begin
state_wait_cominit <= (state_wait_cominit | set_wait_cominit) & ~clr_wait_cominit & ~rst;
state_wait_comwake <= (state_wait_comwake | set_wait_comwake) & ~clr_wait_comwake & ~rst;
state_wait_align <= (state_wait_align | set_wait_align ) & ~clr_wait_align & ~rst;
state_wait_synp <= (state_wait_synp | set_wait_synp ) & ~clr_wait_synp & ~rst;
state_wait_linkup <= (state_wait_linkup | set_wait_linkup ) & ~clr_wait_linkup & ~rst;
state_error <= (state_error | set_error ) & ~clr_error & ~rst;
end
assign set_wait_cominit = state_idle & oob_start & ~cominit_req;
assign set_wait_comwake = state_idle & cominit_req & cominit_allow | state_wait_cominit & rxcominitdet;
assign set_wait_align = state_wait_comwake & rxcomwakedet;
assign set_wait_synp = state_wait_align & detected_alignp;
assign set_wait_linkup = state_wait_synp & detected_syncp;
assign set_error = timer_fin & (state_wait_cominit | state_wait_comwake | state_wait_align | state_wait_synp);
assign clr_wait_cominit = set_wait_comwake | set_error;
assign clr_wait_comwake = set_wait_align | set_error;
assign clr_wait_align = set_wait_synp | set_error;
assign clr_wait_synp = set_wait_linkup | set_error;
assign clr_wait_linkup = state_wait_linkup; //TODO not so important, but still have to trace 3 back-to-back non alignp primitives
assign clr_error = state_error;
// waiting timeout timer
assign timer_fin = timer == TIMER_LIMIT;
assign timer_clr = set_error | state_error | state_idle;
always @ (posedge clk)
timer <= rst | timer_clr ? 20'h0 : timer + CLK_TO_TIMER_CONTRIB;
// something is wrong with speed grades if the host cannot lock to device's alignp stream
assign oob_incompatible = state_wait_align & set_error;
// oob sequence is done, everything is okay
assign oob_done = set_wait_linkup;
// noone responds to cominits
assign oob_silence = set_error & state_wait_cominit;
// other timeouts
assign oob_error = set_error & ~oob_silence & ~oob_incompatible;
// obvioud
assign oob_busy = ~state_idle;
// set gtx controls
reg txelecidle_r;
always @ (posedge clk)
txelecidle_r <= rst ? 1'b1 : clr_wait_cominit ? 1'b0 : set_wait_cominit ? 1'b1 : txelecidle_r;
assign txcominit = set_wait_cominit;
assign txcomwake = set_wait_comwake;
assign txelecidle = set_wait_cominit | txelecidle_r;
// indicate if link up condition was made
assign link_up = clr_wait_linkup;
// link goes down when line is idle
reg rxelecidle_r;
reg rxelecidle_rr;
always @ (posedge clk)
begin
rxelecidle_rr <= rxelecidle_r;
rxelecidle_r <= rxelecidle;
end
assign link_down = rxelecidle_rr;
// indicate that device is requesting for oob
reg cominit_req_r;
wire cominit_req_set;
assign cominit_req_set = state_idle & rxcominitdet;
always @ (posedge clk)
cominit_req_r <= (cominit_req_r | cominit_req_set) & ~(cominit_allow & cominit_req) & ~rst;
assign cominit_req = cominit_req_set | cominit_req_r;
// detect which primitives sends the device after comwake was done
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg detected_alignp_f;
always @ (posedge clk)
detected_alignp_f <= rst | ~state_wait_align ? 1'b0 :
~|(rxdata ^ {8'b01001010, 8'b10111100}) & ~|(rxcharisk ^ 2'b01); // {D10.2, K28.5}
assign detected_alignp = detected_alignp_f & ~|(rxdata ^ {8'b01111011, 8'b01001010}) & ~|(rxcharisk ^ 2'b00); // {D27.3, D10.2}
reg detected_syncp_f;
always @ (posedge clk)
detected_syncp_f <= rst | ~state_wait_synp ? 1'b0 :
~|(rxdata ^ {8'b10010101, 8'b01111100}) & ~|(rxcharisk ^ 2'b01); // {D21.4, K28.3}
assign detected_syncp = detected_syncp_f & ~|(rxdata ^ {8'b10110101, 8'b10110101}) & ~|(rxcharisk ^ 2'b00); // {D21.5, D21.5}
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign detected_alignp = ~|(rxdata ^ {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}) & ~|(rxcharisk ^ 4'h1); // {D27.3, D10.2, D10.2, K28.5}
assign detected_syncp = ~|(rxdata ^ {8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}) & ~|(rxcharisk ^ 4'h1); // {D21.5, D21.5, D21.4, K28.3}
end
else
if (DATA_BYTE_WIDTH == 8)
begin
assign detected_alignp = ~|(rxdata ^ {2{8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}}) & ~|(rxcharisk ^ 8'h11); // {D27.3, D10.2, D10.2, K28.5}
assign detected_syncp = ~|(rxdata ^ {2{8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}}) & ~|(rxcharisk ^ 8'h11); // {D21.5, D21.5, D21.4, K28.3}
end
else
begin
always @ (posedge clk)
begin
$display("%m oob module works only with 16/32/64 gtx input data width");
$finish;
end
end
endgenerate
// buf inputs from gtx
always @ (posedge clk)
begin
rxcominitdet <= rxcominitdet_in;
rxcomwakedet <= rxcomwakedet_in;
rxelecidle <= rxelecidle_in;
rxdata <= rxdata_in;
rxcharisk <= rxcharisk_in;
end
// set data outputs to upper levels
assign rxdata_out = rxdata;
assign rxcharisk_out = rxcharisk;
// as depicted @ doc, p264, figure 163, have to insert D10.2 and align primitives after
// getting comwake from device
reg [DATA_BYTE_WIDTH*8 - 1:0] txdata;
reg [DATA_BYTE_WIDTH - 1:0] txcharisk;
wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_d102;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_d102;
wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_align;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_align;
always @ (posedge clk)
begin
txdata <= state_wait_align ? txdata_d102 :
state_wait_synp ? txdata_align : txdata_in;
txcharisk <= state_wait_align ? txcharisk_d102 :
state_wait_synp ? txcharisk_align : txcharisk_in;
end
// Continious D10.2 primitive
assign txcharisk_d102 = {DATA_BYTE_WIDTH{1'b0}};
assign txdata_d102 = {DATA_BYTE_WIDTH{8'b01001010}};
// Align primitive: K28.5 + D10.2 + D10.2 + D27.3
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg align_odd;
always @ (posedge clk)
align_odd <= rst | ~state_wait_synp ? 1'b0 : ~align_odd;
assign txcharisk_align = align_odd ? 2'b01 : 2'b00;
assign txdata_align = align_odd ? {8'b01001010, 8'b10111100} : // {D10.2, K28.5}
{8'b01111011, 8'b01001010}; // {D27.3, D10.2}
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign txcharisk_align = 4'h1;
assign txdata_align = {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}; // {D27.3, D10.2, D10.2, K28.5}
end
else
if (DATA_BYTE_WIDTH == 8)
begin
assign txcharisk_align = 8'h11;
assign txdata_align = {2{8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}}; // 2x{D27.3, D10.2, D10.2, K28.5}
end
else
always @ (posedge clk)
begin
$display("%m oob module works only with 16/32/64 gtx input data width");
$finish;
end
endgenerate
// set data outputs to gtx
assign txdata_out = txdata;
assign txcharisk_out = txcharisk;
*/
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/device/sata_device.v 0000664 0000000 0000000 00000111306 12572445207 0023720 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: sata_device
* Date: 2015-07-11
* Author: Alexey
* Description: sata device emul top level
*
* Copyright (c) 2015 Elphel, Inc.
* sata_device.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sata_device.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`include "sata_phy_dev.v"
module sata_device(
input wire rst,
input wire RXN,
input wire RXP,
output wire TXN,
output wire TXP,
input wire EXTCLK_P,
input wire EXTCLK_N
);
wire phy_ready;
wire [31:0] phy2dev_data;
wire [3:0] phy2dev_charisk;
wire [3:0] phy2dev_err;
wire clk;
wire dev_rst;
reg [31:0] dev2phy_data = 32'hB5B5957C; // SYNCP
reg [3:0] dev2phy_isk = 4'h1;
sata_phy_dev phy(
// pll reset
.extrst (rst),
// top-level ifaces
// ref clk from an external source, shall be connected to pads
.extclk_p (EXTCLK_P),
.extclk_n (EXTCLK_N),
// sata link data pins
.txp_out (TXP),
.txn_out (TXN),
.rxp_in (RXP),
.rxn_in (RXN),
.clk (clk),
.rst (dev_rst),
.phy_ready (phy_ready),
.ll_data_out (phy2dev_data),
.ll_charisk_out (phy2dev_charisk),
.ll_err_out (phy2dev_err),
.ll_data_in (dev2phy_data),
.ll_charisk_in (dev2phy_isk)
);
localparam [31:0] PRIM_SYNCP = {3'd5, 5'd21, 3'd5, 5'd21, 3'd4, 5'd21, 3'd3, 5'd28};
localparam [31:0] PRIM_ALIGNP = {3'd3, 5'd27, 3'd2, 5'd10, 3'd2, 5'd10, 3'd5, 5'd28};
localparam [31:0] PRIM_XRDYP = {3'd2, 5'd23, 3'd2, 5'd23, 3'd5, 5'd21, 3'd3, 5'd28};
localparam [31:0] PRIM_SOFP = {3'd1, 5'd23, 3'd1, 5'd23, 3'd5, 5'd21, 3'd3, 5'd28};
localparam [31:0] PRIM_HOLDAP = {3'd4, 5'd21, 3'd4, 5'd21, 3'd5, 5'd10, 3'd3, 5'd28};
localparam [31:0] PRIM_HOLDP = {3'd6, 5'd21, 3'd6, 5'd21, 3'd5, 5'd10, 3'd3, 5'd28};
localparam [31:0] PRIM_EOFP = {3'd6, 5'd21, 3'd6, 5'd21, 3'd5, 5'd21, 3'd3, 5'd28};
localparam [31:0] PRIM_WTRMP = {3'd2, 5'd24, 3'd2, 5'd24, 3'd5, 5'd21, 3'd3, 5'd28};
localparam [31:0] PRIM_RRDYP = {3'd2, 5'd10, 3'd2, 5'd10, 3'd4, 5'd21, 3'd3, 5'd28};
localparam [31:0] PRIM_IPP = {3'd2, 5'd21, 3'd2, 5'd21, 3'd5, 5'd21, 3'd3, 5'd28};
localparam [31:0] PRIM_DMATP = {3'd1, 5'd22, 3'd1, 5'd22, 3'd5, 5'd21, 3'd3, 5'd28};
localparam [31:0] PRIM_OKP = {3'd1, 5'd21, 3'd1, 5'd21, 3'd5, 5'd21, 3'd3, 5'd28};
localparam [31:0] PRIM_ERRP = {3'd2, 5'd22, 3'd2, 5'd22, 3'd5, 5'd21, 3'd3, 5'd28};
initial begin
$display("LIST OF PRIMITIVES:");
$display("SYNC = %x", PRIM_SYNCP );
$display("ALIGN = %x", PRIM_ALIGNP);
$display("XRDY = %x", PRIM_XRDYP );
$display("SOF = %x", PRIM_SOFP );
$display("HOLDA = %x", PRIM_HOLDAP);
$display("HOLD = %x", PRIM_HOLDP );
$display("EOF = %x", PRIM_EOFP );
$display("WTRM = %x", PRIM_WTRMP );
$display("RRDY = %x", PRIM_RRDYP );
$display("IP = %x", PRIM_IPP );
$display("DMAT = %x", PRIM_DMATP );
$display("OK = %x", PRIM_OKP );
$display("ERR = %x", PRIM_ERRP );
end
integer transmit_lock = 0;
integer receive_lock = 0;
integer suppress_receive = 0;
reg [31:0] receive_data [2047:0];
reg [31:0] receive_data_pause [2047:0];
reg [31:0] receive_wait_fifo;
reg [31:0] receive_crc;
integer receive_id = 0;
integer receive_status = 0;
/*
* Monitor incoming primitives every clock cycle
* if there is a data transfer request, start a receive sequence
*/
initial forever @ (posedge clk) begin
if (~transmit_lock) begin
// transmitting sequence is not started
if (~receive_lock) begin
// if for the current xrdy stream we haven't aready started a receiving sequence
if (~suppress_receive) begin
// if we do not intentionally ignore host's transmissions
if (linkGetPrim(0) == "XRDY") begin
linkMonitorFIS(receive_id, 2049, receive_status);
receive_id = receive_id + 1;
end
end
end
end
end
function [31:0] scrambleFunc;
input [31:0] context;
reg [31:0] next;
reg [15:0] now;
begin
now = context[15:0];
next[31] = now[12] ^ now[10] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
next[30] = now[15] ^ now[14] ^ now[12] ^ now[11] ^ now[9] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
next[29] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[28] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[27] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[1] ^ now[0];
next[26] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[0];
next[25] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[3] ^ now[2];
next[24] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[23] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[22] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
next[21] = now[15] ^ now[13] ^ now[12] ^ now[6] ^ now[5] ^ now[4] ^ now[0];
next[20] = now[15] ^ now[11] ^ now[5] ^ now[4];
next[19] = now[14] ^ now[10] ^ now[4] ^ now[3];
next[18] = now[13] ^ now[9] ^ now[3] ^ now[2];
next[17] = now[12] ^ now[8] ^ now[2] ^ now[1];
next[16] = now[11] ^ now[7] ^ now[1] ^ now[0];
next[15] = now[15] ^ now[14] ^ now[12] ^ now[10] ^ now[6] ^ now[3] ^ now[0];
next[14] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[9] ^ now[5] ^ now[3] ^ now[2];
next[13] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[4] ^ now[2] ^ now[1];
next[12] = now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
next[11] = now[15] ^ now[14] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
next[10] = now[15] ^ now[13] ^ now[12] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[9] = now[14] ^ now[12] ^ now[11] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[8] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[7] ^ now[6] ^ now[5] ^ now[1] ^ now[0];
next[7] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[6] ^ now[5] ^ now[4] ^ now[3] ^ now[0];
next[6] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[5] ^ now[4] ^ now[2];
next[5] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[4] ^ now[3] ^ now[1];
next[4] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
next[3] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[2] = now[14] ^ now[13] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[1] = now[15] ^ now[14] ^ now[13] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
next[0] = now[15] ^ now[13] ^ now[4] ^ now[0];
scrambleFunc = next;
end
endfunction
function [31:0] calculateCRC;
input [31:0] seed;
input [31:0] data;
reg [31:0] crc_bit;
reg [31:0] new_bit;
begin
crc_bit = seed ^ data;
new_bit[31] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^
crc_bit[23] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[5];
new_bit[30] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^
crc_bit[22] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[4];
new_bit[29] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^
crc_bit[22] ^ crc_bit[21] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[3];
new_bit[28] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^
crc_bit[21] ^ crc_bit[20] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[2];
new_bit[27] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^
crc_bit[20] ^ crc_bit[19] ^ crc_bit[11] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[1];
new_bit[26] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^
crc_bit[20] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[10] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
crc_bit[0];
new_bit[25] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ crc_bit[18] ^
crc_bit[17] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[3] ^ crc_bit[2];
new_bit[24] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[17] ^
crc_bit[16] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[2] ^ crc_bit[1];
new_bit[23] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^
crc_bit[16] ^ crc_bit[15] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
new_bit[22] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[19] ^
crc_bit[18] ^ crc_bit[16] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[0];
new_bit[21] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[18] ^
crc_bit[17] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[5];
new_bit[20] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[17] ^
crc_bit[16] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[4];
new_bit[19] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[20] ^ crc_bit[16] ^
crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3];
new_bit[18] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[19] ^
crc_bit[15] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2];
new_bit[17] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[20] ^
crc_bit[18] ^ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[1];
new_bit[16] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^
crc_bit[17] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[0];
new_bit[15] = crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[16] ^
crc_bit[15] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^
crc_bit[3];
new_bit[14] = crc_bit[29] ^ crc_bit[26] ^ crc_bit[23] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ crc_bit[15] ^
crc_bit[14] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
crc_bit[2];
new_bit[13] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[16] ^
crc_bit[14] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[3] ^
crc_bit[2] ^ crc_bit[1];
new_bit[12] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[18] ^ crc_bit[17] ^
crc_bit[15] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^
crc_bit[2] ^ crc_bit[1] ^ crc_bit[0];
new_bit[11] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^
crc_bit[17] ^ crc_bit[16] ^ crc_bit[15] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[4] ^
crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
new_bit[10] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[19] ^ crc_bit[16] ^ crc_bit[14] ^
crc_bit[13] ^ crc_bit[9] ^ crc_bit[5] ^ crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
new_bit[9] = crc_bit[29] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[18] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[11] ^
crc_bit[9] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^ crc_bit[1];
new_bit[8] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[17] ^ crc_bit[12] ^ crc_bit[11] ^
crc_bit[10] ^ crc_bit[8] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
new_bit[7] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[21] ^
crc_bit[16] ^ crc_bit[15] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[3] ^
crc_bit[2] ^ crc_bit[0];
new_bit[6] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[14] ^
crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^
crc_bit[1];
new_bit[5] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[13] ^
crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^
crc_bit[0];
new_bit[4] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ crc_bit[19] ^
crc_bit[18] ^ crc_bit[15] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[4] ^
crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
new_bit[3] = crc_bit[31] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[15] ^
crc_bit[14] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3] ^ crc_bit[2] ^
crc_bit[1];
new_bit[2] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[16] ^
crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2] ^
crc_bit[1] ^ crc_bit[0];
new_bit[1] = crc_bit[28] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[17] ^ crc_bit[16] ^ crc_bit[13] ^ crc_bit[12] ^
crc_bit[11] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
new_bit[0] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^
crc_bit[16] ^ crc_bit[12] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[0];
calculateCRC = new_bit;
end
endfunction
// stub TODO
function tranCheckFIS;
input count;
begin
$display("[Device] TRANSPORT: Says the FIS is valid");
tranCheckFIS = 0; // always tell LL the FIS os OK
end
endfunction
// TODO align every 256 dwords!
/*
* Receives data from a host. ~Link Receive FSM
* Correct execution, as it shall be w/o errors from a device side.
*
* Received data is stored in receive_data memory.
* Data is received by a dword // TODO make support for uneven words (16bit each) count
*
* Each data bundle has corresponding "pause" register, stored in a memory 'receive_data_pause'
* It represents a time (in clock cycles), for which the device shall send HOLD primitives after
* current data bundle reception. If after HOLD request data is still coming, consequetive 'pause's are summed up.
* Could be used to test timeout watchdogs of the host.
*
* receive_wait_fifo shows how many clock cycles receiver shall spent before it allows the host to transmit data
*
* Parameters:
* id - reception id, shown in logs
* dmat_index - after this count of received data dwords DMAT primitive would be sent to the line
* status - returns 0 when the host acknowledges the transaction with OK code,
* 1 when with ERR code
* if it's 1, there are 3 options:
* a) Generated CRC is invalid
* b) Scrambler messed up
* c) There is an error in the host
*/
task linkMonitorFIS;
input integer id;
input integer dmat_index;
output integer status;
reg [112:0] rprim;
integer pause;
integer rcv_stop;
integer rcv_ignore;
integer cnt;
reg [31:0] scrambler_value;
reg [31:0] crc;
begin
pause = receive_wait_fifo;
status = 0;
rcv_ignore = 0;
rcv_stop = 0;
crc = 32'h52325032;// crc seed
scrambler_value = {16'hf0f6, 16'h0000}; // scrambler seed
cnt = 0;
// current rprim = XRDY
rprim = "XRDY";
$display("[Device] LINK: Detected incoming transmission");
$display("[Device] LINK: Waiting %h cycles to empty input buffer", pause);
while (pause > 0) begin
// L_RcvWaitFifo
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim != "XRDY") begin
$display("[Device] LINK: Reception terminated by the host, reception id = %d", id);
$finish;
end
@ (posedge clk)
rprim = linkGetPrim(0);
end
// L_RcvChkRdy
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim != "XRDY") begin
$display("[Device] LINK: Reception terminated by the host, reception id = %d", id);
$finish;
end
linkSendPrim("RRDY");
$display("[Device] LINK: Starting the reception");
@ (posedge clk)
rprim = linkGetPrim(0);
while (rprim != "SOF") begin
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim != "XRDY") begin
$display("[Device] LINK: Reception terminated by the host, reception id = %d", id);
$finish;
end
@ (posedge clk)
rprim = linkGetPrim(0);
end
// L_RcvData
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
$display("[Device] LINK: Detected Start of FIS");
linkSendPrim("IP");
@ (posedge clk)
rprim = linkGetPrim(0);
pause = 0;
while (rcv_stop == 0) begin
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim == "SYNC") begin
$display("[Device] LINK: Reception terminated by the host, reception id = %d", id);
$finish;
end
if (rprim == "SCRAP") begin
$display("[Device] LINK: Bad primitives from the host, is data = %h, data = %h, reception id = %d", linkIsData(0), linkGetData(0), id);
$finish;
end
if (rprim == "EOF") begin
$display("[Device] LINK: Detected End of FIS");
rcv_stop = 1;
end
else
if (pause > 0) begin
pause = pause - 1;
linkSendPrim("HOLD");
if (rprim == "HOLDA") begin
$display("[Device] LINK: The pause is acknowledged by the host, chilling out");
rcv_ignore = 1;
end
else begin
$display("[Device] LINK: Asked for a pause");
rcv_ignore = 0;
end
end
else
if (rprim == "HOLD") begin
$display("[Device] LINK: the host asked for a pause, acknowledging");
linkSendPrim("HOLDA");
rcv_ignore = 1;
end
else begin
linkSendPrim("IP");
rcv_ignore = 0;
end
if (rprim == "WTRM") begin
$display("[Device] LINK: Host invalidated the reception, reception id = %d", id);
rcv_stop = 2;
end
if ((rcv_stop == 0) && (rcv_ignore == 0)) begin
if (cnt > 2048) begin
$display("[Device] LINK: Wrong data dwords count received, reception id = %d", id);
$finish;
end
if (cnt >= dmat_index) begin
linkSendPrim("DMAT");
end
scrambler_value = scrambleFunc(scrambler_value[31:16]);
receive_data[cnt] = linkGetData(0) ^ scrambler_value;
$display("[Device] LINK: Got data = %h", receive_data[cnt]);
pause = pause + receive_data_pause[cnt];
crc = calculateCRC(crc, receive_data[cnt]); // running crc. shall be 0
cnt = cnt + 1;
if (cnt <= 2048)
pause = pause + receive_data_pause[cnt];
end
@ (posedge clk)
rprim = linkGetPrim(0);
end
if (cnt < 2) begin
$display("[Device] LINK: Incorrect number of received words");
$finish;
end
$display("[Device] LINK: Running CRC after all data was received = %h", crc);
if (crc != 32'h88c21025) begin // running disparity when data crc matches actual received crc
$display("[Device] LINK: Running CRC check failed");
rcv_stop = 2;
end
else begin
$display("[Device] LINK: Running CRC OK");
end
if (rcv_stop == 1) begin // ordinary path
// L_RcvEOF
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim == "SYNC") begin
$display("[Device] LINK: Reception terminated by the host, reception id = %d", id);
$finish;
end
if ((rprim == "SCRAP") || (rprim == "DATA")) begin
$display("[Device] LINK: Bad primitives from the host, is data = %h, data = %h, reception id = %d", linkIsData(0), linkGetData(0), id);
$finish;
end
@ (posedge clk)
rprim = linkGetPrim(0);
// L_GoodCRC
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim == "SYNC") begin
$display("[Device] LINK: Reception terminated by the host, reception id = %d", id);
$finish;
end
if ((rprim == "SCRAP") || (rprim == "DATA")) begin
$display("[Device] LINK: Bad primitives from the host, is data = %h, data = %h, reception id = %d", linkIsData(0), linkGetData(0), id);
$finish;
end
if (tranCheckFIS(cnt - 1)) begin
rcv_stop = 2;
end
end
if (rcv_stop == 2) begin
// L_BadEnd
status = 1;
linkSendPrim("ERR");
$display("[Device] LINK: Found an error");
end
else begin
// L_GoodEnd
status = 0;
linkSendPrim("OK");
end
@ (posedge clk)
rprim = linkGetPrim(0);
while (rprim != "SYNC") begin
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if ((rprim == "SCRAP") || (rprim == "DATA")) begin
$display("[Device] LINK: Bad primitives from the host, is data = %h, data = %h, reception id = %d", linkIsData(0), linkGetData(0), id);
$finish;
end
@ (posedge clk)
rprim = linkGetPrim(0);
end
// L_IDLE
linkSendPrim("SYNC");
if (status == 1) begin
$display("[Device] LINK: Reception done, errors detected, reception id = %d", id);
end
else
if (status == 0) begin
$display("[Device] LINK: Reception done OK, reception id = %d", id);
end
end
endtask
reg [31:0] transmit_data [2047:0];
reg [31:0] transmit_data_pause [2047:0];
reg [31:0] transmit_crc;
/*
* Transmits data to a host. ~Link Transmit FSM
* Correct execution, as it shall be w/o errors from a device side. (except timeouts and data consistency, see below)
*
* Data to transmit is stored in transmit_data memory.
* Data is transmitted by dwords // TODO make support for uneven words (16bit each) count
*
* It is possible to send incorrect CRC by setting up an input transmit_custom_crc into 1 and desired crc value to transmit_crc
*
* Each data bundle has corresponding "pause" register, stored in a memory 'transmit_data_pause'
* It represents a time (in clock cycles), for which the device shall "wait" for a new portion of data
* Could be used to test timeout watchdogs of the host.
*
* Parameters:
* id - transmission id, shown in logs
* size - how much data to transmit in a FIS
* transmit_custom_crc - see upper
* status - returns 0 when the host acknowledges the transaction with OK code,
* 1 when with ERR code
* if it's 1, there are 3 options:
* a) Generated CRC is invalid
* b) Scrambler messed up
* c) There is an error in the host
*/
task linkTransmitFIS;
input integer id;
input integer size; // dwords count
input integer transmit_custom_crc;
output integer status;
integer pause;
integer cnt;
integer crc;
reg [112:0] rprim;
reg [31:0] scrambler_value;
begin
crc = 32'h52325032;// crc seed
scrambler_value = {16'hf0f6, 16'h0000}; // scrambler seed
// tell everyone we need a bus to transmit data
transmit_lock = 1;
// DL_SendChkRdy
linkSendPrim("XRDY");
$display("[Device] LINK: Started outcoming transmission");
rprim = linkGetPrim(0);
$display("[Device] LINK: Waiting for acknowledgement");
while (rprim != "RRDY") begin
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
@ (posedge clk)
rprim = linkGetPrim(0);
end
// L_SendSOF
linkSendPrim("SOF");
$display("[Device] LINK: Sending Start of FIS");
@ (posedge clk)
rprim = linkGetPrim(0);
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim == "SYNC") begin
$display("[Device] LINK: Transmission terminated by the host, transmission id = %d", id);
$finish;
end
if ((rprim == "SCRAP") || (rprim == "DATA")) begin
$display("[Device] LINK: Bad primitives from the host, is data = %h, data = %h, transmission id = %d", linkIsData(0), linkGetData(0), id);
$finish;
end
// L_SendData + L_RcvrHold + L_SendHold
cnt = 0;
pause = transmit_data_pause[0];
while (cnt < size) begin
scrambler_value = scrambleFunc(scrambler_value[31:16]);
// $display("[Device] LINK: Scrambler = %h", scrambler_value);
linkSendData(transmit_data[cnt] ^ scrambler_value);
crc = calculateCRC(crc, transmit_data[cnt]);
$display("[Device] LINK: Sent data = %h", transmit_data[cnt]);
@ (posedge clk)
rprim = linkGetPrim(0);
if (rprim == "SYNC") begin
$display("[Device] LINK: Transmission terminated by the host, transmission id = %d", id);
$finish;
end
if ((rprim == "SCRAP") || (rprim == "DATA")) begin
$display("[Device] LINK: Bad primitives from the host, is data = %h, data = %h, transmission id = %d", linkIsData(0), linkGetData(0), id);
$finish;
end
else
if (rprim == "DMAT") begin
$display("[Device] LINK: Transmission terminated by the host via DMAT, transmission id = %d", id);
$finish;
end
else
if (pause > 0) begin
$display("[Device] LINK: Transmission is paused");
linkSendPrim("HOLD");
pause = pause - 1;
end
else
if (rprim == "HOLD") begin
$display("[Device] LINK: The host asked for a pause, acknowledging");
linkSendPrim("HOLDA");
end
else begin
cnt = cnt + 1;
if (cnt < size)
pause = transmit_data_pause[cnt];
end
end
// L_SendCRC
scrambler_value = scrambleFunc(scrambler_value[31:16]);
if (transmit_custom_crc != 0) begin
crc = transmit_crc;
end
linkSendData(crc ^ scrambler_value);
$display("[Device] LINK: Sent crc = %h", crc);
@ (posedge clk)
rprim = linkGetPrim(0);
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim == "SYNC") begin
$display("[Device] LINK: Transmission terminated by the host, transmission id = %d", id);
$finish;
end
if ((rprim == "SCRAP") || (rprim == "DATA")) begin
$display("[Device] LINK: Bad primitives from the host, is data = %h, data = %h, transmission id = %d", linkIsData(0), linkGetData(0), id);
$finish;
end
// L_SendEOF
linkSendPrim("EOF");
$display("[Device] LINK: Sent End of FIS");
@ (posedge clk)
rprim = linkGetPrim(0);
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim == "SYNC") begin
$display("[Device] LINK: Transmission terminated by the host, transmission id = %d", id);
$finish;
end
if ((rprim == "SCRAP") || (rprim == "DATA")) begin
$display("[Device] LINK: Bad primitives from the host, is data = %h, data = %h, transmission id = %d", linkIsData(0), linkGetData(0), id);
$finish;
end
// L_Wait
linkSendPrim("WTRM");
$display("[Device] LINK: Waiting for a response from the host");
@ (posedge clk)
rprim = linkGetPrim(0);
status = 0;
while ((rprim != "OK") && (status == 0)) begin
if (~phy_ready) begin
$display("[Device] LINK: Unexpected line disconnect");
$finish;
end
if (rprim == "SYNC") begin
$display("[Device] LINK: Transmission terminated by the host, transmission id = %d", id);
$finish;
end
if ((rprim == "SCRAP") || (rprim == "DATA")) begin
$display("[Device] LINK: Bad primitives from the host, is data = %h, data = %h, transmission id = %d", linkIsData(0), linkGetData(0), id);
$finish;
end
if (rprim == "ERR") begin
$display("[Device] LINK: Host invalidated the transmission, transmission id = %d", id);
status = 1;
end
@ (posedge clk)
rprim = linkGetPrim(0);
end
if (status == 0)
$display("[Device] LINK: Transmission done OK, id = %d", id);
if (status == 1)
$display("[Device] LINK: Transmission done with ERRORs, id = %d", id);
// L_IDLE
linkSendPrim("SYNC");
@ (posedge clk);
end
endtask
// checks, if it is data coming from the host
function [0:0] linkIsData;
input dummy;
begin
if (|phy2dev_charisk)
linkIsData = 1;
else
linkIsData = 0;
end
endfunction
// obvious
function [31:0] linkGetData;
// TODO non-even word count
input dummy;
begin
linkGetData = phy2dev_data;
end
endfunction
/*
* Returns current primitive at the outputs of phy level
* Return value is a string containing its name!
*/
function [112:0] linkGetPrim;
input integer dummy;
reg [112:0] type;
begin
if (~|phy2dev_charisk) begin
type = "DATA";
end
else
if (phy2dev_charisk == 4'h1) begin
case (phy2dev_data)
PRIM_SYNCP:
type = "SYNC";
PRIM_ALIGNP:
type = "ALIGN";
PRIM_XRDYP:
type = "XRDY";
PRIM_SOFP:
type = "SOF";
PRIM_HOLDAP:
type = "HOLDA";
PRIM_HOLDP:
type = "HOLD";
PRIM_EOFP:
type = "EOF";
PRIM_WTRMP:
type = "WTRM";
PRIM_RRDYP:
type = "RRDY";
PRIM_IPP:
type = "IP";
PRIM_DMATP:
type = "DMAT";
PRIM_OKP:
type = "OK";
PRIM_ERRP:
type = "ERR";
default:
type = "SCRAP";
endcase
end
else begin
type = "SCRAP";
end
linkGetPrim = type;
end
endfunction
/*
* Sets some data to phy inputs
* input is a data dword
*/
task linkSendData;
input [31:0] data;
begin
dev2phy_data <= data;
dev2phy_isk <= 4'h0;
end
endtask
/*
* Set a desired primitive to phy inputs
* input is a string containing its name!
*/
task linkSendPrim;
input [112:0] type;
begin
case (type)
"SYNC":
begin
dev2phy_data <= PRIM_SYNCP;
dev2phy_isk <= 4'h1;
end
"ALIGN":
begin
dev2phy_data <= PRIM_ALIGNP;
dev2phy_isk <= 4'h1;
end
"XRDY":
begin
dev2phy_data <= PRIM_XRDYP;
dev2phy_isk <= 4'h1;
end
"SOF":
begin
dev2phy_data <= PRIM_SOFP;
dev2phy_isk <= 4'h1;
end
"HOLDA":
begin
dev2phy_data <= PRIM_HOLDAP;
dev2phy_isk <= 4'h1;
end
"HOLD":
begin
dev2phy_data <= PRIM_HOLDP;
dev2phy_isk <= 4'h1;
end
"EOF":
begin
dev2phy_data <= PRIM_EOFP;
dev2phy_isk <= 4'h1;
end
"WTRM":
begin
dev2phy_data <= PRIM_WTRMP;
dev2phy_isk <= 4'h1;
end
"RRDY":
begin
dev2phy_data <= PRIM_RRDYP;
dev2phy_isk <= 4'h1;
end
"IP":
begin
dev2phy_data <= PRIM_IPP;
dev2phy_isk <= 4'h1;
end
"DMAT":
begin
dev2phy_data <= PRIM_DMATP;
dev2phy_isk <= 4'h1;
end
"OK":
begin
dev2phy_data <= PRIM_OKP;
dev2phy_isk <= 4'h1;
end
"ERR":
begin
dev2phy_data <= PRIM_ERRP;
dev2phy_isk <= 4'h1;
end
default:
begin
dev2phy_data <= PRIM_SYNCP;
dev2phy_isk <= 4'h1;
end
endcase
end
endtask
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/device/sata_phy_dev.v 0000664 0000000 0000000 00000076024 12572445207 0024126 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: sata_phy
* Date: 2015-07-11
* Author: Alexey
* Description: phy-level, including oob, clock generation and GTXE2
*
* Copyright (c) 2015 Elphel, Inc.
* sata_phy.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sata_phy.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`include "oob_dev.v"
module sata_phy_dev #(
parameter DATA_BYTE_WIDTH = 4
)
(
// initial reset, resets PLL. After pll is locked, an internal sata reset is generated.
input wire extrst,
// sata clk, generated in pll as usrclk2
output wire clk,
output wire rst,
// state
output wire phy_ready,
// top-level ifaces
// ref clk from an external source, shall be connected to pads
input wire extclk_p,
input wire extclk_n,
// sata link data pins
output wire txp_out,
output wire txn_out,
input wire rxp_in,
input wire rxn_in,
// to link layer
output wire [31:0] ll_data_out,
output wire [3:0] ll_charisk_out,
output wire [3:0] ll_err_out, // TODO!!!
// from link layer
input wire [31:0] ll_data_in,
input wire [3:0] ll_charisk_in
);
parameter CHIPSCOPE = "FALSE";
wire txcomfinish;
wire [31:0] txdata;
wire [31:0] txdata_oob;
wire [3:0] txcharisk;
wire [3:0] txcharisk_oob;
wire [63:0] rxdata;
wire [63:0] rxdata_gtx;
wire [7:0] rxcharisk;
wire [7:0] rxcharisk_gtx;
wire [7:0] rxchariscomma;
wire [7:0] rxchariscomma_gtx;
wire [7:0] rxdisperr;
wire [7:0] rxdisperr_gtx;
wire [7:0] rxnotintable;
wire [7:0] rxnotintable_gtx;
wire [31:0] rxdata_out;
wire [31:0] txdata_in;
wire [3:0] txcharisk_in;
wire [3:0] rxcharisk_out;
wire rxcomwakedet;
wire rxcominitdet;
wire cplllock;
wire txcominit;
wire txcomwake;
wire rxreset;
wire rxelecidle;
wire txelecidle;
wire rxbyteisaligned;
wire txpcsreset_req;
wire recal_tx_done;
wire gtx_ready;
assign txdata = phy_ready ? ll_data_in : txdata_oob;
assign txcharisk = phy_ready ? ll_charisk_in : txcharisk_oob;
assign ll_err_out = 4'h0;
assign ll_charisk_out = rxcharisk[3:0];
assign ll_data_out = rxdata;
oob_dev oob_dev(
// sata clk = usrclk2
.clk (clk),
// reset oob
.rst (rst),
// gtx is ready = all resets are done
.gtx_ready (gtx_ready),
// oob responces
.rxcominitdet_in (rxcominitdet),
.rxcomwakedet_in (rxcomwakedet),
.rxelecidle_in (rxelecidle),
// oob issues
.txcominit (txcominit),
.txcomwake (txcomwake),
.txelecidle (txelecidle),
.txpcsreset_req (txpcsreset_req),
.recal_tx_done (recal_tx_done),
// output data stream to gtx
.txdata_out (txdata_oob),
.txcharisk_out (txcharisk_oob),
// input data from gtx
.rxdata_in (rxdata[31:0]),
.rxcharisk_in (rxcharisk[3:0]),
// shows if channel is ready
.link_up (phy_ready)
);
wire cplllockdetclk; // TODO
wire drpclk; // TODO
wire cpllreset;
wire gtrefclk;
wire rxresetdone;
wire txresetdone;
wire txpcsreset;
wire txreset;
wire txuserrdy;
wire rxuserrdy;
wire txusrclk;
wire txusrclk2;
wire rxusrclk;
wire rxusrclk2;
wire txp;
wire txn;
wire rxp;
wire rxn;
wire txoutclk;
wire txpmareset_done;
wire rxeyereset_done;
// tx reset sequence; waves @ ug476 p67
localparam TXPMARESET_TIME = 5'h1;
reg [2:0] txpmareset_cnt;
assign txpmareset_done = txpmareset_cnt == TXPMARESET_TIME;
always @ (posedge gtrefclk)
txpmareset_cnt <= txreset ? 3'h0 : txpmareset_done ? txpmareset_cnt : txpmareset_cnt + 1'b1;
// rx reset sequence; waves @ ug476 p77
localparam RXPMARESET_TIME = 5'h11;
localparam RXCDRPHRESET_TIME = 5'h1;
localparam RXCDRFREQRESET_TIME = 5'h1;
localparam RXDFELPMRESET_TIME = 7'hf;
localparam RXISCANRESET_TIME = 5'h1;
localparam RXEYERESET_TIME = 7'h0 + RXPMARESET_TIME + RXCDRPHRESET_TIME + RXCDRFREQRESET_TIME + RXDFELPMRESET_TIME + RXISCANRESET_TIME;
reg [6:0] rxeyereset_cnt;
assign rxeyereset_done = rxeyereset_cnt == RXEYERESET_TIME;
always @ (posedge gtrefclk)
rxeyereset_cnt <= rxreset ? 3'h0 : rxeyereset_done ? rxeyereset_cnt : rxeyereset_cnt + 1'b1;
/*
* Resets
*/
wire usrpll_locked;
assign cpllreset = extrst;
assign rxreset = ~cplllock | cpllreset;
assign txreset = ~cplllock | cpllreset;
assign rxuserrdy = usrpll_locked & cplllock & ~cpllreset & ~rxreset & rxeyereset_done;
assign txuserrdy = usrpll_locked & cplllock & ~cpllreset & ~txreset & txpmareset_done;
assign gtx_ready = rxuserrdy & txuserrdy & rxresetdone & txresetdone;
// issue partial tx reset to restore functionality after oob sequence. Let it lasts 8 clock lycles
reg [3:0] txpcsreset_cnt;
wire txpcsreset_stop;
assign txpcsreset_stop = txpcsreset_cnt[3];
assign txpcsreset = txpcsreset_req & ~txpcsreset_stop;
assign recal_tx_done = txpcsreset_stop & gtx_ready;
always @ (posedge clk or posedge extrst)
txpcsreset_cnt <= extrst | rst | ~txpcsreset_req ? 4'h0 : txpcsreset_stop ? txpcsreset_cnt : txpcsreset_cnt + 1'b1;
// generate internal reset after a clock is established
// !!!ATTENTION!!!
// async rst block
reg [7:0] rst_timer;
reg rst_r;
localparam [7:0] RST_TIMER_LIMIT = 8'b1000;
always @ (posedge clk or posedge extrst)
rst_timer <= extrst | ~cplllock | ~usrpll_locked ? 8'h0 : rst_timer == RST_TIMER_LIMIT ? rst_timer : rst_timer + 1'b1;
assign rst = rst_r;
always @ (posedge clk or posedge extrst)
rst_r <= extrst | ~|rst_timer ? 1'b0 : rst_timer[3] ? 1'b0 : 1'b1;
/*
* USRCLKs generation. USRCLK @ 150MHz, same as TXOUTCLK; USRCLK2 @ 75Mhz -> sata_clk === sclk
* It's recommended to use MMCM instead of PLL, whatever
*/
wire usrpll_fb_clk;
wire usrclk;
wire usrclk2;
assign txusrclk = usrclk;
assign txusrclk2 = usrclk2;
assign rxusrclk = usrclk;
assign rxusrclk2 = usrclk2;
PLLE2_ADV #(
.BANDWIDTH ("OPTIMIZED"),
.CLKFBOUT_MULT (8),
.CLKFBOUT_PHASE (0.000),
.CLKIN1_PERIOD (6.666),
.CLKIN2_PERIOD (0.000),
.CLKOUT0_DIVIDE (8),
.CLKOUT0_DUTY_CYCLE (0.500),
.CLKOUT0_PHASE (0.000),
.CLKOUT1_DIVIDE (16),
.CLKOUT1_DUTY_CYCLE (0.500),
.CLKOUT1_PHASE (0.000),
/* .CLKOUT2_DIVIDE = 1,
.CLKOUT2_DUTY_CYCLE = 0.500,
.CLKOUT2_PHASE = 0.000,
.CLKOUT3_DIVIDE = 1,
.CLKOUT3_DUTY_CYCLE = 0.500,
.CLKOUT3_PHASE = 0.000,
.CLKOUT4_DIVIDE = 1,
.CLKOUT4_DUTY_CYCLE = 0.500,
.CLKOUT4_PHASE = 0.000,
.CLKOUT5_DIVIDE = 1,
.CLKOUT5_DUTY_CYCLE = 0.500,
.CLKOUT5_PHASE = 0.000,*/
.COMPENSATION ("ZHOLD"),
.DIVCLK_DIVIDE (1),
.IS_CLKINSEL_INVERTED (1'b0),
.IS_PWRDWN_INVERTED (1'b0),
.IS_RST_INVERTED (1'b0),
.REF_JITTER1 (0.010),
.REF_JITTER2 (0.010),
.STARTUP_WAIT ("FALSE")
)
usrclk_pll(
.CLKFBOUT (usrpll_fb_clk),
.CLKOUT0 (usrclk),
.CLKOUT1 (usrclk2),
.CLKOUT2 (),
.CLKOUT3 (),
.CLKOUT4 (),
.CLKOUT5 (),
.DO (),
.DRDY (),
.LOCKED (usrpll_locked),
.CLKFBIN (usrpll_fb_clk),
.CLKIN1 (txoutclk),
.CLKIN2 (1'b0),
.CLKINSEL (1'b1),
.DADDR (7'h0),
.DCLK (drpclk),
.DEN (1'b0),
.DI (16'h0),
.DWE (1'b0),
.PWRDWN (1'b0),
.RST (~cplllock)
);
/*
* Padding for an external input clock @ 150 MHz
*/
localparam [1:0] CLKSWING_CFG = 2'b11;
IBUFDS_GTE2 #(
.CLKRCV_TRST ("TRUE"),
.CLKCM_CFG ("TRUE"),
.CLKSWING_CFG (CLKSWING_CFG)
)
ext_clock_buf(
.I (extclk_p),
.IB (extclk_n),
.CEB (1'b0),
.O (gtrefclk),
.ODIV2 ()
);
GTXE2_CHANNEL #(
.SIM_RECEIVER_DETECT_PASS ("TRUE"),
.SIM_TX_EIDLE_DRIVE_LEVEL ("X"),
.SIM_RESET_SPEEDUP ("FALSE"),
.SIM_CPLLREFCLK_SEL (3'b001),
.SIM_VERSION ("4.0"),
.ALIGN_COMMA_DOUBLE ("FALSE"),
.ALIGN_COMMA_ENABLE (10'b1111111111),
.ALIGN_COMMA_WORD (1),
.ALIGN_MCOMMA_DET ("TRUE"),
.ALIGN_MCOMMA_VALUE (10'b1010000011),
.ALIGN_PCOMMA_DET ("TRUE"),
.ALIGN_PCOMMA_VALUE (10'b0101111100),
.SHOW_REALIGN_COMMA ("TRUE"),
.RXSLIDE_AUTO_WAIT (7),
.RXSLIDE_MODE ("OFF"),
.RX_SIG_VALID_DLY (10),
.RX_DISPERR_SEQ_MATCH ("TRUE"),
.DEC_MCOMMA_DETECT ("TRUE"),
.DEC_PCOMMA_DETECT ("TRUE"),
.DEC_VALID_COMMA_ONLY ("FALSE"),
.CBCC_DATA_SOURCE_SEL ("DECODED"),
.CLK_COR_SEQ_2_USE ("FALSE"),
.CLK_COR_KEEP_IDLE ("FALSE"),
.CLK_COR_MAX_LAT (9),
.CLK_COR_MIN_LAT (7),
.CLK_COR_PRECEDENCE ("TRUE"),
.CLK_COR_REPEAT_WAIT (0),
.CLK_COR_SEQ_LEN (1),
.CLK_COR_SEQ_1_ENABLE (4'b1111),
.CLK_COR_SEQ_1_1 (10'b0100000000),
.CLK_COR_SEQ_1_2 (10'b0000000000),
.CLK_COR_SEQ_1_3 (10'b0000000000),
.CLK_COR_SEQ_1_4 (10'b0000000000),
.CLK_CORRECT_USE ("FALSE"),
.CLK_COR_SEQ_2_ENABLE (4'b1111),
.CLK_COR_SEQ_2_1 (10'b0100000000),
.CLK_COR_SEQ_2_2 (10'b0000000000),
.CLK_COR_SEQ_2_3 (10'b0000000000),
.CLK_COR_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_KEEP_ALIGN ("FALSE"),
.CHAN_BOND_MAX_SKEW (1),
.CHAN_BOND_SEQ_LEN (1),
.CHAN_BOND_SEQ_1_1 (10'b0000000000),
.CHAN_BOND_SEQ_1_2 (10'b0000000000),
.CHAN_BOND_SEQ_1_3 (10'b0000000000),
.CHAN_BOND_SEQ_1_4 (10'b0000000000),
.CHAN_BOND_SEQ_1_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_1 (10'b0000000000),
.CHAN_BOND_SEQ_2_2 (10'b0000000000),
.CHAN_BOND_SEQ_2_3 (10'b0000000000),
.CHAN_BOND_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_SEQ_2_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_USE ("FALSE"),
.FTS_DESKEW_SEQ_ENABLE (4'b1111),
.FTS_LANE_DESKEW_CFG (4'b1111),
.FTS_LANE_DESKEW_EN ("FALSE"),
.ES_CONTROL (6'b000000),
.ES_ERRDET_EN ("FALSE"),
.ES_EYE_SCAN_EN ("TRUE"),
.ES_HORZ_OFFSET (12'h000),
.ES_PMA_CFG (10'b0000000000),
.ES_PRESCALE (5'b00000),
.ES_QUALIFIER (80'h00000000000000000000),
.ES_QUAL_MASK (80'h00000000000000000000),
.ES_SDATA_MASK (80'h00000000000000000000),
.ES_VERT_OFFSET (9'b000000000),
.RX_DATA_WIDTH (40),
.OUTREFCLK_SEL_INV (2'b11),
.PMA_RSV (32'h00018480),
.PMA_RSV2 (16'h2050),
.PMA_RSV3 (2'b00),
.PMA_RSV4 (32'h00000000),
.RX_BIAS_CFG (12'b000000000100),
.DMONITOR_CFG (24'h000A00),
.RX_CM_SEL (2'b11),
.RX_CM_TRIM (3'b010),
.RX_DEBUG_CFG (12'b000000000000),
.RX_OS_CFG (13'b0000010000000),
.TERM_RCAL_CFG (5'b10000),
.TERM_RCAL_OVRD (1'b0),
.TST_RSV (32'h00000000),
.RX_CLK25_DIV (6),
.TX_CLK25_DIV (6),
.UCODEER_CLR (1'b0),
.PCS_PCIE_EN ("FALSE"),
.PCS_RSVD_ATTR (48'h0100),
.RXBUF_ADDR_MODE ("FAST"),
.RXBUF_EIDLE_HI_CNT (4'b1000),
.RXBUF_EIDLE_LO_CNT (4'b0000),
.RXBUF_EN ("TRUE"),
.RX_BUFFER_CFG (6'b000000),
.RXBUF_RESET_ON_CB_CHANGE ("TRUE"),
.RXBUF_RESET_ON_COMMAALIGN ("FALSE"),
.RXBUF_RESET_ON_EIDLE ("FALSE"),
.RXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.RXBUFRESET_TIME (5'b00001),
.RXBUF_THRESH_OVFLW (61),
.RXBUF_THRESH_OVRD ("FALSE"),
.RXBUF_THRESH_UNDFLW (4),
.RXDLY_CFG (16'h001F),
.RXDLY_LCFG (9'h030),
.RXDLY_TAP_CFG (16'h0000),
.RXPH_CFG (24'h000000),
.RXPHDLY_CFG (24'h084020),
.RXPH_MONITOR_SEL (5'b00000),
.RX_XCLK_SEL ("RXREC"),
.RX_DDI_SEL (6'b000000),
.RX_DEFER_RESET_BUF_EN ("TRUE"),
.RXCDR_CFG (72'h03000023ff10200020),
.RXCDR_FR_RESET_ON_EIDLE (1'b0),
.RXCDR_HOLD_DURING_EIDLE (1'b0),
.RXCDR_PH_RESET_ON_EIDLE (1'b0),
.RXCDR_LOCK_CFG (6'b010101),
.RXCDRFREQRESET_TIME (RXCDRFREQRESET_TIME),
.RXCDRPHRESET_TIME (RXCDRPHRESET_TIME),
.RXISCANRESET_TIME (RXISCANRESET_TIME),
.RXPCSRESET_TIME (5'b00001),
.RXPMARESET_TIME (RXPMARESET_TIME),
.RXOOB_CFG (7'b0000110),
.RXGEARBOX_EN ("FALSE"),
.GEARBOX_MODE (3'b000),
.RXPRBS_ERR_LOOPBACK (1'b0),
.PD_TRANS_TIME_FROM_P2 (12'h03c),
.PD_TRANS_TIME_NONE_P2 (8'h3c),
.PD_TRANS_TIME_TO_P2 (8'h64),
.SAS_MAX_COM (64),
.SAS_MIN_COM (36),
.SATA_BURST_SEQ_LEN (4'b0111),
.SATA_BURST_VAL (3'b110),
.SATA_EIDLE_VAL (3'b110),
.SATA_MAX_BURST (8),
.SATA_MAX_INIT (21),
.SATA_MAX_WAKE (7),
.SATA_MIN_BURST (4),
.SATA_MIN_INIT (12),
.SATA_MIN_WAKE (4),
.TRANS_TIME_RATE (8'h0E),
.TXBUF_EN ("TRUE"),
.TXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.TXDLY_CFG (16'h001F),
.TXDLY_LCFG (9'h030),
.TXDLY_TAP_CFG (16'h0000),
.TXPH_CFG (16'h0780),
.TXPHDLY_CFG (24'h084020),
.TXPH_MONITOR_SEL (5'b00000),
.TX_XCLK_SEL ("TXOUT"),
.TX_DATA_WIDTH (40),
.TX_DEEMPH0 (5'b00000),
.TX_DEEMPH1 (5'b00000),
.TX_EIDLE_ASSERT_DELAY (3'b110),
.TX_EIDLE_DEASSERT_DELAY (3'b100),
.TX_LOOPBACK_DRIVE_HIZ ("FALSE"),
.TX_MAINCURSOR_SEL (1'b0),
.TX_DRIVE_MODE ("DIRECT"),
.TX_MARGIN_FULL_0 (7'b1001110),
.TX_MARGIN_FULL_1 (7'b1001001),
.TX_MARGIN_FULL_2 (7'b1000101),
.TX_MARGIN_FULL_3 (7'b1000010),
.TX_MARGIN_FULL_4 (7'b1000000),
.TX_MARGIN_LOW_0 (7'b1000110),
.TX_MARGIN_LOW_1 (7'b1000100),
.TX_MARGIN_LOW_2 (7'b1000010),
.TX_MARGIN_LOW_3 (7'b1000000),
.TX_MARGIN_LOW_4 (7'b1000000),
.TXGEARBOX_EN ("FALSE"),
.TXPCSRESET_TIME (5'b00001),
.TXPMARESET_TIME (TXPMARESET_TIME),
.TX_RXDETECT_CFG (14'h1832),
.TX_RXDETECT_REF (3'b100),
.CPLL_CFG (24'hBC07DC),
.CPLL_FBDIV (4),
.CPLL_FBDIV_45 (5),
.CPLL_INIT_CFG (24'h00001E),
.CPLL_LOCK_CFG (16'h01E8),
.CPLL_REFCLK_DIV (1),
.RXOUT_DIV (2),
.TXOUT_DIV (2),
.SATA_CPLL_CFG ("VCO_3000MHZ"),
.RXDFELPMRESET_TIME (RXDFELPMRESET_TIME),
.RXLPM_HF_CFG (14'b00000011110000),
.RXLPM_LF_CFG (14'b00000011110000),
.RX_DFE_GAIN_CFG (23'h020FEA),
.RX_DFE_H2_CFG (12'b000000000000),
.RX_DFE_H3_CFG (12'b000001000000),
.RX_DFE_H4_CFG (11'b00011110000),
.RX_DFE_H5_CFG (11'b00011100000),
.RX_DFE_KL_CFG (13'b0000011111110),
.RX_DFE_LPM_CFG (16'h0954),
.RX_DFE_LPM_HOLD_DURING_EIDLE (1'b0),
.RX_DFE_UT_CFG (17'b10001111000000000),
.RX_DFE_VP_CFG (17'b00011111100000011),
.RX_CLKMUX_PD (1'b1),
.TX_CLKMUX_PD (1'b1),
.RX_INT_DATAWIDTH (0),
.TX_INT_DATAWIDTH (0),
.TX_QPI_STATUS_EN (1'b0),
.RX_DFE_KL_CFG2 (32'h301148AC),
.RX_DFE_XYD_CFG (13'b0000000000000),
.TX_PREDRIVER_MODE (1'b0)
)
gtx(
.CPLLFBCLKLOST (),
.CPLLLOCK (cplllock),
.CPLLLOCKDETCLK (cplllockdetclk),
.CPLLLOCKEN (1'b1),
.CPLLPD (1'b0),
.CPLLREFCLKLOST (),
.CPLLREFCLKSEL (3'b001),
.CPLLRESET (cpllreset),
.GTRSVD (1'b0),
.PCSRSVDIN (1'b0),
.PCSRSVDIN2 (1'b0),
.PMARSVDIN (1'b0),
.PMARSVDIN2 (1'b0),
.TSTIN (1'b1),
.TSTOUT (),
.CLKRSVD (4'b0000),
.GTGREFCLK (1'b0),
.GTNORTHREFCLK0 (1'b0),
.GTNORTHREFCLK1 (1'b0),
.GTREFCLK0 (gtrefclk),
.GTREFCLK1 (1'b0),
.GTSOUTHREFCLK0 (1'b0),
.GTSOUTHREFCLK1 (1'b0),
.DRPADDR (9'b0),
.DRPCLK (drpclk),
.DRPDI (16'b0),
.DRPDO (),
.DRPEN (1'b0),
.DRPRDY (),
.DRPWE (1'b0),
.GTREFCLKMONITOR (),
.QPLLCLK (gtrefclk),
.QPLLREFCLK (gtrefclk),
.RXSYSCLKSEL (2'b00),
.TXSYSCLKSEL (2'b00),
.DMONITOROUT (),
.TX8B10BEN (1'b1),
.LOOPBACK (3'd0),
.PHYSTATUS (),
.RXRATE (3'd0),
.RXVALID (),
.RXPD (2'b00),
.TXPD (2'b00),
.SETERRSTATUS (1'b0),
.EYESCANRESET (1'b0),//rxreset), // p78
.RXUSERRDY (rxuserrdy),
.EYESCANDATAERROR (),
.EYESCANMODE (1'b0),
.EYESCANTRIGGER (1'b0),
.RXCDRFREQRESET (1'b0),
.RXCDRHOLD (1'b0),
.RXCDRLOCK (),
.RXCDROVRDEN (1'b0),
.RXCDRRESET (1'b0),
.RXCDRRESETRSV (1'b0),
.RXCLKCORCNT (),
.RX8B10BEN (1'b1),
.RXUSRCLK (rxusrclk),
.RXUSRCLK2 (rxusrclk2),
.RXDATA (rxdata_gtx),
.RXPRBSERR (),
.RXPRBSSEL (3'd0),
.RXPRBSCNTRESET (1'b0),
.RXDFEXYDEN (1'b1),
.RXDFEXYDHOLD (1'b0),
.RXDFEXYDOVRDEN (1'b0),
.RXDISPERR (rxdisperr_gtx),
.RXNOTINTABLE (rxnotintable_gtx),
.GTXRXP (rxp),
.GTXRXN (rxn),
.RXBUFRESET (1'b0),
.RXBUFSTATUS (),
.RXDDIEN (1'b0),
.RXDLYBYPASS (1'b1),
.RXDLYEN (1'b0),
.RXDLYOVRDEN (1'b0),
.RXDLYSRESET (1'b0),
.RXDLYSRESETDONE (),
.RXPHALIGN (1'b0),
.RXPHALIGNDONE (),
.RXPHALIGNEN (1'b0),
.RXPHDLYPD (1'b0),
.RXPHDLYRESET (1'b0),
.RXPHMONITOR (),
.RXPHOVRDEN (1'b0),
.RXPHSLIPMONITOR (),
.RXSTATUS (),
.RXBYTEISALIGNED (rxbyteisaligned),
.RXBYTEREALIGN (),
.RXCOMMADET (),
.RXCOMMADETEN (1'b1),
.RXMCOMMAALIGNEN (1'b1),
.RXPCOMMAALIGNEN (1'b1),
.RXCHANBONDSEQ (),
.RXCHBONDEN (1'b0),
.RXCHBONDLEVEL (3'd0),
.RXCHBONDMASTER (1'b0),
.RXCHBONDO (),
.RXCHBONDSLAVE (1'b0),
.RXCHANISALIGNED (),
.RXCHANREALIGN (),
.RXLPMHFHOLD (1'b0),
.RXLPMHFOVRDEN (1'b0),
.RXLPMLFHOLD (1'b0),
.RXDFEAGCHOLD (1'b0),
.RXDFEAGCOVRDEN (1'b0),
.RXDFECM1EN (1'b0),
.RXDFELFHOLD (1'b0),
.RXDFELFOVRDEN (1'b1),
.RXDFELPMRESET (rxreset),
.RXDFETAP2HOLD (1'b0),
.RXDFETAP2OVRDEN (1'b0),
.RXDFETAP3HOLD (1'b0),
.RXDFETAP3OVRDEN (1'b0),
.RXDFETAP4HOLD (1'b0),
.RXDFETAP4OVRDEN (1'b0),
.RXDFETAP5HOLD (1'b0),
.RXDFETAP5OVRDEN (1'b0),
.RXDFEUTHOLD (1'b0),
.RXDFEUTOVRDEN (1'b0),
.RXDFEVPHOLD (1'b0),
.RXDFEVPOVRDEN (1'b0),
// .RXDFEVSEN (1'b0),
.RXLPMLFKLOVRDEN (1'b0),
.RXMONITOROUT (),
.RXMONITORSEL (2'b01),
.RXOSHOLD (1'b0),
.RXOSOVRDEN (1'b0),
.RXRATEDONE (),
.RXOUTCLK (),
.RXOUTCLKFABRIC (),
.RXOUTCLKPCS (),
.RXOUTCLKSEL (3'b010),
.RXDATAVALID (),
.RXHEADER (),
.RXHEADERVALID (),
.RXSTARTOFSEQ (),
.RXGEARBOXSLIP (1'b0),
.GTRXRESET (rxreset),
.RXOOBRESET (1'b0),
.RXPCSRESET (1'b0),
.RXPMARESET (1'b0),//rxreset), // p78
.RXLPMEN (1'b0),
.RXCOMSASDET (),
.RXCOMWAKEDET (rxcomwakedet),
.RXCOMINITDET (rxcominitdet),
.RXELECIDLE (rxelecidle),
.RXELECIDLEMODE (2'b00),
.RXPOLARITY (1'b0),
.RXSLIDE (1'b0),
.RXCHARISCOMMA (rxchariscomma_gtx),
.RXCHARISK (rxcharisk_gtx),
.RXCHBONDI (5'b00000),
.RXRESETDONE (rxresetdone),
.RXQPIEN (1'b0),
.RXQPISENN (),
.RXQPISENP (),
.TXPHDLYTSTCLK (1'b0),
.TXPOSTCURSOR (5'b00000),
.TXPOSTCURSORINV (1'b0),
.TXPRECURSOR (5'd0),
.TXPRECURSORINV (1'b0),
.TXQPIBIASEN (1'b0),
.TXQPISTRONGPDOWN (1'b0),
.TXQPIWEAKPUP (1'b0),
.CFGRESET (1'b0),
.GTTXRESET (txreset),
.PCSRSVDOUT (),
.TXUSERRDY (txuserrdy),
.GTRESETSEL (1'b0),
.RESETOVRD (1'b0),
.TXCHARDISPMODE (8'd0),
.TXCHARDISPVAL (8'd0),
.TXUSRCLK (txusrclk),
.TXUSRCLK2 (txusrclk2),
.TXELECIDLE (txelecidle),
.TXMARGIN (3'd0),
.TXRATE (3'd0),
.TXSWING (1'b0),
.TXPRBSFORCEERR (1'b0),
.TXDLYBYPASS (1'b1),
.TXDLYEN (1'b0),
.TXDLYHOLD (1'b0),
.TXDLYOVRDEN (1'b0),
.TXDLYSRESET (1'b0),
.TXDLYSRESETDONE (),
.TXDLYUPDOWN (1'b0),
.TXPHALIGN (1'b0),
.TXPHALIGNDONE (),
.TXPHALIGNEN (1'b0),
.TXPHDLYPD (1'b0),
.TXPHDLYRESET (1'b0),
.TXPHINIT (1'b0),
.TXPHINITDONE (),
.TXPHOVRDEN (1'b0),
.TXBUFSTATUS (),
.TXBUFDIFFCTRL (3'b100),
.TXDEEMPH (1'b0),
.TXDIFFCTRL (4'b1000),
.TXDIFFPD (1'b0),
.TXINHIBIT (1'b0),
.TXMAINCURSOR (7'b0000000),
.TXPISOPD (1'b0),
.TXDATA ({32'h0, txdata}),
.GTXTXN (txn),
.GTXTXP (txp),
.TXOUTCLK (txoutclk),
.TXOUTCLKFABRIC (),
.TXOUTCLKPCS (),
.TXOUTCLKSEL (3'b010),
.TXRATEDONE (),
.TXCHARISK ({4'b0, txcharisk}),
.TXGEARBOXREADY (),
.TXHEADER (3'd0),
.TXSEQUENCE (7'd0),
.TXSTARTSEQ (1'b0),
.TXPCSRESET (txpcsreset),
.TXPMARESET (1'b0),
.TXRESETDONE (txresetdone),
.TXCOMFINISH (txcomfinish),
.TXCOMINIT (txcominit),
.TXCOMSAS (1'b0),
.TXCOMWAKE (txcomwake),
.TXPDELECIDLEMODE (1'b0),
.TXPOLARITY (1'b0),
.TXDETECTRX (1'b0),
.TX8B10BBYPASS (8'd0),
.TXPRBSSEL (3'd0),
.TXQPISENN (),
.TXQPISENP ()/*,
.TXSYNCMODE (1'b0),
.TXSYNCALLIN (1'b0),
.TXSYNCIN (1'b0)*/
);
// align to 4-byte boundary
reg twobytes_shift;
always @ (posedge clk)
twobytes_shift <= rst ? 1'b0 : rxchariscomma_gtx[0] === 1'bx ? 1'b0 : rxchariscomma_gtx[2] === 1'bx ? 1'b0 : rxchariscomma_gtx[2] ? 1'b1 : rxchariscomma_gtx[0] ? 1'b0 : twobytes_shift;
assign rxdata = twobytes_shift ? {rxdata_gtx[63:32] , rxdata_gtx[15:0] , rxdata_gtx[31:16] } : rxdata_gtx;
assign rxcharisk = twobytes_shift ? {rxcharisk_gtx[7:4] , rxcharisk_gtx[1:0] , rxcharisk_gtx[3:2] } : rxcharisk_gtx;
assign rxchariscomma = twobytes_shift ? {rxchariscomma_gtx[7:4], rxchariscomma_gtx[1:0], rxchariscomma_gtx[3:2]} : rxchariscomma_gtx;
assign rxdisperr = twobytes_shift ? {rxdisperr_gtx[7:4] , rxdisperr_gtx[1:0] , rxdisperr_gtx[3:2] } : rxdisperr_gtx;
assign rxnotintable = twobytes_shift ? {rxnotintable_gtx[7:4] , rxnotintable_gtx[1:0] , rxnotintable_gtx[3:2] } : rxnotintable_gtx;
/*
* Interfaces
*/
assign cplllockdetclk = gtrefclk; //TODO
assign drpclk = gtrefclk;
assign clk = usrclk2;
assign rxn = rxn_in;
assign rxp = rxp_in;
assign txn_out = txn;
assign txp_out = txp;
assign ll_data_out = rxdata_out;
assign ll_charisk_out = rxcharisk_out;
assign txdata_in = ll_data_in;
assign txcharisk_in = ll_charisk_in;
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/dma/ 0000775 0000000 0000000 00000000000 12572445207 0020562 5 ustar 00root root 0000000 0000000 x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/dma/axi_regs.v 0000664 0000000 0000000 00000015364 12572445207 0022563 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: axi_regs
* Date: 2015-07-11
* Author: Alexey
* Description: slave axi interface buffer
*
* Copyright (c) 2015 Elphel, Inc.
* axi_regs.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* axi_regs.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`include "axibram_read.v"
`include "axibram_write.v"
module axi_regs #(
parameter REGISTERS_CNT = 20
)
(
input wire ACLK, // AXI PS Master GP1 Clock , input
input wire ARESETN, // AXI PS Master GP1 Reset, output
// AXI PS Master GP1: Read Address
input wire [31:0] ARADDR, // AXI PS Master GP1 ARADDR[31:0], output
input wire ARVALID, // AXI PS Master GP1 ARVALID, output
output wire ARREADY, // AXI PS Master GP1 ARREADY, input
input wire [11:0] ARID, // AXI PS Master GP1 ARID[11:0], output
input wire [1:0] ARLOCK, // AXI PS Master GP1 ARLOCK[1:0], output
input wire [3:0] ARCACHE, // AXI PS Master GP1 ARCACHE[3:0], output
input wire [2:0] ARPROT, // AXI PS Master GP1 ARPROT[2:0], output
input wire [3:0] ARLEN, // AXI PS Master GP1 ARLEN[3:0], output
input wire [1:0] ARSIZE, // AXI PS Master GP1 ARSIZE[1:0], output
input wire [1:0] ARBURST, // AXI PS Master GP1 ARBURST[1:0], output
input wire [3:0] ARQOS, // AXI PS Master GP1 ARQOS[3:0], output
// AXI PS Master GP1: Read Data
output wire [31:0] RDATA, // AXI PS Master GP1 RDATA[31:0], input
output wire RVALID, // AXI PS Master GP1 RVALID, input
input wire RREADY, // AXI PS Master GP1 RREADY, output
output wire [11:0] RID, // AXI PS Master GP1 RID[11:0], input
output wire RLAST, // AXI PS Master GP1 RLAST, input
output wire [1:0] RRESP, // AXI PS Master GP1 RRESP[1:0], input
// AXI PS Master GP1: Write Address
input wire [31:0] AWADDR, // AXI PS Master GP1 AWADDR[31:0], output
input wire AWVALID, // AXI PS Master GP1 AWVALID, output
output wire AWREADY, // AXI PS Master GP1 AWREADY, input
input wire [11:0] AWID, // AXI PS Master GP1 AWID[11:0], output
input wire [1:0] AWLOCK, // AXI PS Master GP1 AWLOCK[1:0], output
input wire [3:0] AWCACHE, // AXI PS Master GP1 AWCACHE[3:0], output
input wire [2:0] AWPROT, // AXI PS Master GP1 AWPROT[2:0], output
input wire [3:0] AWLEN, // AXI PS Master GP1 AWLEN[3:0], outpu:t
input wire [1:0] AWSIZE, // AXI PS Master GP1 AWSIZE[1:0], output
input wire [1:0] AWBURST, // AXI PS Master GP1 AWBURST[1:0], output
input wire [3:0] AWQOS, // AXI PS Master GP1 AWQOS[3:0], output
// AXI PS Master GP1: Write Data
input wire [31:0] WDATA, // AXI PS Master GP1 WDATA[31:0], output
input wire WVALID, // AXI PS Master GP1 WVALID, output
output wire WREADY, // AXI PS Master GP1 WREADY, input
input wire [11:0] WID, // AXI PS Master GP1 WID[11:0], output
input wire WLAST, // AXI PS Master GP1 WLAST, output
input wire [3:0] WSTRB, // AXI PS Master GP1 WSTRB[3:0], output
// AXI PS Master GP1: Write Responce
output wire BVALID, // AXI PS Master GP1 BVALID, input
input wire BREADY, // AXI PS Master GP1 BREADY, output
output wire [11:0] BID, // AXI PS Master GP1 BID[11:0], input
output wire [1:0] BRESP, // AXI PS Master GP1 BRESP[1:0], input
// registers iface
input wire [31:0] bram_rdata,
output wire [31:0] bram_waddr,
output wire [31:0] bram_wdata,
output wire [31:0] bram_raddr,
output wire [3:0] bram_wstb,
output wire bram_wen,
output wire bram_ren,
output wire bram_regen
);
/*
* Converntional MAXI interface from x393 project
*/
// Interface's instantiation
axibram_write #(
.ADDRESS_BITS(16)
)
axibram_write(
.aclk (ACLK),
.arst (ARESETN),
.awaddr (AWADDR),
.awvalid (AWVALID),
.awready (AWREADY),
.awid (AWID),
.awlen (AWLEN),
.awsize (AWSIZE),
.awburst (AWBURST),
.wdata (WDATA),
.wvalid (WVALID),
.wready (WREADY),
.wid (WID),
.wlast (WLAST),
.wstb (WSTRB),
.bvalid (BVALID),
.bready (BREADY),
.bid (BID),
.bresp (BRESP),
.pre_awaddr (),
.start_burst (),
.dev_ready (1'b1),
.bram_wclk (),
.bram_waddr (bram_waddr[15:0]),
.bram_wen (bram_wen),
.bram_wstb (bram_wstb),
.bram_wdata (bram_wdata)
);
axibram_read #(
.ADDRESS_BITS(16)
)
axibram_read(
.aclk (ACLK),
.arst (ARESETN),
.araddr (ARADDR),
.arvalid (ARVALID),
.arready (ARREADY),
.arid (ARID),
.arlen (ARLEN),
.arsize (ARSIZE),
.arburst (ARBURST),
.rdata (RDATA),
.rvalid (RVALID),
.rready (RREADY),
.rid (RID),
.rlast (RLAST),
.rresp (RRESP),
.pre_araddr (),
.start_burst (),
.dev_ready (1'b1),
.bram_rclk (),
.bram_raddr (bram_raddr[15:0]),
.bram_ren (bram_ren),
.bram_regen (bram_regen),
.bram_rdata (bram_rdata)
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/dma/dma_adapter.v 0000664 0000000 0000000 00000042573 12572445207 0023225 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: dma_adapter
* Date: 2015-07-11
* Author: Alexey
* Description: temporary interconnect to membridge testing purposes only
*
* Copyright (c) 2015 Elphel, Inc.
* dma_adapter.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dma_adapter.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/*
* The module is temporary
* It could make transactions from DMA data buffer to membridge and vice versa.
* Processes 1 transaction of 16 x 64bit-words at a time.
* Waits until 1 read or 1 write is completely done.
* After that it deasserts busy and is ready to process a new transaction.
*
* The whole purpose of a module as a system block is to be a buffer between
* a big dma data storage and axi interface. So it shall recieve data and control
* for 1 burst and pass it to axi.
*/
module dma_adapter(
input wire clk,
input wire rst,
// cmd iface
input wire cmd_type, // 1 = wr, 0 = rd
input wire cmd_val, // issue a cmd
input wire [31:7] cmd_addr, // [2:0] - 64-bit (8-bytes) word offset, [6:3] - 16-words transfer offset
output wire cmd_busy, // no-pipelined cmd execution, 1 cmd at a time
// data iface
input wire [63:0] wr_data_in,
input wire wr_val_in,
output wire wr_ack_out,
output wire [63:0] rd_data_out,
output wire rd_val_out,
input wire rd_ack_in,
// membridge iface
output wire [7:0] cmd_ad,
output wire cmd_stb,
input wire [7:0] status_ad,
input wire status_rq,
output wire status_start,
input wire frame_start_chn,
input wire next_page_chn,
output wire cmd_wrmem,
output wire page_ready_chn,
output wire frame_done_chn,
output wire [15:0] line_unfinished_chn1,
input wire suspend_chn1,
output wire xfer_reset_page_rd,
output wire buf_wpage_nxt,
output wire buf_wr,
output wire [63:0] buf_wdata,
output wire xfer_reset_page_wr,
output wire buf_rpage_nxt,
output wire buf_rd,
input wire [63:0] buf_rdata,
// additinal wire to indicate if membridge recieved a packet
input wire rdata_done // = membridge.is_last_in_page & membridge.afi_rready;
);
reg [2:0] membr_state;
// cmd handling
// if not busy and got cmd with val => cmd recieved, assert busy, start a respective algorithm
wire wr_start;
wire rd_start;
wire dma_start;
reg wr_done;
reg rd_done;
reg cmd_type_r;
reg [31:7] cmd_addr_r;
reg cmd_busy_r;
wire set_busy;
wire clr_busy;
assign set_busy = ~cmd_busy_r & cmd_val;
assign clr_busy = cmd_busy_r & (wr_done | rd_done);
assign cmd_busy = cmd_busy_r;
assign wr_start = set_busy & cmd_type;
assign rd_start = set_busy & ~cmd_type;
always @ (posedge clk)
begin
cmd_type_r <= rst ? 1'b0 : set_busy ? cmd_type : cmd_type_r;
cmd_addr_r <= rst ? 1'b0 : set_busy ? cmd_addr : cmd_addr_r;
cmd_busy_r <= (cmd_busy_r | set_busy) & ~rst & ~clr_busy;
end
/*
* Read/write data state machine
* For better readability the state machine is splitted to two pieces:
* the first one is responsible only for the CMD WRITE case handling,
* the second one, respectively, for CMD READ
*
* Simultaniously with each fsm starts a membridge fsm, which, if being 1st time launched,
* sets up membridge's registers, or, if have been launched before, just programs read/write
* address.
*
* Current implementation is extremely slow, but simple and reliable
* After all other parts are implemented and this place occurs to be a bottleneck
* then replace it (and may be membridge too) with something more ... pipelined
*/
// check if memberidge was already set up
reg membr_is_set;
always @ (posedge clk)
membr_is_set <= (membr_is_set | dma_start) & ~rst;
// common state register
reg [3:0] rdwr_state;
// Get data from buffer
localparam READ_IDLE = 0;
localparam READ_WAIT_ADDR = 3;
localparam READ_DATA = 4;
reg rd_reset_page;
reg rd_next_page;
reg rd_data;
reg [6:0] rd_data_count;
reg rd_en;
wire rd_stop;
wire rd_cnt_to_pull;
assign rd_cnt_to_pull = 7'hf;
assign rd_stop = rd_ack_in & rd_data_count == rd_cnt_to_pull;
assign rd_data_out = rd_data;
always @ (posedge clk)
if (rst)
begin
rdwr_state <= READ_IDLE;
rd_done <= 1'b0;
rd_data_count <= 7'h0;
rd_next_page <= 1'b0;
rd_en <= 1'b0;
end
else
case (rdwr_state)
READ_IDLE:
begin
rdwr_state <= rd_start ? READ_WAIT_ADDR : READ_IDLE;
rd_done <= 1'b0;
rd_data_count <= 7'h0;
rd_next_page <= 1'b0;
rd_en <= 1'b0;
end
READ_WAIT_ADDR: // wait until address information is sent to the bus and input buffer got data
begin
rdwr_state <= membr_state == READ_IDLE & rdata_done ? READ_DATA : READ_WAIT_ADDR;
rd_done <= 1'b0;
rd_data_count <= 7'h0;
rd_next_page <= 1'b0;
rd_en <= 1'b0;
end
READ_DATA:
begin
rdwr_state <= rd_stop ? READ_IDLE : READ_DATA;
rd_done <= rd_stop ? 1'b1 : 1'b0;
rd_data_count <= rd_ack_in ? rd_data_count + 1'b1 : rd_data_count;
rd_next_page <= rd_stop ? 1'b1 : 1'b0;
rd_en <= rd_ack_in ? 1'b1 : 1'b0;
end
default: // write is processing
begin
rdwr_state <= READ_IDLE;
rd_done <= 1'b0;
rd_data_count <= 7'h0;
rd_next_page <= 1'b0;
rd_en <= 1'b0;
end
endcase
// Put data into buffer
localparam WRITE_IDLE = 0;
localparam WRITE_DATA = 1;
localparam WRITE_WAIT_ADDR = 2;
reg wr_en;
reg wr_reset_page;
reg wr_next_page;
reg [63:0] wr_data;
reg [6:0] wr_data_count;
reg wr_page_ready;
reg wr_val;
wire [6:0] wr_cnt_to_push;
wire wr_stop;
assign wr_cnt_to_push = 7'hf;
assign wr_stop = wr_val_in & wr_data_count == wr_cnt_to_push;
assign wr_ack_out = wr_val_in & rdwr_state == WRITE_DATA;
//assign wr_data_in = wr_data;
// assuming for now we write only pre-defined 16 64-bit words
always @ (posedge clk)
if (rst)
begin
wr_done <= 1'b0;
wr_data_count <= 7'd0;
wr_val <= 1'b0;
wr_data <= 64'h0;
wr_next_page <= 1'b0;
wr_reset_page <= 1'b0;
wr_en <= 1'b0;
wr_page_ready <= 1'b0;
rdwr_state <= WRITE_IDLE;
end
else
case (rdwr_state)
WRITE_IDLE:
begin
wr_data_count <= 7'd0;
wr_done <= 1'b0;
wr_data <= 64'h0;
wr_next_page <= 1'b0;
wr_reset_page <= wr_start ? 1'b1 : 1'b0;
wr_en <= 1'b0;
wr_page_ready <= 1'b0;
rdwr_state <= wr_start ? WRITE_DATA : WRITE_IDLE;
end
WRITE_DATA:
begin
wr_done <= wr_stop & membr_state == WRITE_IDLE ? 1'b1 : 1'b0;
wr_data_count <= wr_val_in ? wr_data_count + 1'b1 : wr_data_count;
wr_data <= wr_data_in;
wr_next_page <= wr_stop ? 1'b1 : 1'b0;
wr_reset_page <= 1'b0;
wr_en <= wr_val_in;
wr_page_ready <= wr_stop ? 1'b1 : 1'b0;
rdwr_state <= wr_stop & membr_state == WRITE_IDLE ? WRITE_IDLE :
wr_stop ? WRITE_WAIT_ADDR : WRITE_DATA;
end
WRITE_WAIT_ADDR: // in case all data is written into a buffer, but address is still being issued on axi bus
begin
wr_done <= membr_state == WRITE_IDLE ? 1'b1 : 1'b0;
wr_data_count <= 7'd0;
wr_data <= 64'h0;
wr_next_page <= 1'b0;
wr_reset_page <= 1'b0;
wr_en <= 1'b0;
wr_page_ready <= 1'b0;
rdwr_state <= membr_state == WRITE_IDLE ? WRITE_IDLE : WRITE_WAIT_ADDR;
end
default: // read is executed
begin
wr_done <= 1'b0;
wr_data_count <= 7'd0;
wr_data <= 64'h0;
wr_next_page <= 1'b0;
wr_reset_page <= 1'b0;
wr_en <= 1'b0;
wr_page_ready <= 1'b0;
rdwr_state <= rdwr_state;
end
endcase
// membridge interface assigments
assign status_start = 1'b0; // no need until status is used
assign cmd_wrmem = ~cmd_type_r;
assign xfer_reset_page_wr = rd_reset_page;
assign buf_rpage_nxt = rd_next_page;
assign buf_rd = rd_en;
assign buf_wdata = wr_data;
assign buf_wr = wr_en;
assign buf_wpage_nxt = wr_next_page;
assign xfer_reset_page_rd = wr_reset_page;
assign page_ready_chn = cmd_wrmem ? 1'b0 : wr_page_ready;
assign frame_done_chn = 1'b1;
/*
* Transfer address and membridge set-ups state machine
*/
localparam MEMBR_IDLE = 0;
localparam MEMBR_MODE = 1;
localparam MEMBR_WIDTH = 2;
localparam MEMBR_LEN = 3;
localparam MEMBR_START = 4;
localparam MEMBR_SIZE = 5;
localparam MEMBR_LOADDR = 6;
localparam MEMBR_CTRL = 7;
reg [32:0] membr_data;
reg [15:0] membr_addr;
reg membr_start;
reg membr_done;
reg membr_setup; // indicates the first tick of the state
wire membr_inprocess;
assign dma_start = wr_start | rd_start;
always @ (posedge clk)
if (rst)
begin
membr_data <= 32'h0;
membr_addr <= 16'h0;
membr_start <= 1'b0;
membr_setup <= 1'b0;
membr_done <= 1'b0;
membr_state <= MEMBR_IDLE;
end
else
case (membr_state)
MEMBR_IDLE:
begin
membr_data <= 32'h0;
membr_addr <= 16'h200;
membr_start <= dma_start ? 1'b1 : 1'b0;
membr_setup <= dma_start ? 1'b1 : 1'b0;
membr_done <= 1'b0;
membr_state <= dma_start & membr_is_set ? MEMBR_LOADDR :
dma_start ? MEMBR_MODE : MEMBR_IDLE;
end
MEMBR_MODE:
begin
membr_data <= 32'h3;
membr_addr <= 16'h207;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_done <= 1'b0;
membr_state <= membr_inprocess | membr_setup ? MEMBR_MODE : MEMBR_WIDTH;
end
MEMBR_WIDTH:
begin
membr_data <= 32'h10;
membr_addr <= 16'h206;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_done <= 1'b0;
membr_state <= membr_inprocess | membr_setup ? MEMBR_WIDTH : MEMBR_LEN;
end
MEMBR_LEN:
begin
membr_data <= 32'h10;
membr_addr <= 16'h205;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_done <= 1'b0;
membr_state <= membr_inprocess | membr_setup ? MEMBR_LEN : MEMBR_START;
end
MEMBR_START:
begin
membr_data <= 32'h0;
membr_addr <= 16'h204;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_done <= 1'b0;
membr_state <= membr_inprocess | membr_setup ? MEMBR_START : MEMBR_SIZE;
end
MEMBR_SIZE:
begin
membr_data <= 32'h10;
membr_addr <= 16'h203;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_done <= 1'b0;
membr_state <= membr_inprocess | membr_setup ? MEMBR_SIZE : MEMBR_LOADDR;
end
MEMBR_LOADDR:
begin
membr_data <= cmd_addr_r;
membr_addr <= 16'h202;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_done <= 1'b0;
membr_state <= membr_inprocess | membr_setup ? MEMBR_LOADDR : MEMBR_CTRL;
end
MEMBR_CTRL:
begin
membr_data <= {28'h0000000, 4'b0011};
membr_addr <= 16'h200;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= 1'b0;
membr_done <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_state <= membr_inprocess | membr_setup ? MEMBR_CTRL : MEMBR_IDLE;
end
default:
begin
membr_data <= 32'h0;
membr_addr <= 16'h0;
membr_start <= 1'b0;
membr_setup <= 1'b0;
membr_done <= 1'b0;
membr_state <= MEMBR_IDLE;
end
endcase
// write to memridge registers fsm
localparam STATE_IDLE = 3'h0;
localparam STATE_CMD_0 = 3'h1;
localparam STATE_CMD_1 = 3'h2;
localparam STATE_DATA_0 = 3'h3;
localparam STATE_DATA_1 = 3'h4;
localparam STATE_DATA_2 = 3'h5;
localparam STATE_DATA_3 = 3'h6;
reg [2:0] state;
reg [7:0] out_ad;
reg out_stb;
assign membr_inprocess = state != STATE_IDLE;
assign cmd_ad = out_ad;
assign cmd_stb = out_stb;
always @ (posedge clk)
if (rst)
begin
state <= STATE_IDLE;
out_ad <= 8'h0;
out_stb <= 1'b0;
end
else
case (state)
STATE_IDLE:
begin
out_ad <= 8'h0;
out_stb <= 1'b0;
state <= membr_setup ? STATE_CMD_0 : STATE_IDLE;
end
STATE_CMD_0:
begin
out_ad <= membr_addr[7:0];
out_stb <= 1'b1;
state <= STATE_CMD_1;
end
STATE_CMD_1:
begin
out_ad <= membr_addr[15:8];
out_stb <= 1'b0;
state <= STATE_DATA_0;
end
STATE_DATA_0:
begin
out_ad <= membr_data[7:0];
out_stb <= 1'b0;
state <= STATE_DATA_1;
end
STATE_DATA_1:
begin
out_ad <= membr_data[15:8];
out_stb <= 1'b0;
state <= STATE_DATA_2;
end
STATE_DATA_2:
begin
out_ad <= membr_data[23:16];
out_stb <= 1'b0;
state <= STATE_DATA_3;
end
STATE_DATA_3:
begin
out_ad <= membr_data[31:24];
out_stb <= 1'b0;
state <= STATE_IDLE;
end
default:
begin
out_ad <= 8'hff;
out_stb <= 1'b0;
state <= STATE_IDLE;
end
endcase
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/dma/dma_control.v 0000664 0000000 0000000 00000034327 12572445207 0023263 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: dma_control
* Date: 2015-07-11
* Author: Alexey
* Description: temporary dma request control logic
*
* Copyright (c) 2015 Elphel, Inc.
* dma_control.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dma_control.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/*
* Later on most of address evaluation logic could be divided into 2 parts, which
* could be presented as 2 instances of 1 parameterized module
* + split data and address parts. Didnt do that because not sure if
* virtual channels would be implemented in the future
*/
module dma_control(
input wire sclk, // sata clock
input wire hclk, // axi-hp clock
input wire rst,
// registers iface
input wire [31:7] mem_address,
input wire [31:0] lba,
input wire [31:0] sector_cnt,
input wire dma_type,
input wire dma_start,
output wire dma_done,
// adapter command iface
input wire adp_busy,
output wire [31:7] adp_addr,
output wire adp_type,
output wire adp_val,
// sata host command iface
input wire host_ready_for_cmd,
output wire host_new_cmd,
output wire [1:0] host_cmd_type,
output wire [31:0] host_sector_count,
output wire [31:0] host_sector_addr,
// adapter data iface
// to main memory
output wire [63:0] to_data,
output wire to_val,
input wire to_ack,
// from main memory
input wire [63:0] from_data,
input wire from_val,
output wire from_ack,
// sata host iface
// data from sata host
input wire [31:0] in_data,
output wire in_val,
input wire in_busy,
// data to sata host
output wire [31:0] out_data,
output wire out_val,
input wire out_busy
);
//////////////////////////////////////////////////////////////////////////////////////
//// ADDRESS
//////////////////////////////////////////////////////////////////////////////////////
wire dma_done_adp;
wire dma_done_host;
assign dma_done = dma_done_host & dma_done_adp;
reg adp_busy_sclk;
/*
* Commands to sata host fsm
*/
// for now only 2 states: idle and send a pulse
reg host_issued;
wire host_issued_set;
wire host_issued_clr;
assign dma_done_host = host_issued;
assign host_issued_set = ~adp_busy_sclk & host_ready_for_cmd & dma_start;
assign host_issued_clr = dma_done;
always @ (posedge sclk)
host_issued <= (host_issued | host_issued_set) & ~host_issued_clr & ~rst;
// drive iface signals
assign host_new_cmd = host_issued_set;
assign host_cmd_type = dma_type;
assign host_sector_count = sector_cnt;
assign host_sector_addr = lba;
/*
* Commands to adapter fsm
*/
reg [33:0] quarter_sector_cnt;
wire last_data; // last 128 bytes of data are transmitted now
wire adp_val_sclk;
reg [31:7] current_addr;
reg current_type;
// fsm itself
wire state_idle;
reg state_wait_busy;
reg state_wait_done;
wire set_wait_busy;
wire set_wait_done;
wire clr_wait_busy;
wire clr_wait_done;
assign set_wait_busy = state_idle & host_issued_set // same start pulse for both fsms
| state_wait_done & clr_wait_done & ~last_data; // still have some data to transmit within a current dma request
assign set_wait_done = state_wait_busy & clr_wait_busy;
assign clr_wait_busy = adp_busy_sclk;
assign clr_wait_done = ~adp_busy_sclk;
assign state_idle = ~state_wait_busy & ~state_wait_done;
always @ (posedge sclk)
begin
state_wait_busy <= (state_wait_busy | set_wait_busy) & ~clr_wait_busy & ~rst;
state_wait_done <= (state_wait_done | set_wait_done) & ~clr_wait_done & ~rst;
end
// conrol signals resync
reg adp_val_r;
reg adp_val_rr;
always @ (posedge hclk)
begin
adp_val_r <= adp_val_sclk;
adp_val_rr <= adp_val_r;
end
assign adp_addr = current_addr;
assign adp_type = current_type;
assign adp_val = adp_val_rr;
// Maintaining correct adp_busy level @ sclk
// assuming busy won't toggle rapidly, can afford not implementing handshakes
wire adp_busy_sclk_set;
wire adp_busy_sclk_clr;
wire adp_busy_set;
wire adp_busy_clr;
reg adp_busy_r;
assign adp_busy_set = adp_busy & ~adp_busy_r;
assign adp_busy_clr = ~adp_busy & adp_busy_r;
always @ (posedge sclk)
adp_busy_sclk <= (adp_busy_sclk | adp_busy_sclk_set) & ~rst & ~adp_busy_sclk_clr;
always @ (posedge hclk)
adp_busy_r <= adp_busy;
pulse_cross_clock adp_busy_set_pulse(
.rst (rst),
.src_clk (hclk),
.dst_clk (sclk),
.in_pulse (adp_busy_set),
.out_pulse (adp_busy_sclk_set),
.busy ()
);
pulse_cross_clock adp_busy_clr_pulse(
.rst (rst),
.src_clk (hclk),
.dst_clk (sclk),
.in_pulse (adp_busy_clr),
.out_pulse (adp_busy_sclk_clr),
.busy ()
);
// synchronize with host fsm
reg adp_done;
wire adp_done_clr;
wire adp_done_set;
assign dma_done_adp = adp_done;
assign adp_done_set = state_wait_done & clr_wait_done & ~set_wait_busy; // = state_wait_done & set_idle;
assign adp_done_clr = dma_done;
always @ (posedge sclk)
adp_done <= (adp_done | adp_done_set) & ~adp_done_clr & ~rst;
// calculate sent sector count
// 1 sector = 512 bytes for now => 1 quarter_sector = 128 bytes
always @ (posedge sclk)
quarter_sector_cnt <= ~set_wait_busy ? quarter_sector_cnt :
state_idle ? 34'h0 : // new dma request
quarter_sector_cnt + 1'b1; // same dma request, next 128 bytes
// flags if we're currently sending the last data piece of dma transaction
assign last_data = (sector_cnt == quarter_sector_cnt[33:2] + 1'b1) & (&quarter_sector_cnt[1:0]);
// calculate outgoing address
// increment every transaction to adapter
always @ (posedge sclk)
current_addr <= ~set_wait_busy ? current_addr :
state_idle ? mem_address : // new dma request
current_addr + 1'b1; // same dma request, next 128 bytes
always @ (posedge sclk)
current_type <= ~set_wait_busy ? current_type :
state_idle ? dma_type : // new dma request
current_type; // same dma request, next 128 bytes
//////////////////////////////////////////////////////////////////////////////////////
//// DATA
//////////////////////////////////////////////////////////////////////////////////////
/*
* from main memory resyncronisation circuit
*/
reg [9:0] from_rd_addr;
reg [8:0] from_wr_addr;
// incremened addresses
wire [8:0] from_wr_next_addr;
wire [9:0] from_rd_next_addr;
// gray coded addresses
reg [9:0] from_rd_addr_gr;
reg [8:0] from_wr_addr_gr;
// anti-metastability shift registers for gray-coded addresses
reg [9:0] from_rd_addr_gr_r;
reg [8:0] from_wr_addr_gr_r;
reg [9:0] from_rd_addr_gr_rr;
reg [8:0] from_wr_addr_gr_rr;
// resynced to opposite clks addresses
wire [9:0] from_rd_addr_r;
wire [8:0] from_wr_addr_r;
// fifo states
wire from_full; // MAY BE full. ~full -> MUST NOT be full
wire from_empty; // MAY BE empty. ~empty -> MUST NOT be empty
wire from_re;
wire from_we;
assign from_wr_next_addr = from_wr_addr + 1'b1;
assign from_rd_next_addr = from_rd_addr + 1'b1;
// hclk domain counters
always @ (posedge hclk)
begin
from_wr_addr <= rst ? 9'h0 : from_we ? from_wr_next_addr : from_wr_addr;
from_wr_addr_gr <= rst ? 9'h0 : from_we ? from_wr_next_addr ^ {1'b0, from_wr_next_addr[8:1]} : from_wr_addr_gr;
end
// sclk domain counters
always @ (posedge sclk)
begin
from_rd_addr <= rst ? 10'h0 : from_re ? from_rd_next_addr : from_rd_addr;
from_rd_addr_gr <= rst ? 10'h0 : from_re ? from_rd_next_addr ^ {1'b0, from_rd_next_addr[9:1]} : from_rd_addr_gr;
end
// write address -> sclk (rd) domain to compare
always @ (posedge sclk)
begin
from_wr_addr_gr_r <= rst ? 9'h0 : from_wr_addr;
from_wr_addr_gr_rr <= rst ? 9'h0 : from_wr_addr_gr_r;
end
// read address -> hclk (wr) domain to compare
always @ (posedge hclk)
begin
from_rd_addr_gr_r <= rst ? 10'h0 : from_rd_addr;
from_rd_addr_gr_rr <= rst ? 10'h0 : from_rd_addr_gr_r;
end
// translate resynced write address into ordinary (non-gray) address
genvar ii;
generate
for (ii = 0; ii < 9; ii = ii + 1)
begin: from_wr_antigray
assign from_wr_addr_r[ii] = ^from_wr_addr_gr_rr[8:ii];
end
endgenerate
// translate resynced read address into ordinary (non-gray) address
generate
for (ii = 0; ii < 10; ii = ii + 1)
begin: from_rd_antigray
assign from_rd_addr_r[ii] = ^from_rd_addr_gr_rr[9:ii];
end
endgenerate
// so we've got the following:
// hclk domain: from_wr_addr - current write address
// from_rd_addr_r - read address some hclk ticks ago
// => we can say if the fifo have the possibility to be full
// since actual from_rd_addr could only be incremented
//
// sclk domain: from_rd_addr - current read address
// from_wr_addr_r - write address some sclk ticks ago
// => we can say if the fifo have the possibility to be empty
// since actual from_wr_addr could only be incremented
assign from_full = {from_wr_addr, 1'b0} == from_rd_addr_r + 1'b1;
assign from_empty = {from_wr_addr_r, 1'b0} == from_rd_addr; // overflows must never be achieved
// calculate bus responses in order to fifo status:
assign from_ack = from_val & ~from_full;
assign out_val = ~out_busy & ~from_empty;
assign from_re = out_val;
assign from_we = from_ack;
// data buffer, recieves 64-bit data from main memory, directs it to sata host
ram_512x64w_1kx32r #(
.REGISTERS (0)
)
dma_data_from_mem (
.rclk (sclk),
.raddr (from_rd_addr),
.ren (from_re),
.regen (1'b0),
.data_out (out_data),
.wclk (hclk),
.waddr (from_wr_addr),
.we (from_we),
.web (8'hff),
.data_in (from_data)
);
/////////////////////////////////////////////////////////////////////////////////
/*
* to main memory resyncronisation circuit
*/
reg [8:0] to_rd_addr;
reg [9:0] to_wr_addr;
// incremened addresses
wire [9:0] to_wr_next_addr;
wire [8:0] to_rd_next_addr;
// gray coded addresses
reg [8:0] to_rd_addr_gr;
reg [9:0] to_wr_addr_gr;
// anti-metastability shift registers for gray-coded addresses
reg [8:0] to_rd_addr_gr_r;
reg [9:0] to_wr_addr_gr_r;
reg [8:0] to_rd_addr_gr_rr;
reg [9:0] to_wr_addr_gr_rr;
// resynced to opposite clks addresses
wire [8:0] to_rd_addr_r;
wire [9:0] to_wr_addr_r;
// fifo states
wire to_full; // MAY BE full. ~full -> MUST NOT be full
wire to_empty; // MAY BE empty. ~empty -> MUST NOT be empty
wire to_re;
wire to_we;
assign to_wr_next_addr = to_wr_addr + 1'b1;
assign to_rd_next_addr = to_rd_addr + 1'b1;
// sclk domain counters
always @ (posedge sclk)
begin
to_wr_addr <= rst ? 10'h0 : to_we ? to_wr_next_addr : to_wr_addr;
to_wr_addr_gr <= rst ? 10'h0 : to_we ? to_wr_next_addr ^ {1'b0, to_wr_next_addr[9:1]} : to_wr_addr_gr;
end
// hclk domain counters
always @ (posedge hclk)
begin
to_rd_addr <= rst ? 9'h0 : to_re ? to_rd_next_addr : to_rd_addr;
to_rd_addr_gr <= rst ? 9'h0 : to_re ? to_rd_next_addr ^ {1'b0, to_rd_next_addr[8:1]} : to_rd_addr_gr;
end
// write address -> hclk (rd) domain to compare
always @ (posedge hclk)
begin
to_wr_addr_gr_r <= rst ? 10'h0 : to_wr_addr;
to_wr_addr_gr_rr <= rst ? 10'h0 : to_wr_addr_gr_r;
end
// read address -> sclk (wr) domain to compare
always @ (posedge sclk)
begin
to_rd_addr_gr_r <= rst ? 9'h0 : to_rd_addr;
to_rd_addr_gr_rr <= rst ? 9'h0 : to_rd_addr_gr_r;
end
// translate resynced write address into ordinary (non-gray) address
generate
for (ii = 0; ii < 10; ii = ii + 1)
begin: to_wr_antigray
assign to_wr_addr_r[ii] = ^to_wr_addr_gr_rr[9:ii];
end
endgenerate
// translate resynced read address into ordinary (non-gray) address
generate
for (ii = 0; ii < 9; ii = ii + 1)
begin: to_rd_antigray
assign to_rd_addr_r[ii] = ^to_rd_addr_gr_rr[8:ii];
end
endgenerate
// so we've got the following:
// sclk domain: to_wr_addr - current write address
// to_rd_addr_r - read address some sclk ticks ago
// => we can say if the fifo have the possibility to be full
// since actual to_rd_addr could only be incremented
//
// hclk domain: to_rd_addr - current read address
// to_wr_addr_r - write address some hclk ticks ago
// => we can say if the fifo have the possibility to be empty
// since actual to_wr_addr could only be incremented
assign to_full = {to_wr_addr, 1'b0} == to_rd_addr_r + 1'b1;
assign to_empty = {to_wr_addr_r, 1'b0} == to_rd_addr; // overflows must never be achieved
// calculate bus responses in order to fifo status:
assign to_val = ~to_empty;
assign in_val = ~in_busy & ~to_full;
assign to_re = to_ack;
assign to_we = in_val;
// data buffer, recieves 32-bit data from sata host, directs it to the main memory
ram_1kx32w_512x64r #(
.REGISTERS (0)
)
dma_data_to_mem (
.rclk (hclk),
.raddr (to_rd_addr),
.ren (to_re),
.regen (1'b0),
.data_out (to_data),
.wclk (sclk),
.waddr (to_wr_addr),
.we (to_we),
.web (4'hf),
.data_in (in_data)
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/dma/dma_regs.v 0000664 0000000 0000000 00000026501 12572445207 0022536 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: dma_regs
* Date: 2015-07-11
* Author: Alexey
* Description: temporary registers, connected to axi bus
*
* Copyright (c) 2015 Elphel, Inc.
* dma_regs.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dma_regs.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
module dma_regs #(
parameter REGISTERS_CNT = 20
)
(
input wire rst,
input wire ACLK,
input wire sclk,
// registers iface
output wire [31:7] mem_address,
output wire [31:0] lba,
output wire [31:0] sector_cnt,
output wire dma_type,
output wire dma_start,
input wire dma_done,
// axi buffer iface
output wire [31:0] bram_rdata,
input wire [31:0] bram_raddr,
input wire [31:0] bram_waddr,
input wire [31:0] bram_wdata,
input wire [3:0] bram_wstb,
input wire bram_wen,
input wire bram_ren,
input wire bram_regen,
// tmp to cmd control
output wire cmd_val_out,
output wire [31:0] cmd_out,
// tmp to shadow registers
output wire [31:0] sh_data, // write data
output wire sh_data_val, // write strobe
output wire sh_data_strobe, // read strobe
output wire [15:0] sh_feature,
output wire sh_feature_val,
output wire [23:0] sh_lba_lo,
output wire sh_lba_lo_val,
output wire [23:0] sh_lba_hi,
output wire sh_lba_hi_val,
output wire [15:0] sh_count,
output wire sh_count_val,
output wire [7:0] sh_command,
output wire sh_command_val,
output wire [7:0] sh_dev,
output wire sh_dev_val,
output wire [7:0] sh_control,
output wire sh_control_val,
output wire [31:0] sh_dma_id_lo,
output wire sh_dma_id_lo_val,
output wire [31:0] sh_dma_id_hi,
output wire sh_dma_id_hi_val,
output wire [31:0] sh_buf_off,
output wire sh_buf_off_val,
output wire [31:0] sh_dma_cnt,
output wire sh_dma_cnt_val,
output wire [15:0] sh_tran_cnt,
output wire sh_tran_cnt_val,
output wire sh_autoact,
output wire sh_autoact_val,
output wire sh_inter,
output wire sh_inter_val,
output wire [3:0] sh_port,
output wire sh_port_val,
output wire sh_notif,
output wire sh_notif_val,
output wire sh_dir,
output wire sh_dir_val,
// inputs from sh registers
input wire sh_data_val_in,
input wire [31:0] sh_data_in,
input wire [7:0] sh_control_in,
input wire [15:0] sh_feature_in,
input wire [47:0] sh_lba_in,
input wire [15:0] sh_count_in,
input wire [7:0] sh_command_in,
input wire [7:0] sh_err_in,
input wire [7:0] sh_status_in,
input wire [7:0] sh_estatus_in, // E_Status
input wire [7:0] sh_dev_in,
input wire [3:0] sh_port_in,
input wire sh_inter_in,
input wire sh_dir_in,
input wire [63:0] sh_dma_id_in,
input wire [31:0] sh_dma_off_in,
input wire [31:0] sh_dma_cnt_in,
input wire [15:0] sh_tran_cnt_in, // Transfer Count
input wire sh_notif_in,
input wire sh_autoact_in,
// inputs from cmd control
input wire [31:0] cmd_in
);
//reg [32*REGISTERS_CNT - 1:0] mem;
/*
* Converntional MAXI interface from x393 project, uses fifos, writes to/reads from memory
*/
/*
* Temporary mapping:
* rw 0x00: dma address (will automatically align to 128-bytes boundary, i.e. [6:0] -> 0
* rw 0x04: lba
* rw 0x08: sector count
* rw 0x0c: dma type (any(0x0c) => write)
* r1c 0x10: writes: dma start (any(0x10) => start)
* reads: dma status of last issued transfer (0xffffffff => done)
* ro 0x14: dma last issued dma_address
*/
reg [31:0] reg00;
reg [31:0] reg04;
reg [31:0] reg08;
reg [31:0] reg0c;
reg [31:0] reg10;
reg [31:0] reg14;
wire dma_done_aclk;
wire dma_start_aclk;
reg dma_issued;
wire [31:0] wdata;
pulse_cross_clock dma_done_pulse(
.rst (rst),
.src_clk (sclk),
.dst_clk (ACLK),
.in_pulse (dma_done),
.out_pulse (dma_done_aclk),
.busy ()
);
pulse_cross_clock dma_start_pulse(
.rst (rst),
.src_clk (ACLK),
.dst_clk (sclk),
.in_pulse (dma_start_aclk & ~dma_issued),
.out_pulse (dma_start),
.busy ()
);
assign dma_start_aclk = bram_wen & (bram_waddr[7:0] == 8'hf4) & |wdata;
assign wdata = bram_wdata[31:0] & {{8{bram_wstb[3]}}, {8{bram_wstb[2]}}, {8{bram_wstb[1]}}, {8{bram_wstb[0]}}};
always @ (posedge ACLK)
dma_issued <= (dma_issued | dma_start_aclk) & ~rst & ~dma_done_aclk;
assign mem_address = reg00[31:7];
assign lba = reg04;
assign sector_cnt = reg08;
assign dma_type = |reg0c;
always @ (posedge ACLK)
begin
reg00 <= rst ? 32'h0 : bram_wen & (bram_waddr[7:0] == 8'hf0) ? wdata : reg00;
reg04 <= rst ? 32'h0 : bram_wen & (bram_waddr[7:0] == 8'hf1) ? wdata : reg04;
reg08 <= rst ? 32'h0 : bram_wen & (bram_waddr[7:0] == 8'hf2) ? wdata : reg08;
reg0c <= rst ? 32'h0 : bram_wen & (bram_waddr[7:0] == 8'hf3) ? wdata : reg0c;
reg10 <= rst ? 32'h0 : dma_start_aclk ? 32'h0 : dma_done_aclk ? 32'hffffffff : reg10; // status reg
reg14 <= rst ? 32'h0 : dma_done_aclk ? reg00 : reg14;
end
// writes to shadow registers:
assign sh_data_val = bram_wen & (bram_waddr[7:0] == 8'h0);
assign sh_feature_val = bram_wen & (bram_waddr[7:0] == 8'h1);
assign sh_lba_lo_val = bram_wen & (bram_waddr[7:0] == 8'h2);
assign sh_lba_hi_val = bram_wen & (bram_waddr[7:0] == 8'h3);
assign sh_count_val = bram_wen & (bram_waddr[7:0] == 8'h4);
assign sh_command_val = bram_wen & (bram_waddr[7:0] == 8'h5);
assign sh_dev_val = bram_wen & (bram_waddr[7:0] == 8'h6);
assign sh_control_val = bram_wen & (bram_waddr[7:0] == 8'h7);
assign sh_dma_id_lo_val = bram_wen & (bram_waddr[7:0] == 8'h8);
assign sh_dma_id_hi_val = bram_wen & (bram_waddr[7:0] == 8'h9);
assign sh_buf_off_val = bram_wen & (bram_waddr[7:0] == 8'ha);
assign sh_tran_cnt_val = bram_wen & (bram_waddr[7:0] == 8'hb);
assign sh_autoact_val = bram_wen & (bram_waddr[7:0] == 8'hc);
assign sh_inter_val = bram_wen & (bram_waddr[7:0] == 8'hd);
assign sh_dir_val = bram_wen & (bram_waddr[7:0] == 8'he);
assign cmd_val_out = bram_wen & (bram_waddr[7:0] == 8'hf);
assign sh_port = bram_wen & (bram_waddr[7:0] == 8'h13);
assign sh_dma_cnt_val = bram_wen & (bram_waddr[7:0] == 8'h14);
assign sh_notif_val = bram_wen & (bram_waddr[7:0] == 8'h15);
assign sh_data = wdata;
assign sh_feature = wdata;
assign sh_lba_lo = wdata;
assign sh_lba_hi = wdata;
assign sh_count = wdata;
assign sh_command = wdata;
assign sh_dev = wdata;
assign sh_control = wdata;
assign sh_dma_id_lo = wdata;
assign sh_dma_id_hi = wdata;
assign sh_buf_off = wdata;
assign sh_tran_cnt = wdata;
assign sh_autoact = wdata;
assign sh_inter = wdata;
assign sh_dir = wdata;
assign sh_port = wdata;
assign sh_notif = wdata;
assign sh_dma_cnt = wdata;
assign cmd_out = wdata;
reg [7:0] bram_raddr_r;
assign sh_data_strobe = bram_ren & bram_raddr[7:0] == 8'h00;
// read from registers. Interface's protocol assumes returning data with a delay
reg [31:0] bram_rdata_r;
always @ (posedge ACLK) begin
bram_raddr_r <= bram_ren ? bram_raddr[7:0] : bram_raddr_r;
bram_rdata_r <= ~bram_regen ? bram_rdata_r :
bram_raddr_r == 8'hf0 ? reg00 :
bram_raddr_r == 8'hf1 ? reg04 :
bram_raddr_r == 8'hf2 ? reg08 :
bram_raddr_r == 8'hf3 ? reg0c :
bram_raddr_r == 8'hf4 ? reg10 :
bram_raddr_r == 8'hf5 ? reg14 :
bram_raddr_r == 8'h00 ? sh_data_in :
bram_raddr_r == 8'h01 ? sh_feature_in :
bram_raddr_r == 8'h02 ? sh_lba_in[23:0] :
bram_raddr_r == 8'h03 ? sh_lba_in[47:24] :
bram_raddr_r == 8'h04 ? sh_count_in :
bram_raddr_r == 8'h05 ? sh_command_in :
bram_raddr_r == 8'h06 ? sh_dev_in :
bram_raddr_r == 8'h07 ? sh_control_in :
bram_raddr_r == 8'h08 ? sh_dma_id_in[31:0] :
bram_raddr_r == 8'h09 ? sh_dma_id_in[63:32] :
bram_raddr_r == 8'h0a ? sh_dma_off_in :
bram_raddr_r == 8'h0b ? sh_tran_cnt_in : // Transfer Count
bram_raddr_r == 8'h0c ? sh_autoact_in :
bram_raddr_r == 8'h0d ? sh_inter_in :
bram_raddr_r == 8'h0e ? sh_dir_in :
bram_raddr_r == 8'h0f ? cmd_in :
bram_raddr_r == 8'h10 ? sh_err_in :
bram_raddr_r == 8'h11 ? sh_status_in :
bram_raddr_r == 8'h12 ? sh_estatus_in : // E_Status
bram_raddr_r == 8'h13 ? sh_port_in :
bram_raddr_r == 8'h14 ? sh_dma_cnt_in :
bram_raddr_r == 8'h15 ? sh_notif_in :
32'hd34db33f;
end
assign bram_rdata = bram_rdata_r;
/*
// for testing purposes the 'memory' is a set of registers for now
// later on will try to use them as an application level registers
genvar ii;
generate
for (ii = 0; ii < REGISTERS_CNT; ii = ii + 1)
begin: write_to_mem
always @ (posedge ACLK)
begin
mem[32*ii + 31-:8] <= bram_wen & (bram_waddr[3:0] == ii) ? bram_wdata[31-:8] & {8{bram_wstb[3]}}: mem[32*ii + 31-:8];
mem[32*ii + 23-:8] <= bram_wen & (bram_waddr[3:0] == ii) ? bram_wdata[23-:8] & {8{bram_wstb[2]}}: mem[32*ii + 23-:8];
mem[32*ii + 15-:8] <= bram_wen & (bram_waddr[3:0] == ii) ? bram_wdata[15-:8] & {8{bram_wstb[1]}}: mem[32*ii + 15-:8];
mem[32*ii + 7-:8] <= bram_wen & (bram_waddr[3:0] == ii) ? bram_wdata[ 7-:8] & {8{bram_wstb[0]}}: mem[32*ii + 7-:8];
end
end
endgenerate
// read from memory. Interface's protocol assumes returning data with a delay
reg [3:0] bram_raddr_r;
reg [31:0] bram_rdata_r;
always @ (posedge ACLK) begin
bram_raddr_r <= bram_ren ? bram_raddr[3:0] : bram_raddr_r;
bram_rdata_r <= bram_regen ? mem[32*bram_raddr_r + 31-:32] : bram_rdata_r;
end
assign bram_rdata = bram_rdata_r;
*/
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/dma/sata_top.v 0000664 0000000 0000000 00000065524 12572445207 0022577 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: sata_top
* Date: 2015-07-11
* Author: Alexey
* Description: sata for z7nq top-level module
*
* Copyright (c) 2015 Elphel, Inc.
* sata_top.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sata_top.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`timescale 1ns/1ps
`include "axi_regs.v"
`include "dma_regs.v"
`include "sata_host.v"
`include "dma_adapter.v"
`include "dma_control.v"
`include "membridge.v"
/*
* Takes commands from axi iface as a slave, transfers data with another axi iface as a master
*/
module sata_top(
output wire sclk,
output wire sata_rst,
input wire extrst,
/*
* Commands interface
*/
input wire ACLK, // AXI PS Master GP1 Clock , input
input wire ARESETN, // AXI PS Master GP1 Reset, output
// AXI PS Master GP1: Read Address
input wire [31:0] ARADDR, // AXI PS Master GP1 ARADDR[31:0], output
input wire ARVALID, // AXI PS Master GP1 ARVALID, output
output wire ARREADY, // AXI PS Master GP1 ARREADY, input
input wire [11:0] ARID, // AXI PS Master GP1 ARID[11:0], output
input wire [1:0] ARLOCK, // AXI PS Master GP1 ARLOCK[1:0], output
input wire [3:0] ARCACHE, // AXI PS Master GP1 ARCACHE[3:0], output
input wire [2:0] ARPROT, // AXI PS Master GP1 ARPROT[2:0], output
input wire [3:0] ARLEN, // AXI PS Master GP1 ARLEN[3:0], output
input wire [1:0] ARSIZE, // AXI PS Master GP1 ARSIZE[1:0], output
input wire [1:0] ARBURST, // AXI PS Master GP1 ARBURST[1:0], output
input wire [3:0] ARQOS, // AXI PS Master GP1 ARQOS[3:0], output
// AXI PS Master GP1: Read Data
output wire [31:0] RDATA, // AXI PS Master GP1 RDATA[31:0], input
output wire RVALID, // AXI PS Master GP1 RVALID, input
input wire RREADY, // AXI PS Master GP1 RREADY, output
output wire [11:0] RID, // AXI PS Master GP1 RID[11:0], input
output wire RLAST, // AXI PS Master GP1 RLAST, input
output wire [1:0] RRESP, // AXI PS Master GP1 RRESP[1:0], input
// AXI PS Master GP1: Write Address
input wire [31:0] AWADDR, // AXI PS Master GP1 AWADDR[31:0], output
input wire AWVALID, // AXI PS Master GP1 AWVALID, output
output wire AWREADY, // AXI PS Master GP1 AWREADY, input
input wire [11:0] AWID, // AXI PS Master GP1 AWID[11:0], output
input wire [1:0] AWLOCK, // AXI PS Master GP1 AWLOCK[1:0], output
input wire [3:0] AWCACHE, // AXI PS Master GP1 AWCACHE[3:0], output
input wire [2:0] AWPROT, // AXI PS Master GP1 AWPROT[2:0], output
input wire [3:0] AWLEN, // AXI PS Master GP1 AWLEN[3:0], outpu:t
input wire [1:0] AWSIZE, // AXI PS Master GP1 AWSIZE[1:0], output
input wire [1:0] AWBURST, // AXI PS Master GP1 AWBURST[1:0], output
input wire [3:0] AWQOS, // AXI PS Master GP1 AWQOS[3:0], output
// AXI PS Master GP1: Write Data
input wire [31:0] WDATA, // AXI PS Master GP1 WDATA[31:0], output
input wire WVALID, // AXI PS Master GP1 WVALID, output
output wire WREADY, // AXI PS Master GP1 WREADY, input
input wire [11:0] WID, // AXI PS Master GP1 WID[11:0], output
input wire WLAST, // AXI PS Master GP1 WLAST, output
input wire [3:0] WSTRB, // AXI PS Master GP1 WSTRB[3:0], output
// AXI PS Master GP1: Write Responce
output wire BVALID, // AXI PS Master GP1 BVALID, input
input wire BREADY, // AXI PS Master GP1 BREADY, output
output wire [11:0] BID, // AXI PS Master GP1 BID[11:0], input
output wire [1:0] BRESP, // AXI PS Master GP1 BRESP[1:0], input
/*
* Data interface
*/
output wire [31:0] afi_awaddr,
output wire afi_awvalid,
input wire afi_awready,
output wire [5:0] afi_awid,
output wire [1:0] afi_awlock,
output wire [3:0] afi_awcache,
output wire [2:0] afi_awprot,
output wire [3:0] afi_awlen,
output wire [2:0] afi_awsize,
output wire [1:0] afi_awburst,
output wire [3:0] afi_awqos,
// write data
output wire [63:0] afi_wdata,
output wire afi_wvalid,
input wire afi_wready,
output wire [5:0] afi_wid,
output wire afi_wlast,
output wire [7:0] afi_wstrb,
// write response
input wire afi_bvalid,
output wire afi_bready,
input wire [5:0] afi_bid,
input wire [1:0] afi_bresp,
// PL extra (non-AXI) signals
input wire [7:0] afi_wcount,
input wire [5:0] afi_wacount,
output wire afi_wrissuecap1en,
// AXI_HP signals - read channel
// read address
output wire [31:0] afi_araddr,
output wire afi_arvalid,
input wire afi_arready,
output wire [5:0] afi_arid,
output wire [1:0] afi_arlock,
output wire [3:0] afi_arcache,
output wire [2:0] afi_arprot,
output wire [3:0] afi_arlen,
output wire [2:0] afi_arsize,
output wire [1:0] afi_arburst,
output wire [3:0] afi_arqos,
// read data
input wire [63:0] afi_rdata,
input wire afi_rvalid,
output wire afi_rready,
input wire [5:0] afi_rid,
input wire afi_rlast,
input wire [1:0] afi_rresp,
// PL extra (non-AXI) signals
input wire [7:0] afi_rcount,
input wire [2:0] afi_racount,
output wire afi_rdissuecap1en,
/*
* PHY
*/
output wire TXN,
output wire TXP,
output wire RXN,
output wire RXP,
input wire EXTCLK_P,
input wire EXTCLK_N
);
//wire sata_rst;
// dma_regs <-> sata host
// tmp to cmd control
wire cmd_val_out;
wire [31:0] cmd_out;
// tmp to shadow registers
wire [31:0] sh_data; // write data
wire sh_data_val; // write strobe
wire sh_data_strobe; // read strobe
wire [15:0] sh_feature;
wire sh_feature_val;
wire [23:0] sh_lba_lo;
wire sh_lba_lo_val;
wire [23:0] sh_lba_hi;
wire sh_lba_hi_val;
wire [15:0] sh_count;
wire sh_count_val;
wire [7:0] sh_command;
wire sh_command_val;
wire [7:0] sh_dev;
wire sh_dev_val;
wire [7:0] sh_control;
wire sh_control_val;
wire [31:0] sh_dma_id_lo;
wire sh_dma_id_lo_val;
wire [31:0] sh_dma_id_hi;
wire sh_dma_id_hi_val;
wire [31:0] sh_buf_off;
wire sh_buf_off_val;
wire [31:0] sh_dma_cnt;
wire sh_dma_cnt_val;
wire [15:0] sh_tran_cnt;
wire sh_tran_cnt_val;
wire sh_autoact;
wire sh_autoact_val;
wire sh_inter;
wire sh_inter_val;
wire [3:0] sh_port;
wire sh_port_val;
wire sh_notif;
wire sh_notif_val;
wire sh_dir;
wire sh_dir_val;
// inputs from sh registers
wire sh_data_val_in;
wire [31:0] sh_data_in;
wire [7:0] sh_control_in;
wire [15:0] sh_feature_in;
wire [47:0] sh_lba_in;
wire [15:0] sh_count_in;
wire [7:0] sh_command_in;
wire [7:0] sh_err_in;
wire [7:0] sh_status_in;
wire [7:0] sh_estatus_in; // E_Status
wire [7:0] sh_dev_in;
wire [3:0] sh_port_in;
wire sh_inter_in;
wire sh_dir_in;
wire [63:0] sh_dma_id_in;
wire [31:0] sh_dma_off_in;
wire [31:0] sh_dma_cnt_in;
wire [15:0] sh_tran_cnt_in; // Transfer Count
wire sh_notif_in;
wire sh_autoact_in;
// inputs from cmd control
wire [31:0] cmd_in;
// axi_regs <-> data regs
wire [31:0] bram_rdata;
wire [31:0] bram_waddr;
wire [31:0] bram_wdata;
wire [31:0] bram_raddr;
wire [3:0] bram_wstb;
wire bram_wen;
wire bram_ren;
wire bram_regen;
// sata logic reset
//wire rst;
// sata clk
//wire sclk;
// dma_regs <-> dma_control
wire [31:7] mem_address;
wire [31:0] lba;
wire [31:0] sector_cnt;
wire dma_type;
wire dma_start;
wire dma_done;
// axi-hp clock
wire hclk;
// dma_control <-> dma_adapter command iface
wire adp_busy;
wire [31:7] adp_addr;
wire adp_type;
wire adp_val;
// dma_control <-> sata_host command iface
wire host_ready_for_cmd;
wire host_new_cmd;
wire [1:0] host_cmd_type;
wire [31:0] host_sector_count;
wire [31:0] host_sector_addr;
// dma_control <-> dma_adapter data iface
wire [63:0] to_data;
wire to_val;
wire to_ack;
wire [63:0] from_data;
wire from_val;
wire from_ack;
// dma_control <-> sata_host data iface
wire [31:0] in_data;
wire in_val;
wire in_busy;
wire [31:0] out_data;
wire out_val;
wire out_busy;
// adapter <-> membridge iface
wire [7:0] cmd_ad;
wire cmd_stb;
wire [7:0] status_ad;
wire status_rq;
wire status_start;
wire frame_start_chn;
wire next_page_chn;
wire cmd_wrmem;
wire page_ready_chn;
wire frame_done_chn;
wire [15:0] line_unfinished_chn1;
wire suspend_chn1;
wire xfer_reset_page_rd;
wire buf_wpage_nxt;
wire buf_wr;
wire [63:0] buf_wdata;
wire xfer_reset_page_wr;
wire buf_rpage_nxt;
wire buf_rd;
wire [63:0] buf_rdata;
// additional adapter <-> membridge wire
wire rdata_done; // = membridge.is_last_in_page & membridge.afi_rready;
//assign rst = ARESETN;
axi_regs axi_regs(
// axi iface
.ACLK (ACLK),
.ARESETN (ARESETN),
.ARADDR (ARADDR),
.ARVALID (ARVALID),
.ARREADY (ARREADY),
.ARID (ARID),
.ARLOCK (ARLOCK),
.ARCACHE (ARCACHE),
.ARPROT (ARPROT),
.ARLEN (ARLEN),
.ARSIZE (ARSIZE),
.ARBURST (ARBURST),
.ARQOS (ARQOS),
.RDATA (RDATA),
.RVALID (RVALID),
.RREADY (RREADY),
.RID (RID),
.RLAST (RLAST),
.RRESP (RRESP),
.AWADDR (AWADDR),
.AWVALID (AWVALID),
.AWREADY (AWREADY),
.AWID (AWID),
.AWLOCK (AWLOCK),
.AWCACHE (AWCACHE),
.AWPROT (AWPROT),
.AWLEN (AWLEN),
.AWSIZE (AWSIZE),
.AWBURST (AWBURST),
.AWQOS (AWQOS),
.WDATA (WDATA),
.WVALID (WVALID),
.WREADY (WREADY),
.WID (WID),
.WLAST (WLAST),
.WSTRB (WSTRB),
.BVALID (BVALID),
.BREADY (BREADY),
.BID (BID),
.BRESP (BRESP),
// registers iface
.bram_rdata (bram_rdata),
.bram_waddr (bram_waddr),
.bram_wdata (bram_wdata),
.bram_raddr (bram_raddr),
.bram_wstb (bram_wstb),
.bram_wen (bram_wen),
.bram_ren (bram_ren),
.bram_regen (bram_regen)
);
/*
* Programmable sata controller registers
*/
dma_regs dma_regs(
.rst (sata_rst),
.ACLK (ACLK),
.sclk (sclk),
// control iface
.mem_address (mem_address),
.lba (lba),
.sector_cnt (sector_cnt),
.dma_type (dma_type),
.dma_start (dma_start),
.dma_done (dma_done),
// axi buffer iface
.bram_rdata (bram_rdata),
.bram_raddr (bram_raddr),
.bram_waddr (bram_waddr),
.bram_wdata (bram_wdata),
.bram_wstb (bram_wstb),
.bram_wen (bram_wen),
.bram_ren (bram_ren),
.bram_regen (bram_regen),
// direct connections to the host
// tmp to cmd control
.cmd_val_out (cmd_val_out),
.cmd_out (cmd_out),
// tmp to shadow registers
.sh_data (sh_data), // write data
.sh_data_val (sh_data_val), // write strobe
.sh_data_strobe (sh_data_strobe), // read strobe
.sh_feature (sh_feature),
.sh_feature_val (sh_feature_val),
.sh_lba_lo (sh_lba_lo),
.sh_lba_lo_val (sh_lba_lo_val),
.sh_lba_hi (sh_lba_hi),
.sh_lba_hi_val (sh_lba_hi_val),
.sh_count (sh_count),
.sh_count_val (sh_count_val),
.sh_command (sh_command),
.sh_command_val (sh_command_val),
.sh_dev (sh_dev),
.sh_dev_val (sh_dev_val),
.sh_control (sh_control),
.sh_control_val (sh_control_val),
.sh_dma_id_lo (sh_dma_id_lo),
.sh_dma_id_lo_val (sh_dma_id_lo_val),
.sh_dma_id_hi (sh_dma_id_hi),
.sh_dma_id_hi_val (sh_dma_id_hi_val),
.sh_buf_off (sh_buf_off),
.sh_buf_off_val (sh_buf_off_val),
.sh_dma_cnt (sh_dma_cnt),
.sh_dma_cnt_val (sh_dma_cnt_val),
.sh_tran_cnt (sh_tran_cnt),
.sh_tran_cnt_val (sh_tran_cnt_val),
.sh_autoact (sh_autoact),
.sh_autoact_val (sh_autoact_val),
.sh_inter (sh_inter),
.sh_inter_val (sh_inter_val),
.sh_port (sh_port),
.sh_port_val (sh_port_val),
.sh_notif (sh_notif),
.sh_notif_val (sh_notif_val),
.sh_dir (sh_dir),
.sh_dir_val (sh_dir_val),
// inputs from sh registers
.sh_data_val_in (sh_data_val_in),
.sh_data_in (sh_data_in),
.sh_control_in (sh_control_in),
.sh_feature_in (sh_feature_in),
.sh_lba_in (sh_lba_in),
.sh_count_in (sh_count_in),
.sh_command_in (sh_command_in),
.sh_err_in (sh_err_in),
.sh_status_in (sh_status_in),
.sh_estatus_in (sh_estatus_in), // E_Status
.sh_dev_in (sh_dev_in),
.sh_port_in (sh_port_in),
.sh_inter_in (sh_inter_in),
.sh_dir_in (sh_dir_in),
.sh_dma_id_in (sh_dma_id_in),
.sh_dma_off_in (sh_dma_off_in),
.sh_dma_cnt_in (sh_dma_cnt_in),
.sh_tran_cnt_in (sh_tran_cnt_in), // Transfer Count
.sh_notif_in (sh_notif_in),
.sh_autoact_in (sh_autoact_in),
// inputs from cmd control
.cmd_in (cmd_in)
);
dma_control dma_control(
.sclk (sclk),
.hclk (hclk),
.rst (sata_rst),
// registers iface
.mem_address (mem_address),
.lba (lba),
.sector_cnt (sector_cnt),
.dma_type (dma_type),
.dma_start (dma_start),
.dma_done (dma_done),
// adapter command iface
.adp_busy (adp_busy),
.adp_addr (adp_addr),
.adp_type (adp_type),
.adp_val (adp_val),
// sata host command iface
.host_ready_for_cmd (host_ready_for_cmd),
.host_new_cmd (host_new_cmd),
.host_cmd_type (host_cmd_type),
.host_sector_count (host_sector_count),
.host_sector_addr (host_sector_addr),
// adapter data iface
// to main memory
.to_data (to_data),
.to_val (to_val),
.to_ack (to_ack),
// from main memory
.from_data (from_data),
.from_val (from_val),
.from_ack (from_ack),
// sata host iface
// data from sata host
.in_data (in_data),
.in_val (in_val),
.in_busy (in_busy),
// data to sata host
.out_data (out_data),
.out_val (out_val),
.out_busy (out_busy)
);
//assign rdata_done = membridge.is_last_in_page & membridge.afi_rready;
dma_adapter dma_adapter(
.clk (hclk),
.rst (sata_rst),
// command iface
.cmd_type (adp_type),
.cmd_val (adp_val),
.cmd_addr (adp_addr),
.cmd_busy (adp_busy),
// data iface
.wr_data_in (to_data),
.wr_val_in (to_val),
.wr_ack_out (to_ack),
.rd_data_out (from_data),
.rd_val_out (from_val),
.rd_ack_in (from_ack),
// membridge iface
.cmd_ad (cmd_ad),
.cmd_stb (cmd_stb),
.status_ad (status_ad),
.status_rq (status_rq),
.status_start (status_start),
.frame_start_chn (frame_start_chn),
.next_page_chn (next_page_chn),
.cmd_wrmem (cmd_wrmem),
.page_ready_chn (page_ready_chn),
.frame_done_chn (frame_done_chn),
.line_unfinished_chn1 (line_unfinished_chn1),
.suspend_chn1 (suspend_chn1),
.xfer_reset_page_rd (xfer_reset_page_rd),
.buf_wpage_nxt (buf_wpage_nxt),
.buf_wr (buf_wr),
.buf_wdata (buf_wdata),
.xfer_reset_page_wr (xfer_reset_page_wr),
.buf_rpage_nxt (buf_rpage_nxt),
.buf_rd (buf_rd),
.buf_rdata (buf_rdata),
.rdata_done (rdata_done)
);
membridge /*#(
V .MEMBRIDGE_ADDR (),
.MEMBRIDGE_MASK (),
.MEMBRIDGE_CTRL (),
.MEMBRIDGE_STATUS_CNTRL (),
.MEMBRIDGE_LO_ADDR64 (),
.MEMBRIDGE_SIZE64 (),
.MEMBRIDGE_START64 (),
.MEMBRIDGE_LEN64 (),
.MEMBRIDGE_WIDTH64 (),
.MEMBRIDGE_MODE (),
.MEMBRIDGE_STATUS_REG (),
.FRAME_HEIGHT_BITS (),
.FRAME_WIDTH_BITS ()
)*/ membridge(
.mrst (sata_rst), // input
.hrst (ARESETN), // input
.mclk (hclk), // input
.hclk (hclk), // input
.cmd_ad (cmd_ad),
.cmd_stb (cmd_stb),
.status_ad (status_ad),
.status_rq (status_rq),
.status_start (status_start),
.frame_start_chn (frame_start_chn),
.next_page_chn (next_page_chn),
.cmd_wrmem (cmd_wrmem),
.page_ready_chn (page_ready_chn),
.frame_done_chn (frame_done_chn),
.line_unfinished_chn1 (line_unfinished_chn1),
.suspend_chn1 (suspend_chn1),
.xfer_reset_page_rd (xfer_reset_page_rd),
.buf_wpage_nxt (buf_wpage_nxt),
.buf_wr (buf_wr),
.buf_wdata (buf_wdata),
.xfer_reset_page_wr (xfer_reset_page_wr),
.buf_rpage_nxt (buf_rpage_nxt),
.buf_rd (buf_rd),
.buf_rdata (buf_rdata),
.afi_awaddr (afi_awaddr), // output[31:0]
.afi_awvalid (afi_awvalid), // output
.afi_awready (afi_awready), // input
.afi_awid (afi_awid), // output[5:0]
.afi_awlock (afi_awlock), // output[1:0]
.afi_awcache (afi_awcache), // output[3:0]
.afi_awprot (afi_awprot), // output[2:0]
.afi_awlen (afi_awlen), // output[3:0]
.afi_awsize (afi_awsize), // output[2:0]
.afi_awburst (afi_awburst), // output[1:0]
.afi_awqos (afi_awqos), // output[3:0]
.afi_wdata (afi_wdata), // output[63:0]
.afi_wvalid (afi_wvalid), // output
.afi_wready (afi_wready), // input
.afi_wid (afi_wid), // output[5:0]
.afi_wlast (afi_wlast), // output
.afi_wstrb (afi_wstrb), // output[7:0]
.afi_bvalid (afi_bvalid), // input
.afi_bready (afi_bready), // output
.afi_bid (afi_bid), // input[5:0]
.afi_bresp (afi_bresp), // input[1:0]
.afi_wcount (afi_wcount), // input[7:0]
.afi_wacount (afi_wacount), // input[5:0]
.afi_wrissuecap1en (afi_wrissuecap1en), // output
.afi_araddr (afi_araddr), // output[31:0]
.afi_arvalid (afi_arvalid), // output
.afi_arready (afi_arready), // input
.afi_arid (afi_arid), // output[5:0]
.afi_arlock (afi_arlock), // output[1:0]
.afi_arcache (afi_arcache), // output[3:0]
.afi_arprot (afi_arprot), // output[2:0]
.afi_arlen (afi_arlen), // output[3:0]
.afi_arsize (afi_arsize), // output[2:0]
.afi_arburst (afi_arburst), // output[1:0]
.afi_arqos (afi_arqos), // output[3:0]
.afi_rdata (afi_rdata), // input[63:0]
.afi_rvalid (afi_rvalid), // input
.afi_rready (afi_rready), // output
.afi_rid (afi_rid), // input[5:0]
.afi_rlast (afi_rlast), // input
.afi_rresp (afi_rresp), // input[2:0]
.afi_rcount (afi_rcount), // input[7:0]
.afi_racount (afi_racount), // input[2:0]
.afi_rdissuecap1en (afi_rdissuecap1en)/*, // output
.rdata_done (rdata_done)*/
);
assign rdata_done = 1'b0;
sata_host sata_host(
.extrst (extrst),
// sata rst
.rst (sata_rst),
// sata clk
.clk (sclk),
// temporary
.al_cmd_in (cmd_out), // == {cmd_type, cmd_port, cmd_val, cmd_done_bad, cmd_done_good; cmd_busy}
.al_cmd_val_in (cmd_val_out),
.al_cmd_out (cmd_in), // same
// tmp inputs directly from registers for each and every shadow register and control bit
// from al
.al_sh_data_in (sh_data), // write data
.al_sh_data_val_in (sh_data_val), // write strobe
.al_sh_data_strobe_in (sh_data_strobe), // read strobe
.al_sh_feature_in (sh_feature),
.al_sh_feature_val_in (sh_feature_val),
.al_sh_lba_lo_in (sh_lba_lo),
.al_sh_lba_lo_val_in (sh_lba_lo_val),
.al_sh_lba_hi_in (sh_lba_hi),
.al_sh_lba_hi_val_in (sh_lba_hi_val),
.al_sh_count_in (sh_count),
.al_sh_count_val_in (sh_count_val),
.al_sh_command_in (sh_command),
.al_sh_command_val_in (sh_command_val),
.al_sh_dev_in (sh_dev),
.al_sh_dev_val_in (sh_dev_val),
.al_sh_control_in (sh_control),
.al_sh_control_val_in (sh_control_val),
.al_sh_dma_id_lo_in (sh_dma_id_lo),
.al_sh_dma_id_lo_val_in (sh_dma_id_lo_val),
.al_sh_dma_id_hi_in (sh_dma_id_hi),
.al_sh_dma_id_hi_val_in (sh_dma_id_hi_val),
.al_sh_buf_off_in (sh_buf_off),
.al_sh_buf_off_val_in (sh_buf_off_val),
.al_sh_tran_cnt_in (sh_tran_cnt),
.al_sh_tran_cnt_val_in (sh_tran_cnt_val),
.al_sh_autoact_in (sh_autoact),
.al_sh_autoact_val_in (sh_autoact_val),
.al_sh_inter_in (sh_inter),
.al_sh_inter_val_in (sh_inter_val),
.al_sh_dir_in (sh_dir),
.al_sh_dir_val_in (sh_dir_val),
.al_sh_dma_cnt_in (sh_dma_cnt),
.al_sh_dma_cnt_val_in (sh_dma_cnt_val),
.al_sh_notif_in (sh_notif),
.al_sh_notif_val_in (sh_notif_val),
.al_sh_port_in (sh_port),
.al_sh_port_val_in (sh_port_val),
// outputs from shadow registers
.sh_data_val_out (sh_data_val_in),
.sh_data_out (sh_data_in),
.sh_control_out (sh_control_in),
.sh_feature_out (sh_feature_in),
.sh_lba_out (sh_lba_in),
.sh_count_out (sh_count_in),
.sh_command_out (sh_command_in),
.sh_err_out (sh_err_in),
.sh_status_out (sh_status_in),
.sh_estatus_out (sh_estatus_in), // E_Status
.sh_dev_out (sh_dev_in),
.sh_port_out (sh_port_in),
.sh_inter_out (sh_inter_in),
.sh_dir_out (sh_dir_in),
.sh_dma_id_out (sh_dma_id_in),
.sh_dma_off_out (sh_dma_off_in),
.sh_dma_cnt_out (sh_dma_cnt_in),
.sh_tran_cnt_out (sh_tran_cnt_in), // Transfer Count
.sh_notif_out (sh_notif_in),
.sh_autoact_out (sh_autoact_in),
// top-level ifaces
// ref clk from an external source, shall be connected to pads
.extclk_p (EXTCLK_P),
.extclk_n (EXTCLK_N),
// sata physical link data pins
.txp_out (TXP),
.txn_out (TXN),
.rxp_in (RXP),
.rxn_in (RXN)
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/dma/send_dma.v 0000664 0000000 0000000 00000037315 12572445207 0022534 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: send_dma
* Date: 2015-07-11
* Author: Alexey
* Description: temporary interconnect to membridge testing purposes only
*
* Copyright (c) 2015 Elphel, Inc.
* send_dma.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* send_dma.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/*
* The module is temporary
* It could make transactions from DMA data buffer to membridge and vice versa.
* Processes 1 transaction of 16 x 64bit-words at a time.
* Waits until 1 read or 1 write is completely done.
* After that it deasserts busy and is ready to process a new transaction.
*
* The whole purpose of a module as a system block is to be a buffer between
* a big dma data storage and axi interface. So it shall recieve data and control
* for 1 burst and pass it to axi.
*/
/*
* For debug only:
* DMA write:
* 0x0c: |mem[:] => use dbg registers as a source of dma data
* 0x10: addr of the buffer
* 0x14: size
* 0x18: burst len
* 0x1c: start dma
* 0x20-0x3c - data
*/
module send_dma #(
parameter REGISTERS_CNT = 20
)
(
input wire clk,
input wire rst,
// dbg iface
input wire [32*REGISTERS_CNT - 1:0] mem,
input wire dbg_mode,
output wire clrstart,
// cmd iface
input wire cmd_type, // 1 = wr, 0 = rd
input wire cmd_val, // issue a cmd
input wire [31:7] cmd_addr, // [2:0] - 64-bit (8-bytes) word offset, [6:3] - 16-words transfer offset
output wire cmd_busy, // no-pipelined cmd execution, 1 cmd at a time
// data iface
input wire [63:0] wr_data_in,
output wire wr_val_out,
output wire [63:0] rd_data_out,
input wire rd_val_in,
// membridge iface
output wire [7:0] cmd_ad,
output wire cmd_stb,
input wire [7:0] status_ad,
input wire status_rq,
output wire status_start,
input wire frame_start_chn,
input wire next_page_chn,
output wire cmd_wrmem,
output wire page_ready_chn,
output wire frame_done_chn,
output wire [15:0] line_unfinished_chn1,
input wire suspend_chn1,
output wire xfer_reset_page_rd,
output wire buf_wpage_nxt,
output wire buf_wr,
output wire [63:0] buf_wdata,
output wire xfer_reset_page_wr,
output wire buf_rpage_nxt,
output wire buf_rd,
input wire [63:0] buf_rdata,
// additinal wire to indicate if membridge recieved a packet
input wire rdata_done // = membridge.is_last_in_page & membridge.afi_rready;
);
// cmd handling
// if not busy and got cmd with val => cmd recieved, assert busy, start a respective algorithm
wire wr_start;
wire rd_start;
reg wr_done;
reg rd_done;
reg cmd_type_r;
reg cmd_addr_r;
reg cmd_val_r;
reg cmd_busy_r;
wire set_busy;
wire clr_busy;
assign set_busy = ~cmd_busy_r & cmd_val;
assign clr_busy = cmd_busy_r & (wr_done | rd_done)
always @ (posedge clk)
begin
cmd_type_r <= rst ? 1'b0 :
cmd_addr_r <= rst ? 1'b0 :
cmd_val_r <= rst ? 1'b0 :
cmd_busy_r <= rst ? 1'b0 : ~cmd_busy_r & cmd_val_r
end
/*
* Read/write state machine
* For better readability the state machine is splitted to two pieces:
* the first one is responsible only for the CMD WRITE case handling,
* the second one, respectively, for CMD READ
*
* Each fsm starts a membridge fsm, which, if being 1st time launched, sets up
* membridge's registers, or, if have been launched before, just programs read/write
* address.
*
* Current implementation is extremely slow, but simple and reliable
* After all other parts are implemented and this place occurs to be a bottleneck
* then replace it (and may be membridge too) with something more ... pipelined
*/
reg [1:0] rdwr_state;
// Get data from buffer
localparam READ_IDLE = 0;
localparam READ_ON = 2;
localparam READ_DATA = 3;
reg rd_reset_page;
reg rd_next_page;
reg rd_data
always @ (posedge clk)
if (rst)
begin
rd_state <= READ_IDLE;
rd_done <=
end
else
case (rst)
READ_IDLE:
begin
end
READ_ON:
begin
end
// Put data into buffer
localparam WRITE_IDLE = 0;
localparam WRITE_ON = 1;
reg wr_en;
reg wr_reset_page;
reg wr_next_page;
reg [63:0] wr_data;
reg [6:0] wr_page_offset;
reg wr_page_ready;
reg wr_val;
wire [31:0] dw0 = mem[32*9-1:32*8];
wire [31:0] dw1 = mem[32*10-1:32*9];
wire [31:0] dw2 = mem[32*11-1:32*10];
wire [31:0] dw3 = mem[32*12-1:32*11];
wire [6:0] wr_cnt_to_push;
wire wr_stop;
assign wr_cnt_to_push = 7'hf;
assign wr_stop = wr_page_offset == wr_cnt_to_push;
assign wr_val_in = wr_val;
assign wr_data_in = wr_data;
// assuming for now we write only pre-defined 16 64-bit words
always @ (posedge clk)
if (rst)
begin
wr_done <= 1'b0;
wr_page_offset <= 7'd0;
wr_val <= 1'b0;
wr_data <= 64'h0;
wr_next_page <= 1'b0;
wr_reset_page <= 1'b0;
wr_en <= 1'b0;
wr_page_ready <= 1'b0;
rdwr_state <= WRITE_IDLE;
end
else
case (wr_state)
WRITE_IDLE:
begin
wr_page_offset <= 7'd0;
wr_done <= 1'b0;
wr_val <= 1'b0;
wr_data <= 64'h0;
wr_next_page <= 1'b0;
wr_reset_page <= wr_start ? 1'b1 : 1'b0;
wr_en <= 1'b0;
wr_page_ready <= 1'b0;
rdwr_state <= wr_start ? WRITE_ON : WRITE_IDLE;
end
WRITE_ON:
begin
wr_done <= wr_stop ? 1'b1 : 1'b0;
wr_page_offset <= wr_page_offset + 1'b1;
wr_val <= 1'b1;
wr_data <= ~dbg_mode ? in_data :
wr_page_offset[1:0] == 2'b00 ? {dw0, 25'h0, wr_page_offset} :
wr_page_offset[1:0] == 2'b01 ? {dw1, 25'h0, wr_page_offset} :
wr_page_offset[1:0] == 2'b10 ? {dw2, 25'h0, wr_page_offset} :
{dw3, 25'h0, wr_page_offset};
wr_next_page <= wr_stop ? 1'b1 : 1'b0;
wr_reset_page <= 1'b0;
wr_en <= 1'b1;
wr_page_ready <= wr_stop ? 1'b1 : 1'b0;
rdwr_state <= wr_stop ? WRITE_IDLE : WRITE_ON;
end
default: // read is executed
begin
wr_done <= 1'b0;
wr_page_offset <= 7'd0;
wr_val <= 1'b0;
wr_data <= 64'h0;
wr_next_page <= 1'b0;
wr_reset_page <= 1'b0;
wr_en <= 1'b0;
wr_page_ready <= 1'b0;
rdwr_state <= rdwr_state;
end
endcase
// temporary assigments
assign status_start = 1'b0; // no need until status is used
assign cmd_wrmem = 1'b0; // for now only writing
assign xfer_reset_page_wr = 1'b0; // for now only writing
assign buf_rpage_nxt = 1'b0; // for now only writing
assign buf_rd = 1'b0; // for now only writing
assign xfer_reset_page_wr = 1'b0;
assign buf_wdata = wr_data;
assign buf_wr = wr_en;
assign buf_wpage_nxt = wr_next_page;
assign xfer_reset_page_rd = wr_reset_page;
assign page_ready_chn = cmd_wrmem ? 1'b0 : wr_page_ready;
assign frame_done_chn = 1'b1;
// compute membridge parameters to corresponding mem register
// dma fsm
// mode = 0
// width = 4
// size = 0x14
// start = 0
// lo_address = 0x10
// ctrl = 0x1c
// len = 0x18
localparam MEMBR_IDLE = 0;
localparam MEMBR_MODE = 1;
localparam MEMBR_WIDTH = 2;
localparam MEMBR_LEN = 3;
localparam MEMBR_START = 4;
localparam MEMBR_SIZE = 5;
localparam MEMBR_LOADDR = 6;
localparam MEMBR_CTRL = 7;
reg [32:0] membr_data;
reg [15:0] membr_addr;
reg membr_start;
reg membr_done;
reg [2:0] membr_state;
reg membr_setup; // indicates the first tick of the state
wire membr_inprocess;
wire dma_start;
assign dma_start = |mem[32*8-1:32*7];
assign clrstart = dma_start & membr_state == MEMBR_IDLE;
//assign wr_start = membr_state == MEMBR_CTRL;
always @ (posedge clk)
if (rst)
begin
membr_data <= 32'h0;
membr_addr <= 16'h0;
membr_start <= 1'b0;
membr_setup <= 1'b0;
membr_state <= MEMBR_IDLE;
end
else
case (membr_state)
MEMBR_IDLE:
begin
membr_data <= 32'h0;
membr_addr <= 16'h200;
membr_start <= dma_start ? 1'b1 : 1'b0;
membr_setup <= dma_start ? 1'b1 : 1'b0;
membr_state <= dma_start ? MEMBR_MODE : MEMBR_IDLE;
end
MEMBR_MODE:
begin
membr_data <= 32'h3;
membr_addr <= 16'h207;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_state <= membr_inprocess | membr_setup ? MEMBR_MODE : MEMBR_WIDTH;
end
MEMBR_WIDTH:
begin
membr_data <= 32'h10;
membr_addr <= 16'h206;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_state <= membr_inprocess | membr_setup ? MEMBR_WIDTH : MEMBR_LEN;
end
MEMBR_LEN:
begin
membr_data <= 32'h10;
membr_addr <= 16'h205;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_state <= membr_inprocess | membr_setup ? MEMBR_LEN : MEMBR_START;
end
MEMBR_START:
begin
membr_data <= 32'h0;
membr_addr <= 16'h204;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_state <= membr_inprocess | membr_setup ? MEMBR_START : MEMBR_SIZE;
end
MEMBR_SIZE:
begin
membr_data <= 32'h10;
membr_addr <= 16'h203;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_state <= membr_inprocess | membr_setup ? MEMBR_SIZE : MEMBR_LOADDR;
end
MEMBR_LOADDR:
begin
membr_data <= mem[32*5-1:32*4];
membr_addr <= 16'h202;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
membr_state <= membr_inprocess | membr_setup ? MEMBR_LOADDR : MEMBR_CTRL;
end
MEMBR_CTRL:
begin
membr_data <= {28'h0000000, 4'b0011};
membr_addr <= 16'h200;
membr_start <= membr_inprocess ? 1'b0 : 1'b1;
membr_setup <= 1'b0;
membr_state <= membr_inprocess | membr_setup ? MEMBR_CTRL : MEMBR_IDLE;
end
default:
begin
membr_data <= 32'h0;
membr_addr <= 16'h0;
membr_start <= 1'b0;
membr_setup <= 1'b0;
membr_state <= MEMBR_IDLE;
end
endcase
// write to memridge registers fsm
localparam STATE_IDLE = 3'h0;
localparam STATE_CMD_0 = 3'h1;
localparam STATE_CMD_1 = 3'h2;
localparam STATE_DATA_0 = 3'h3;
localparam STATE_DATA_1 = 3'h4;
localparam STATE_DATA_2 = 3'h5;
localparam STATE_DATA_3 = 3'h6;
reg [2:0] state;
reg [7:0] out_ad;
reg out_stb;
assign membr_inprocess = state != STATE_IDLE;
assign cmd_ad = out_ad;
assign cmd_stb = out_stb;
always @ (posedge clk)
if (rst)
begin
membr_done <= 1'b0;
state <= STATE_IDLE;
out_ad <= 8'h0;
out_stb <= 1'b0;
end
else
case (state)
STATE_IDLE:
begin
membr_done <= 1'b0;
out_ad <= 8'h0;
out_stb <= 1'b0;
state <= membr_setup ? STATE_CMD_0 : STATE_IDLE;
end
STATE_CMD_0:
begin
membr_done <= 1'b0;
out_ad <= membr_addr[7:0];
out_stb <= 1'b1;
state <= STATE_CMD_1;
end
STATE_CMD_1:
begin
membr_done <= 1'b0;
out_ad <= membr_addr[15:8];
out_stb <= 1'b0;
state <= STATE_DATA_0;
end
STATE_DATA_0:
begin
membr_done <= 1'b0;
out_ad <= membr_data[7:0];
out_stb <= 1'b0;
state <= STATE_DATA_1;
end
STATE_DATA_1:
begin
membr_done <= 1'b0;
out_ad <= membr_data[15:8];
out_stb <= 1'b0;
state <= STATE_DATA_2;
end
STATE_DATA_2:
begin
membr_done <= 1'b0;
out_ad <= membr_data[23:16];
out_stb <= 1'b0;
state <= STATE_DATA_3;
end
STATE_DATA_3:
begin
membr_done <= 1'b0;
out_ad <= membr_data[31:24];
out_stb <= 1'b0;
state <= STATE_IDLE;
end
default:
begin
membr_done <= 1'b1;
out_ad <= 8'hff;
out_stb <= 1'b0;
state <= STATE_IDLE;
end
endcase
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/dma/top.v 0000664 0000000 0000000 00000163060 12572445207 0021561 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: top
* Date: 2015-07-11
* Author: Alexey
* Description: top-level module, instantiates PS7 + sata host controller
*
* Copyright (c) 2015 Elphel, Inc.
* top.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* top.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/*
* all signals' and modules' names and interconnections are taken from x393.v
* to make the final integration easier - just to make an instance of
* what is called now 'axi_regs' and connect it
*/
`include "system_defines.vh"
`include "sata_top.v"
module top #(
`include "includes/x393_parameters.vh"
)
(
// sata serial data iface
input wire RXN,
input wire RXP,
output wire TXN,
output wire TXP,
// sata clocking iface
input wire EXTCLK_P,
input wire EXTCLK_N
);
parameter REGISTERS_CNT = 20;
wire [32*REGISTERS_CNT - 1:0] outmem;
wire clrstart;
wire sclk;
wire sata_rst;
wire extrst;
wire [3:0] fclk;
wire [3:0] frst;
wire axi_aclk;
wire axi_rst;
wire hclk;
wire comb_rst;
wire [31:0] ARADDR;
wire ARVALID;
wire ARREADY;
wire [11:0] ARID;
wire [1:0] ARLOCK;
wire [3:0] ARCACHE;
wire [2:0] ARPROT;
wire [3:0] ARLEN;
wire [1:0] ARSIZE;
wire [1:0] ARBURST;
wire [3:0] ARQOS;
wire [31:0] RDATA;
wire RVALID;
wire RREADY;
wire [11:0] RID;
wire RLAST;
wire [1:0] RRESP;
wire [31:0] AWADDR;
wire AWVALID;
wire AWREADY;
wire [11:0] AWID;
wire [1:0] AWLOCK;
wire [3:0] AWCACHE;
wire [2:0] AWPROT;
wire [3:0] AWLEN;
wire [1:0] AWSIZE;
wire [1:0] AWBURST;
wire [3:0] AWQOS;
wire [31:0] WDATA;
wire WVALID;
wire WREADY;
wire [11:0] WID;
wire WLAST;
wire [3:0] WSTRB;
wire BVALID;
wire BREADY;
wire [11:0] BID;
wire [1:0] BRESP;
reg axi_rst_pre;
// membridge
wire [31:0] afi0_awaddr; // output[31:0]
wire afi0_awvalid; // output
wire afi0_awready; // input
wire [ 5:0] afi0_awid; // output[5:0]
wire [ 1:0] afi0_awlock; // output[1:0]
wire [ 3:0] afi0_awcache; // output[3:0]
wire [ 2:0] afi0_awprot; // output[2:0]
wire [ 3:0] afi0_awlen; // output[3:0]
wire [ 2:0] afi0_awsize; // output[2:0]
wire [ 1:0] afi0_awburst; // output[1:0]
wire [ 3:0] afi0_awqos; // output[3:0]
wire [63:0] afi0_wdata; // output[63:0]
wire afi0_wvalid; // output
wire afi0_wready; // input
wire [ 5:0] afi0_wid; // output[5:0]
wire afi0_wlast; // output
wire [ 7:0] afi0_wstrb; // output[7:0]
wire afi0_bvalid; // input
wire afi0_bready; // output
wire [ 5:0] afi0_bid; // input[5:0]
wire [ 1:0] afi0_bresp; // input[1:0]
wire [ 7:0] afi0_wcount; // input[7:0]
wire [ 5:0] afi0_wacount; // input[5:0]
wire afi0_wrissuecap1en; // output
wire [31:0] afi0_araddr; // output[31:0]
wire afi0_arvalid; // output
wire afi0_arready; // input
wire [ 5:0] afi0_arid; // output[5:0]
wire [ 1:0] afi0_arlock; // output[1:0]
wire [ 3:0] afi0_arcache; // output[3:0]
wire [ 2:0] afi0_arprot; // output[2:0]
wire [ 3:0] afi0_arlen; // output[3:0]
wire [ 2:0] afi0_arsize; // output[2:0]
wire [ 1:0] afi0_arburst; // output[1:0]
wire [ 3:0] afi0_arqos; // output[3:0]
wire [63:0] afi0_rdata; // input[63:0]
wire afi0_rvalid; // input
wire afi0_rready; // output
wire [ 5:0] afi0_rid; // input[5:0]
wire afi0_rlast; // input
wire [ 1:0] afi0_rresp; // input[2:0]
wire [ 7:0] afi0_rcount; // input[7:0]
wire [ 2:0] afi0_racount; // input[2:0]
wire afi0_rdissuecap1en; // output
// send_dma
wire [7:0] cmd_ad;
wire cmd_stb;
wire [7:0] status_ad;
wire status_rq;
wire status_start;
wire frame_start_chn;
wire next_page_chn;
wire cmd_wrmem;
wire page_ready_chn;
wire frame_done_chn;
wire [15:0] line_unfinished_chn1;
wire suspend_chn1;
wire xfer_reset_page_rd;
wire buf_wpage_nxt;
wire buf_wr;
wire [63:0] buf_wdata;
wire xfer_reset_page_wr;
wire buf_rpage_nxt;
wire buf_rd;
wire [63:0] buf_rdata;
assign comb_rst=~frst[0] | frst[1];
always @(posedge comb_rst or posedge axi_aclk0) begin
if (comb_rst) axi_rst_pre <= 1'b1;
else axi_rst_pre <= 1'b0;
end
BUFG bufg_axi_aclk_i (.O(axi_aclk),.I(/*fclk[0]*/ sclk));
BUFG bufg_axi_aclk0_i (.O(axi_aclk0),.I(fclk[0]));
BUFG bufg_axi_rst_i (.O(axi_rst),.I(axi_rst_pre));
BUFG bufg_extrst_i (.O(extrst),.I(axi_rst_pre));
axi_hp_clk #(
.CLKIN_PERIOD(6.666),
.CLKFBOUT_MULT_AXIHP(6),
.CLKFBOUT_DIV_AXIHP(6)
) axi_hp_clk_i (
.rst (axi_rst), // input
.clk_in (axi_aclk0), // input
.clk_axihp (hclk), // output
.locked_axihp () // output // not controlled?
);
sata_top sata_top(
.sclk (sclk),
.sata_rst (sata_rst),
.extrst (extrst),
.ACLK (axi_aclk),
.ARESETN (axi_rst | sata_rst),
// AXI PS Master GP1: Read Address
.ARADDR (ARADDR),
.ARVALID (ARVALID),
.ARREADY (ARREADY),
.ARID (ARID),
.ARLOCK (ARLOCK),
.ARCACHE (ARCACHE),
.ARPROT (ARPROT),
.ARLEN (ARLEN),
.ARSIZE (ARSIZE),
.ARBURST (ARBURST),
.ARQOS (ARQOS),
// AXI PS Master GP1: Read Data
.RDATA (RDATA),
.RVALID (RVALID),
.RREADY (RREADY),
.RID (RID),
.RLAST (RLAST),
.RRESP (RRESP),
// AXI PS Master GP1: Write Address
.AWADDR (AWADDR),
.AWVALID (AWVALID),
.AWREADY (AWREADY),
.AWID (AWID),
.AWLOCK (AWLOCK),
.AWCACHE (AWCACHE),
.AWPROT (AWPROT),
.AWLEN (AWLEN),
.AWSIZE (AWSIZE),
.AWBURST (AWBURST),
.AWQOS (AWQOS),
// AXI PS Master GP1: Write Data
.WDATA (WDATA),
.WVALID (WVALID),
.WREADY (WREADY),
.WID (WID),
.WLAST (WLAST),
.WSTRB (WSTRB),
// AXI PS Master GP1: Write Responce
.BVALID (BVALID),
.BREADY (BREADY),
.BID (BID),
.BRESP (BRESP),
/*
* Data interface
*/
.afi_awaddr (afi0_awaddr),
.afi_awvalid (afi0_awvalid),
.afi_awready (afi0_awready),
.afi_awid (afi0_awid),
.afi_awlock (afi0_awlock),
.afi_awcache (afi0_awcache),
.afi_awprot (afi0_awprot),
.afi_awlen (afi0_awlen),
.afi_awsize (afi0_awsize),
.afi_awburst (afi0_awburst),
.afi_awqos (afi0_awqos),
// write data
.afi_wdata (afi0_wdata),
.afi_wvalid (afi0_wvalid),
.afi_wready (afi0_wready),
.afi_wid (afi0_wid),
.afi_wlast (afi0_wlast),
.afi_wstrb (afi0_wstrb),
// write response
.afi_bvalid (afi0_bvalid),
.afi_bready (afi0_bready),
.afi_bid (afi0_bid),
.afi_bresp (afi0_bresp),
// PL extra (non-AXI) signal
.afi_wcount (afi0_wcount),
.afi_wacount (afi0_wacount),
.afi_wrissuecap1en (afi0_wrissuecap1en),
// AXI_HP signals - read channel
// read address
.afi_araddr (afi0_araddr),
.afi_arvalid (afi0_arvalid),
.afi_arready (afi0_arready),
.afi_arid (afi0_arid),
.afi_arlock (afi0_arlock),
.afi_arcache (afi0_arcache),
.afi_arprot (afi0_arprot),
.afi_arlen (afi0_arlen),
.afi_arsize (afi0_arsize),
.afi_arburst (afi0_arburst),
.afi_arqos (afi0_arqos),
// read data
.afi_rdata (afi0_rdata),
.afi_rvalid (afi0_rvalid),
.afi_rready (afi0_rready),
.afi_rid (afi0_rid),
.afi_rlast (afi0_rlast),
.afi_rresp (afi0_rresp),
// PL extra (non-AXI) signal
.afi_rcount (afi0_rcount),
.afi_racount (afi0_racount),
.afi_rdissuecap1en (afi0_rdissuecap1en),
/*
* PHY
*/
.TXN (TXN),
.TXP (TXP),
.RXN (RXN),
.RXP (RXP),
.EXTCLK_P (EXTCLK_P),
.EXTCLK_N (EXTCLK_N)
);
PS7 ps7_i (
// EMIO interface
// CAN interface
.EMIOCAN0PHYTX(), // CAN 0 TX, output
.EMIOCAN0PHYRX(), // CAN 0 RX, input
.EMIOCAN1PHYTX(), // Can 1 TX, output
.EMIOCAN1PHYRX(), // CAN 1 RX, input
// GMII 0
.EMIOENET0GMIICRS(), // GMII 0 Carrier sense, input
.EMIOENET0GMIICOL(), // GMII 0 Collision detect, input
.EMIOENET0EXTINTIN(), // GMII 0 Controller Interrupt input, input
// GMII 0 TX signals
.EMIOENET0GMIITXCLK(), // GMII 0 TX clock, input
.EMIOENET0GMIITXD(), // GMII 0 Tx Data[7:0], output
.EMIOENET0GMIITXEN(), // GMII 0 Tx En, output
.EMIOENET0GMIITXER(), // GMII 0 Tx Err, output
// GMII 0 TX timestamp signals
.EMIOENET0SOFTX(), // GMII 0 Tx Tx Start-of-Frame, output
.EMIOENET0PTPDELAYREQTX(), // GMII 0 Tx PTP delay req frame detected, output
.EMIOENET0PTPPDELAYREQTX(), // GMII 0 Tx PTP peer delay frame detect, output
.EMIOENET0PTPPDELAYRESPTX(), // GMII 0 Tx PTP pear delay response frame detected, output
.EMIOENET0PTPSYNCFRAMETX(), // GMII 0 Tx PTP sync frame detected, output
// GMII 0 RX signals
.EMIOENET0GMIIRXCLK(), // GMII 0 Rx Clock, input
.EMIOENET0GMIIRXD(), // GMII 0 Rx Data (7:0), input
.EMIOENET0GMIIRXDV(), // GMII 0 Rx Data valid, input
.EMIOENET0GMIIRXER(), // GMII 0 Rx Error, input
// GMII 0 RX timestamp signals
.EMIOENET0SOFRX(), // GMII 0 Rx Start of Frame, output
.EMIOENET0PTPDELAYREQRX(), // GMII 0 Rx PTP delay req frame detected
.EMIOENET0PTPPDELAYREQRX(), // GMII 0 Rx PTP peer delay frame detected, output
.EMIOENET0PTPPDELAYRESPRX(), // GMII 0 Rx PTP peer delay responce frame detected, output
.EMIOENET0PTPSYNCFRAMERX(), // GMII 0 Rx PTP sync frame detected, output
// MDIO 0
.EMIOENET0MDIOMDC(), // MDIO 0 MD clock output, output
.EMIOENET0MDIOO(), // MDIO 0 MD data output, output
.EMIOENET0MDIOTN(), // MDIO 0 MD data 3-state, output
.EMIOENET0MDIOI(), // MDIO 0 MD data input, input
// GMII 1
.EMIOENET1GMIICRS(), // GMII 1 Carrier sense, input
.EMIOENET1GMIICOL(), // GMII 1 Collision detect, input
.EMIOENET1EXTINTIN(), // GMII 1 Controller Interrupt input, input
// GMII 1 TX signals
.EMIOENET1GMIITXCLK(), // GMII 1 TX clock, input
.EMIOENET1GMIITXD(), // GMII 1 Tx Data[7:0], output
.EMIOENET1GMIITXEN(), // GMII 1 Tx En, output
.EMIOENET1GMIITXER(), // GMII 1 Tx Err, output
// GMII 1 TX timestamp signals
.EMIOENET1SOFTX(), // GMII 1 Tx Tx Start-of-Frame, output
.EMIOENET1PTPDELAYREQTX(), // GMII 1 Tx PTP delay req frame detected, output
.EMIOENET1PTPPDELAYREQTX(), // GMII 1 Tx PTP peer delay frame detect, output
.EMIOENET1PTPPDELAYRESPTX(), // GMII 1 Tx PTP pear delay response frame detected, output
.EMIOENET1PTPSYNCFRAMETX(), // GMII 1 Tx PTP sync frame detected, output
// GMII 1 RX signals
.EMIOENET1GMIIRXCLK(), // GMII 1 Rx Clock, input
.EMIOENET1GMIIRXD(), // GMII 1 Rx Data (7:0), input
.EMIOENET1GMIIRXDV(), // GMII 1 Rx Data valid, input
.EMIOENET1GMIIRXER(), // GMII 1 Rx Error, input
// GMII 1 RX timestamp signals
.EMIOENET1SOFRX(), // GMII 1 Rx Start of Frame, output
.EMIOENET1PTPDELAYREQRX(), // GMII 1 Rx PTP delay req frame detected
.EMIOENET1PTPPDELAYREQRX(), // GMII 1 Rx PTP peer delay frame detected, output
.EMIOENET1PTPPDELAYRESPRX(), // GMII 1 Rx PTP peer delay responce frame detected, output
.EMIOENET1PTPSYNCFRAMERX(), // GMII 1 Rx PTP sync frame detected, output
// MDIO 1
.EMIOENET1MDIOMDC(), // MDIO 1 MD clock output, output
.EMIOENET1MDIOO(), // MDIO 1 MD data output, output
.EMIOENET1MDIOTN(), // MDIO 1 MD data 3-state, output
.EMIOENET1MDIOI(), // MDIO 1 MD data input, input
// EMIO GPIO
.EMIOGPIOO(), // EMIO GPIO Data out[63:0], output
.EMIOGPIOI(/*gpio_in[63:0]*/), // EMIO GPIO Data in[63:0], input
.EMIOGPIOTN(), // EMIO GPIO OutputEnable[63:0], output
// EMIO I2C 0
.EMIOI2C0SCLO(), // I2C 0 SCL OUT, output // manual says input
.EMIOI2C0SCLI(), // I2C 0 SCL IN, input // manual says output
.EMIOI2C0SCLTN(), // I2C 0 SCL EN, output // manual says input
.EMIOI2C0SDAO(), // I2C 0 SDA OUT, output // manual says input
.EMIOI2C0SDAI(), // I2C 0 SDA IN, input // manual says output
.EMIOI2C0SDATN(), // I2C 0 SDA EN, output // manual says input
// EMIO I2C 1
.EMIOI2C1SCLO(), // I2C 1 SCL OUT, output // manual says input
.EMIOI2C1SCLI(), // I2C 1 SCL IN, input // manual says output
.EMIOI2C1SCLTN(), // I2C 1 SCL EN, output // manual says input
.EMIOI2C1SDAO(), // I2C 1 SDA OUT, output // manual says input
.EMIOI2C1SDAI(), // I2C 1 SDA IN, input // manual says output
.EMIOI2C1SDATN(), // I2C 1 SDA EN, output // manual says input
// JTAG
.EMIOPJTAGTCK(), // JTAG TCK, input
.EMIOPJTAGTMS(), // JTAG TMS, input
.EMIOPJTAGTDI(), // JTAG TDI, input
.EMIOPJTAGTDO(), // JTAG TDO, output
.EMIOPJTAGTDTN(), // JTAG TDO OE, output
// SDIO 0
.EMIOSDIO0CLKFB(), // SDIO 0 Clock feedback, input
.EMIOSDIO0CLK(), // SDIO 0 Clock, output
.EMIOSDIO0CMDI(), // SDIO 0 Command in, input
.EMIOSDIO0CMDO(), // SDIO 0 Command out, output
.EMIOSDIO0CMDTN(), // SDIO 0 command OE, output
.EMIOSDIO0DATAI(), // SDIO 0 Data in [3:0], input
.EMIOSDIO0DATAO(), // SDIO 0 Data out [3:0], output
.EMIOSDIO0DATATN(), // SDIO 0 Data OE [3:0], output
.EMIOSDIO0CDN(), // SDIO 0 Card detect, input
.EMIOSDIO0WP(), // SDIO 0 Write protect, input
.EMIOSDIO0BUSPOW(), // SDIO 0 Power control, output
.EMIOSDIO0LED(), // SDIO 0 LED control, output
.EMIOSDIO0BUSVOLT(), // SDIO 0 Bus voltage [2:0], output
// SDIO 1
.EMIOSDIO1CLKFB(), // SDIO 1 Clock feedback, input
.EMIOSDIO1CLK(), // SDIO 1 Clock, output
.EMIOSDIO1CMDI(), // SDIO 1 Command in, input
.EMIOSDIO1CMDO(), // SDIO 1 Command out, output
.EMIOSDIO1CMDTN(), // SDIO 1 command OE, output
.EMIOSDIO1DATAI(), // SDIO 1 Data in [3:0], input
.EMIOSDIO1DATAO(), // SDIO 1 Data out [3:0], output
.EMIOSDIO1DATATN(), // SDIO 1 Data OE [3:0], output
.EMIOSDIO1CDN(), // SDIO 1 Card detect, input
.EMIOSDIO1WP(), // SDIO 1 Write protect, input
.EMIOSDIO1BUSPOW(), // SDIO 1 Power control, output
.EMIOSDIO1LED(), // SDIO 1 LED control, output
.EMIOSDIO1BUSVOLT(), // SDIO 1 Bus voltage [2:0], output
// SPI 0
.EMIOSPI0SCLKI(), // SPI 0 CLK in , input
.EMIOSPI0SCLKO(), // SPI 0 CLK out, output
.EMIOSPI0SCLKTN(), // SPI 0 CLK OE, output
.EMIOSPI0SI(), // SPI 0 MOSI in , input
.EMIOSPI0MO(), // SPI 0 MOSI out , output
.EMIOSPI0MOTN(), // SPI 0 MOSI OE, output
.EMIOSPI0MI(), // SPI 0 MISO in, input
.EMIOSPI0SO(), // SPI 0 MISO out, output
.EMIOSPI0STN(), // SPI 0 MISO OE, output
.EMIOSPI0SSIN(), // SPI 0 Slave select 0 in, input
.EMIOSPI0SSON(), // SPI 0 Slave select [2:0] out, output
.EMIOSPI0SSNTN(), // SPI 0 Slave select OE, output
// SPI 1
.EMIOSPI1SCLKI(), // SPI 1 CLK in , input
.EMIOSPI1SCLKO(), // SPI 1 CLK out, output
.EMIOSPI1SCLKTN(), // SPI 1 CLK OE, output
.EMIOSPI1SI(), // SPI 1 MOSI in , input
.EMIOSPI1MO(), // SPI 1 MOSI out , output
.EMIOSPI1MOTN(), // SPI 1 MOSI OE, output
.EMIOSPI1MI(), // SPI 1 MISO in, input
.EMIOSPI1SO(), // SPI 1 MISO out, output
.EMIOSPI1STN(), // SPI 1 MISO OE, output
.EMIOSPI1SSIN(), // SPI 1 Slave select 0 in, input
.EMIOSPI1SSON(), // SPI 1 Slave select [2:0] out, output
.EMIOSPI1SSNTN(), // SPI 1 Slave select OE, output
// TPIU signals (Trace)
.EMIOTRACECTL(), // Trace CTL, output
.EMIOTRACEDATA(), // Trace Data[31:0], output
.EMIOTRACECLK(), // Trace CLK, input
// Timers/counters
.EMIOTTC0CLKI(), // Counter/Timer 0 clock in [2:0], input
.EMIOTTC0WAVEO(), // Counter/Timer 0 wave out[2:0], output
.EMIOTTC1CLKI(), // Counter/Timer 1 clock in [2:0], input
.EMIOTTC1WAVEO(), // Counter/Timer 1 wave out[2:0], output
//UART 0
.EMIOUART0TX(), // UART 0 Transmit, output
.EMIOUART0RX(), // UART 0 Receive, input
.EMIOUART0CTSN(), // UART 0 Clear To Send, input
.EMIOUART0RTSN(), // UART 0 Ready to Send, output
.EMIOUART0DSRN(), // UART 0 Data Set Ready , input
.EMIOUART0DCDN(), // UART 0 Data Carrier Detect, input
.EMIOUART0RIN(), // UART 0 Ring Indicator, input
.EMIOUART0DTRN(), // UART 0 Data Terminal Ready, output
//UART 1
.EMIOUART1TX(), // UART 1 Transmit, output
.EMIOUART1RX(), // UART 1 Receive, input
.EMIOUART1CTSN(), // UART 1 Clear To Send, input
.EMIOUART1RTSN(), // UART 1 Ready to Send, output
.EMIOUART1DSRN(), // UART 1 Data Set Ready , input
.EMIOUART1DCDN(), // UART 1 Data Carrier Detect, input
.EMIOUART1RIN(), // UART 1 Ring Indicator, input
.EMIOUART1DTRN(), // UART 1 Data Terminal Ready, output
// USB 0
.EMIOUSB0PORTINDCTL(), // USB 0 Port Indicator [1:0], output
.EMIOUSB0VBUSPWRFAULT(), // USB 0 Power Fault, input
.EMIOUSB0VBUSPWRSELECT(), // USB 0 Power Select, output
// USB 1
.EMIOUSB1PORTINDCTL(), // USB 1 Port Indicator [1:0], output
.EMIOUSB1VBUSPWRFAULT(), // USB 1 Power Fault, input
.EMIOUSB1VBUSPWRSELECT(), // USB 1 Power Select, output
// Watchdog Timer
.EMIOWDTCLKI(), // Watchdog Timer Clock in, input
.EMIOWDTRSTO(), // Watchdog Timer Reset out, output
// DMAC 0
.DMA0ACLK(), // DMAC 0 Clock, input
.DMA0DRVALID(), // DMAC 0 DMA Request Valid, input
.DMA0DRLAST(), // DMAC 0 DMA Request Last, input
.DMA0DRTYPE(), // DMAC 0 DMA Request Type [1:0] ()single/burst/ackn flush/reserved), input
.DMA0DRREADY(), // DMAC 0 DMA Request Ready, output
.DMA0DAVALID(), // DMAC 0 DMA Acknowledge Valid (DA_TYPE[1:0] valid), output
.DMA0DAREADY(), // DMAC 0 DMA Acknowledge (peripheral can accept DA_TYPE[1:0]), input
.DMA0DATYPE(), // DMAC 0 DMA Ackbowledge TYpe (completed single AXI, completed burst AXI, flush request), output
.DMA0RSTN(), // DMAC 0 RESET output (reserved, do not use), output
// DMAC 1
.DMA1ACLK(), // DMAC 1 Clock, input
.DMA1DRVALID(), // DMAC 1 DMA Request Valid, input
.DMA1DRLAST(), // DMAC 1 DMA Request Last, input
.DMA1DRTYPE(), // DMAC 1 DMA Request Type [1:0] ()single/burst/ackn flush/reserved), input
.DMA1DRREADY(), // DMAC 1 DMA Request Ready, output
.DMA1DAVALID(), // DMAC 1 DMA Acknowledge Valid (DA_TYPE[1:0] valid), output
.DMA1DAREADY(), // DMAC 1 DMA Acknowledge (peripheral can accept DA_TYPE[1:0]), input
.DMA1DATYPE(), // DMAC 1 DMA Ackbowledge TYpe (completed single AXI, completed burst AXI, flush request), output
.DMA1RSTN(), // DMAC 1 RESET output (reserved, do not use), output
// DMAC 2
.DMA2ACLK(), // DMAC 2 Clock, input
.DMA2DRVALID(), // DMAC 2 DMA Request Valid, input
.DMA2DRLAST(), // DMAC 2 DMA Request Last, input
.DMA2DRTYPE(), // DMAC 2 DMA Request Type [1:0] ()single/burst/ackn flush/reserved), input
.DMA2DRREADY(), // DMAC 2 DMA Request Ready, output
.DMA2DAVALID(), // DMAC 2 DMA Acknowledge Valid (DA_TYPE[1:0] valid), output
.DMA2DAREADY(), // DMAC 2 DMA Acknowledge (peripheral can accept DA_TYPE[1:0]), input
.DMA2DATYPE(), // DMAC 2 DMA Ackbowledge TYpe (completed single AXI, completed burst AXI, flush request), output
.DMA2RSTN(), // DMAC 2 RESET output (reserved, do not use), output
// DMAC 3
.DMA3ACLK(), // DMAC 3 Clock, input
.DMA3DRVALID(), // DMAC 3 DMA Request Valid, input
.DMA3DRLAST(), // DMAC 3 DMA Request Last, input
.DMA3DRTYPE(), // DMAC 3 DMA Request Type [1:0] ()single/burst/ackn flush/reserved), input
.DMA3DRREADY(), // DMAC 3 DMA Request Ready, output
.DMA3DAVALID(), // DMAC 3 DMA Acknowledge Valid (DA_TYPE[1:0] valid), output
.DMA3DAREADY(), // DMAC 3 DMA Acknowledge (peripheral can accept DA_TYPE[1:0]), input
.DMA3DATYPE(), // DMAC 3 DMA Ackbowledge TYpe (completed single AXI, completed burst AXI, flush request), output
.DMA3RSTN(), // DMAC 3 RESET output (reserved, do not use), output
// Interrupt signals
.IRQF2P(), // Interrupts, OL to PS [19:0], input
.IRQP2F(), // Interrupts, OL to PS [28:0], output
// Event Signals
.EVENTEVENTI(), // EVENT Wake up one or both CPU from WFE state, input
.EVENTEVENTO(), // EVENT Asserted when one of the COUs executed SEV instruction, output
.EVENTSTANDBYWFE(), // EVENT CPU standby mode [1:0], asserted when CPU is waiting for an event, output
.EVENTSTANDBYWFI(), // EVENT CPU standby mode [1:0], asserted when CPU is waiting for an interrupt, output
// PL Resets and clocks
.FCLKCLK(fclk[3:0]), // PL Clocks [3:0], output
.FCLKCLKTRIGN(), // PL Clock Throttle Control [3:0], input
.FCLKRESETN(frst[3:0]), // PL General purpose user reset [3:0], output (active low)
// Debug signals
.FTMTP2FDEBUG(), // Debug General purpose debug output [31:0], output
.FTMTF2PDEBUG(), // Debug General purpose debug input [31:0], input
.FTMTP2FTRIG(), // Debug Trigger PS to PL [3:0], output
.FTMTP2FTRIGACK(), // Debug Trigger PS to PL acknowledge[3:0], input
.FTMTF2PTRIG(), // Debug Trigger PL to PS [3:0], input
.FTMTF2PTRIGACK(), // Debug Trigger PL to PS acknowledge[3:0], output
.FTMDTRACEINCLOCK(), // Debug Trace PL to PS Clock, input
.FTMDTRACEINVALID(), // Debug Trace PL to PS Clock, data&id valid, input
.FTMDTRACEINDATA(), // Debug Trace PL to PS data [31:0], input
.FTMDTRACEINATID(), // Debug Trace PL to PS ID [3:0], input
// DDR Urgent
.DDRARB(), // DDR Urgent[3:0], input
// SRAM interrupt (on rising edge)
.EMIOSRAMINTIN(), // SRAM interrupt #50 shared with NAND busy, input
// AXI interfaces
.FPGAIDLEN(1'b1), //Idle PL AXI interfaces (active low), input
// AXI PS Master GP0
// AXI PS Master GP0: Clock, Reset
.MAXIGP0ACLK(/*axi_aclk*/), // AXI PS Master GP0 Clock , input
// .MAXIGP0ACLK(/*fclk[0]*/), // AXI PS Master GP0 Clock , input
// .MAXIGP0ACLK(/*~fclk[0]*/), // AXI PS Master GP0 Clock , input
// .MAXIGP0ACLK(/*axi_naclk*/), // AXI PS Master GP0 Clock , input
//
.MAXIGP0ARESETN(), // AXI PS Master GP0 Reset, output
// AXI PS Master GP0: Read Address
.MAXIGP0ARADDR (/*axi_araddr[31:0]*/), // AXI PS Master GP0 ARADDR[31:0], output
.MAXIGP0ARVALID (/*axi_arvalid*/), // AXI PS Master GP0 ARVALID, output
.MAXIGP0ARREADY (/*axi_arready*/), // AXI PS Master GP0 ARREADY, input
.MAXIGP0ARID (/*axi_arid[11:0]*/), // AXI PS Master GP0 ARID[11:0], output
.MAXIGP0ARLOCK (), // AXI PS Master GP0 ARLOCK[1:0], output
.MAXIGP0ARCACHE (),// AXI PS Master GP0 ARCACHE[3:0], output
.MAXIGP0ARPROT(), // AXI PS Master GP0 ARPROT[2:0], output
.MAXIGP0ARLEN (/*axi_arlen[3:0]*/), // AXI PS Master GP0 ARLEN[3:0], output
.MAXIGP0ARSIZE (/*axi_arsize[1:0]*/), // AXI PS Master GP0 ARSIZE[1:0], output
.MAXIGP0ARBURST (/*axi_arburst[1:0]*/),// AXI PS Master GP0 ARBURST[1:0], output
.MAXIGP0ARQOS (), // AXI PS Master GP0 ARQOS[3:0], output
// AXI PS Master GP0: Read Data
.MAXIGP0RDATA (/*axi_rdata[31:0]*/), // AXI PS Master GP0 RDATA[31:0], input
.MAXIGP0RVALID (/*axi_rvalid*/), // AXI PS Master GP0 RVALID, input
.MAXIGP0RREADY (/*axi_rready*/), // AXI PS Master GP0 RREADY, output
.MAXIGP0RID (/*axi_rid[11:0]*/), // AXI PS Master GP0 RID[11:0], input
.MAXIGP0RLAST (/*axi_rlast*/), // AXI PS Master GP0 RLAST, input
.MAXIGP0RRESP (/*axi_rresp[1:0]*/), // AXI PS Master GP0 RRESP[1:0], input
// AXI PS Master GP0: Write Address
.MAXIGP0AWADDR (/*axi_awaddr[31:0]*/), // AXI PS Master GP0 AWADDR[31:0], output
.MAXIGP0AWVALID (/*axi_awvalid*/), // AXI PS Master GP0 AWVALID, output
.MAXIGP0AWREADY (/*axi_awready*/), // AXI PS Master GP0 AWREADY, input
.MAXIGP0AWID (/*axi_awid[11:0]*/), // AXI PS Master GP0 AWID[11:0], output
.MAXIGP0AWLOCK (), // AXI PS Master GP0 AWLOCK[1:0], output
.MAXIGP0AWCACHE (),// AXI PS Master GP0 AWCACHE[3:0], output
.MAXIGP0AWPROT (), // AXI PS Master GP0 AWPROT[2:0], output
.MAXIGP0AWLEN (/*axi_awlen[3:0]*/), // AXI PS Master GP0 AWLEN[3:0], output
.MAXIGP0AWSIZE (/*axi_awsize[1:0]*/), // AXI PS Master GP0 AWSIZE[1:0], output
.MAXIGP0AWBURST (/*axi_awburst[1:0]*/),// AXI PS Master GP0 AWBURST[1:0], output
.MAXIGP0AWQOS (), // AXI PS Master GP0 AWQOS[3:0], output
// AXI PS Master GP0: Write Data
.MAXIGP0WDATA (/*axi_wdata[31:0]*/), // AXI PS Master GP0 WDATA[31:0], output
.MAXIGP0WVALID (/*axi_wvalid*/), // AXI PS Master GP0 WVALID, output
.MAXIGP0WREADY (/*axi_wready*/), // AXI PS Master GP0 WREADY, input
.MAXIGP0WID (/*axi_wid[11:0]*/), // AXI PS Master GP0 WID[11:0], output
.MAXIGP0WLAST (/*axi_wlast*/), // AXI PS Master GP0 WLAST, output
.MAXIGP0WSTRB (/*axi_wstb[3:0]*/), // AXI PS Master GP0 WSTRB[3:0], output
// AXI PS Master GP0: Write Responce
.MAXIGP0BVALID (/*axi_bvalid*/), // AXI PS Master GP0 BVALID, input
.MAXIGP0BREADY (/*axi_bready*/), // AXI PS Master GP0 BREADY, output
.MAXIGP0BID (/*axi_bid[11:0]*/), // AXI PS Master GP0 BID[11:0], input
.MAXIGP0BRESP (/*axi_bresp[1:0]*/), // AXI PS Master GP0 BRESP[1:0], input
// AXI PS Master GP1
// AXI PS Master GP1: Clock, Reset
.MAXIGP1ACLK (axi_aclk), // AXI PS Master GP1 Clock , input
.MAXIGP1ARESETN (), // AXI PS Master GP1 Reset, output
// AXI PS Master GP1: Read Address
.MAXIGP1ARADDR (ARADDR), // AXI PS Master GP1 ARADDR[31:0], output
.MAXIGP1ARVALID (ARVALID), // AXI PS Master GP1 ARVALID, output
.MAXIGP1ARREADY (ARREADY), // AXI PS Master GP1 ARREADY, input
.MAXIGP1ARID (ARID), // AXI PS Master GP1 ARID[11:0], output
.MAXIGP1ARLOCK (ARLOCK), // AXI PS Master GP1 ARLOCK[1:0], output
.MAXIGP1ARCACHE (ARCACHE), // AXI PS Master GP1 ARCACHE[3:0], output
.MAXIGP1ARPROT (ARPROT), // AXI PS Master GP1 ARPROT[2:0], output
.MAXIGP1ARLEN (ARLEN), // AXI PS Master GP1 ARLEN[3:0], output
.MAXIGP1ARSIZE (ARSIZE), // AXI PS Master GP1 ARSIZE[1:0], output
.MAXIGP1ARBURST (ARBURST), // AXI PS Master GP1 ARBURST[1:0], output
.MAXIGP1ARQOS (ARQOS), // AXI PS Master GP1 ARQOS[3:0], output
// AXI PS Master GP1: Read Data
.MAXIGP1RDATA (RDATA), // AXI PS Master GP1 RDATA[31:0], input
.MAXIGP1RVALID (RVALID), // AXI PS Master GP1 RVALID, input
.MAXIGP1RREADY (RREADY), // AXI PS Master GP1 RREADY, output
.MAXIGP1RID (RID), // AXI PS Master GP1 RID[11:0], input
.MAXIGP1RLAST (RLAST), // AXI PS Master GP1 RLAST, input
.MAXIGP1RRESP (RRESP), // AXI PS Master GP1 RRESP[1:0], input
// AXI PS Master GP1: Write Address
.MAXIGP1AWADDR (AWADDR), // AXI PS Master GP1 AWADDR[31:0], output
.MAXIGP1AWVALID (AWVALID), // AXI PS Master GP1 AWVALID, output
.MAXIGP1AWREADY (AWREADY), // AXI PS Master GP1 AWREADY, input
.MAXIGP1AWID (AWID), // AXI PS Master GP1 AWID[11:0], output
.MAXIGP1AWLOCK (AWLOCK), // AXI PS Master GP1 AWLOCK[1:0], output
.MAXIGP1AWCACHE (AWCACHE), // AXI PS Master GP1 AWCACHE[3:0], output
.MAXIGP1AWPROT (AWPROT), // AXI PS Master GP1 AWPROT[2:0], output
.MAXIGP1AWLEN (AWLEN), // AXI PS Master GP1 AWLEN[3:0], output
.MAXIGP1AWSIZE (AWSIZE), // AXI PS Master GP1 AWSIZE[1:0], output
.MAXIGP1AWBURST (AWBURST), // AXI PS Master GP1 AWBURST[1:0], output
.MAXIGP1AWQOS (AWQOS), // AXI PS Master GP1 AWQOS[3:0], output
// AXI PS Master GP1: Write Data
.MAXIGP1WDATA (WDATA), // AXI PS Master GP1 WDATA[31:0], output
.MAXIGP1WVALID (WVALID), // AXI PS Master GP1 WVALID, output
.MAXIGP1WREADY (WREADY), // AXI PS Master GP1 WREADY, input
.MAXIGP1WID (WID), // AXI PS Master GP1 WID[11:0], output
.MAXIGP1WLAST (WLAST), // AXI PS Master GP1 WLAST, output
.MAXIGP1WSTRB (WSTRB), // AXI PS Master GP1 WSTRB[3:0], output
// AXI PS Master GP1: Write Responce
.MAXIGP1BVALID (BVALID), // AXI PS Master GP1 BVALID, input
.MAXIGP1BREADY (BREADY), // AXI PS Master GP1 BREADY, output
.MAXIGP1BID (BID), // AXI PS Master GP1 BID[11:0], input
.MAXIGP1BRESP (BRESP), // AXI PS Master GP1 BRESP[1:0], input
// AXI PS Slave GP0
// AXI PS Slave GP0: Clock, Reset
.SAXIGP0ACLK(), // AXI PS Slave GP0 Clock , input
.SAXIGP0ARESETN(), // AXI PS Slave GP0 Reset, output
// AXI PS Slave GP0: Read Address
.SAXIGP0ARADDR(), // AXI PS Slave GP0 ARADDR[31:0], input
.SAXIGP0ARVALID(), // AXI PS Slave GP0 ARVALID, input
.SAXIGP0ARREADY(), // AXI PS Slave GP0 ARREADY, output
.SAXIGP0ARID(), // AXI PS Slave GP0 ARID[5:0], input
.SAXIGP0ARLOCK(), // AXI PS Slave GP0 ARLOCK[1:0], input
.SAXIGP0ARCACHE(), // AXI PS Slave GP0 ARCACHE[3:0], input
.SAXIGP0ARPROT(), // AXI PS Slave GP0 ARPROT[2:0], input
.SAXIGP0ARLEN(), // AXI PS Slave GP0 ARLEN[3:0], input
.SAXIGP0ARSIZE(), // AXI PS Slave GP0 ARSIZE[1:0], input
.SAXIGP0ARBURST(), // AXI PS Slave GP0 ARBURST[1:0], input
.SAXIGP0ARQOS(), // AXI PS Slave GP0 ARQOS[3:0], input
// AXI PS Slave GP0: Read Data
.SAXIGP0RDATA(), // AXI PS Slave GP0 RDATA[31:0], output
.SAXIGP0RVALID(), // AXI PS Slave GP0 RVALID, output
.SAXIGP0RREADY(), // AXI PS Slave GP0 RREADY, input
.SAXIGP0RID(), // AXI PS Slave GP0 RID[5:0], output
.SAXIGP0RLAST(), // AXI PS Slave GP0 RLAST, output
.SAXIGP0RRESP(), // AXI PS Slave GP0 RRESP[1:0], output
// AXI PS Slave GP0: Write Address
.SAXIGP0AWADDR(), // AXI PS Slave GP0 AWADDR[31:0], input
.SAXIGP0AWVALID(), // AXI PS Slave GP0 AWVALID, input
.SAXIGP0AWREADY(), // AXI PS Slave GP0 AWREADY, output
.SAXIGP0AWID(), // AXI PS Slave GP0 AWID[5:0], input
.SAXIGP0AWLOCK(), // AXI PS Slave GP0 AWLOCK[1:0], input
.SAXIGP0AWCACHE(), // AXI PS Slave GP0 AWCACHE[3:0], input
.SAXIGP0AWPROT(), // AXI PS Slave GP0 AWPROT[2:0], input
.SAXIGP0AWLEN(), // AXI PS Slave GP0 AWLEN[3:0], input
.SAXIGP0AWSIZE(), // AXI PS Slave GP0 AWSIZE[1:0], input
.SAXIGP0AWBURST(), // AXI PS Slave GP0 AWBURST[1:0], input
.SAXIGP0AWQOS(), // AXI PS Slave GP0 AWQOS[3:0], input
// AXI PS Slave GP0: Write Data
.SAXIGP0WDATA(), // AXI PS Slave GP0 WDATA[31:0], input
.SAXIGP0WVALID(), // AXI PS Slave GP0 WVALID, input
.SAXIGP0WREADY(), // AXI PS Slave GP0 WREADY, output
.SAXIGP0WID(), // AXI PS Slave GP0 WID[5:0], input
.SAXIGP0WLAST(), // AXI PS Slave GP0 WLAST, input
.SAXIGP0WSTRB(), // AXI PS Slave GP0 WSTRB[3:0], input
// AXI PS Slave GP0: Write Responce
.SAXIGP0BVALID(), // AXI PS Slave GP0 BVALID, output
.SAXIGP0BREADY(), // AXI PS Slave GP0 BREADY, input
.SAXIGP0BID(), // AXI PS Slave GP0 BID[5:0], output //TODO: Update range !!!
.SAXIGP0BRESP(), // AXI PS Slave GP0 BRESP[1:0], output
// AXI PS Slave GP1
// AXI PS Slave GP1: Clock, Reset
.SAXIGP1ACLK(), // AXI PS Slave GP1 Clock , input
.SAXIGP1ARESETN(), // AXI PS Slave GP1 Reset, output
// AXI PS Slave GP1: Read Address
.SAXIGP1ARADDR(), // AXI PS Slave GP1 ARADDR[31:0], input
.SAXIGP1ARVALID(), // AXI PS Slave GP1 ARVALID, input
.SAXIGP1ARREADY(), // AXI PS Slave GP1 ARREADY, output
.SAXIGP1ARID(), // AXI PS Slave GP1 ARID[5:0], input
.SAXIGP1ARLOCK(), // AXI PS Slave GP1 ARLOCK[1:0], input
.SAXIGP1ARCACHE(), // AXI PS Slave GP1 ARCACHE[3:0], input
.SAXIGP1ARPROT(), // AXI PS Slave GP1 ARPROT[2:0], input
.SAXIGP1ARLEN(), // AXI PS Slave GP1 ARLEN[3:0], input
.SAXIGP1ARSIZE(), // AXI PS Slave GP1 ARSIZE[1:0], input
.SAXIGP1ARBURST(), // AXI PS Slave GP1 ARBURST[1:0], input
.SAXIGP1ARQOS(), // AXI PS Slave GP1 ARQOS[3:0], input
// AXI PS Slave GP1: Read Data
.SAXIGP1RDATA(), // AXI PS Slave GP1 RDATA[31:0], output
.SAXIGP1RVALID(), // AXI PS Slave GP1 RVALID, output
.SAXIGP1RREADY(), // AXI PS Slave GP1 RREADY, input
.SAXIGP1RID(), // AXI PS Slave GP1 RID[5:0], output
.SAXIGP1RLAST(), // AXI PS Slave GP1 RLAST, output
.SAXIGP1RRESP(), // AXI PS Slave GP1 RRESP[1:0], output
// AXI PS Slave GP1: Write Address
.SAXIGP1AWADDR(), // AXI PS Slave GP1 AWADDR[31:0], input
.SAXIGP1AWVALID(), // AXI PS Slave GP1 AWVALID, input
.SAXIGP1AWREADY(), // AXI PS Slave GP1 AWREADY, output
.SAXIGP1AWID(), // AXI PS Slave GP1 AWID[5:0], input
.SAXIGP1AWLOCK(), // AXI PS Slave GP1 AWLOCK[1:0], input
.SAXIGP1AWCACHE(), // AXI PS Slave GP1 AWCACHE[3:0], input
.SAXIGP1AWPROT(), // AXI PS Slave GP1 AWPROT[2:0], input
.SAXIGP1AWLEN(), // AXI PS Slave GP1 AWLEN[3:0], input
.SAXIGP1AWSIZE(), // AXI PS Slave GP1 AWSIZE[1:0], input
.SAXIGP1AWBURST(), // AXI PS Slave GP1 AWBURST[1:0], input
.SAXIGP1AWQOS(), // AXI PS Slave GP1 AWQOS[3:0], input
// AXI PS Slave GP1: Write Data
.SAXIGP1WDATA(), // AXI PS Slave GP1 WDATA[31:0], input
.SAXIGP1WVALID(), // AXI PS Slave GP1 WVALID, input
.SAXIGP1WREADY(), // AXI PS Slave GP1 WREADY, output
.SAXIGP1WID(), // AXI PS Slave GP1 WID[5:0], input
.SAXIGP1WLAST(), // AXI PS Slave GP1 WLAST, input
.SAXIGP1WSTRB(), // AXI PS Slave GP1 WSTRB[3:0], input
// AXI PS Slave GP1: Write Responce
.SAXIGP1BVALID(), // AXI PS Slave GP1 BVALID, output
.SAXIGP1BREADY(), // AXI PS Slave GP1 BREADY, input
.SAXIGP1BID(), // AXI PS Slave GP1 BID[5:0], output
.SAXIGP1BRESP(), // AXI PS Slave GP1 BRESP[1:0], output
// AXI PS Slave HP0
// AXI PS Slave HP0: Clock, Reset
.SAXIHP0ACLK(), // AXI PS Slave HP0 Clock , input
.SAXIHP0ARESETN(), // AXI PS Slave HP0 Reset, output
// AXI PS Slave HP0: Read Address
.SAXIHP0ARADDR(), // AXI PS Slave HP0 ARADDR[31:0], input
.SAXIHP0ARVALID(), // AXI PS Slave HP0 ARVALID, input
.SAXIHP0ARREADY(), // AXI PS Slave HP0 ARREADY, output
.SAXIHP0ARID(), // AXI PS Slave HP0 ARID[5:0], input
.SAXIHP0ARLOCK(), // AXI PS Slave HP0 ARLOCK[1:0], input
.SAXIHP0ARCACHE(), // AXI PS Slave HP0 ARCACHE[3:0], input
.SAXIHP0ARPROT(), // AXI PS Slave HP0 ARPROT[2:0], input
.SAXIHP0ARLEN(), // AXI PS Slave HP0 ARLEN[3:0], input
.SAXIHP0ARSIZE(), // AXI PS Slave HP0 ARSIZE[2:0], input
.SAXIHP0ARBURST(), // AXI PS Slave HP0 ARBURST[1:0], input
.SAXIHP0ARQOS(), // AXI PS Slave HP0 ARQOS[3:0], input
// AXI PS Slave HP0: Read Data
.SAXIHP0RDATA(), // AXI PS Slave HP0 RDATA[63:0], output
.SAXIHP0RVALID(), // AXI PS Slave HP0 RVALID, output
.SAXIHP0RREADY(), // AXI PS Slave HP0 RREADY, input
.SAXIHP0RID(), // AXI PS Slave HP0 RID[5:0], output
.SAXIHP0RLAST(), // AXI PS Slave HP0 RLAST, output
.SAXIHP0RRESP(), // AXI PS Slave HP0 RRESP[1:0], output
.SAXIHP0RCOUNT(), // AXI PS Slave HP0 RCOUNT[7:0], output
.SAXIHP0RACOUNT(), // AXI PS Slave HP0 RACOUNT[2:0], output
.SAXIHP0RDISSUECAP1EN(), // AXI PS Slave HP0 RDISSUECAP1EN, input
// AXI PS Slave HP0: Write Address
.SAXIHP0AWADDR(), // AXI PS Slave HP0 AWADDR[31:0], input
.SAXIHP0AWVALID(), // AXI PS Slave HP0 AWVALID, input
.SAXIHP0AWREADY(), // AXI PS Slave HP0 AWREADY, output
.SAXIHP0AWID(), // AXI PS Slave HP0 AWID[5:0], input
.SAXIHP0AWLOCK(), // AXI PS Slave HP0 AWLOCK[1:0], input
.SAXIHP0AWCACHE(), // AXI PS Slave HP0 AWCACHE[3:0], input
.SAXIHP0AWPROT(), // AXI PS Slave HP0 AWPROT[2:0], input
.SAXIHP0AWLEN(), // AXI PS Slave HP0 AWLEN[3:0], input
.SAXIHP0AWSIZE(), // AXI PS Slave HP0 AWSIZE[1:0], input
.SAXIHP0AWBURST(), // AXI PS Slave HP0 AWBURST[1:0], input
.SAXIHP0AWQOS(), // AXI PS Slave HP0 AWQOS[3:0], input
// AXI PS Slave HP0: Write Data
.SAXIHP0WDATA(), // AXI PS Slave HP0 WDATA[63:0], input
.SAXIHP0WVALID(), // AXI PS Slave HP0 WVALID, input
.SAXIHP0WREADY(), // AXI PS Slave HP0 WREADY, output
.SAXIHP0WID(), // AXI PS Slave HP0 WID[5:0], input
.SAXIHP0WLAST(), // AXI PS Slave HP0 WLAST, input
.SAXIHP0WSTRB(), // AXI PS Slave HP0 WSTRB[7:0], input
.SAXIHP0WCOUNT(), // AXI PS Slave HP0 WCOUNT[7:0], output
.SAXIHP0WACOUNT(), // AXI PS Slave HP0 WACOUNT[5:0], output
.SAXIHP0WRISSUECAP1EN(), // AXI PS Slave HP0 WRISSUECAP1EN, input
// AXI PS Slave HP0: Write Responce
.SAXIHP0BVALID(), // AXI PS Slave HP0 BVALID, output
.SAXIHP0BREADY(), // AXI PS Slave HP0 BREADY, input
.SAXIHP0BID(), // AXI PS Slave HP0 BID[5:0], output
.SAXIHP0BRESP(), // AXI PS Slave HP0 BRESP[1:0], output
// AXI PS Slave HP1
// AXI PS Slave 1: Clock, Reset
.SAXIHP1ACLK(), // AXI PS Slave HP1 Clock , input
.SAXIHP1ARESETN(), // AXI PS Slave HP1 Reset, output
// AXI PS Slave HP1: Read Address
.SAXIHP1ARADDR(), // AXI PS Slave HP1 ARADDR[31:0], input
.SAXIHP1ARVALID(), // AXI PS Slave HP1 ARVALID, input
.SAXIHP1ARREADY(), // AXI PS Slave HP1 ARREADY, output
.SAXIHP1ARID(), // AXI PS Slave HP1 ARID[5:0], input
.SAXIHP1ARLOCK(), // AXI PS Slave HP1 ARLOCK[1:0], input
.SAXIHP1ARCACHE(), // AXI PS Slave HP1 ARCACHE[3:0], input
.SAXIHP1ARPROT(), // AXI PS Slave HP1 ARPROT[2:0], input
.SAXIHP1ARLEN(), // AXI PS Slave HP1 ARLEN[3:0], input
.SAXIHP1ARSIZE(), // AXI PS Slave HP1 ARSIZE[2:0], input
.SAXIHP1ARBURST(), // AXI PS Slave HP1 ARBURST[1:0], input
.SAXIHP1ARQOS(), // AXI PS Slave HP1 ARQOS[3:0], input
// AXI PS Slave HP1: Read Data
.SAXIHP1RDATA(), // AXI PS Slave HP1 RDATA[63:0], output
.SAXIHP1RVALID(), // AXI PS Slave HP1 RVALID, output
.SAXIHP1RREADY(), // AXI PS Slave HP1 RREADY, input
.SAXIHP1RID(), // AXI PS Slave HP1 RID[5:0], output
.SAXIHP1RLAST(), // AXI PS Slave HP1 RLAST, output
.SAXIHP1RRESP(), // AXI PS Slave HP1 RRESP[1:0], output
.SAXIHP1RCOUNT(), // AXI PS Slave HP1 RCOUNT[7:0], output
.SAXIHP1RACOUNT(), // AXI PS Slave HP1 RACOUNT[2:0], output
.SAXIHP1RDISSUECAP1EN(), // AXI PS Slave HP1 RDISSUECAP1EN, input
// AXI PS Slave HP1: Write Address
.SAXIHP1AWADDR(), // AXI PS Slave HP1 AWADDR[31:0], input
.SAXIHP1AWVALID(), // AXI PS Slave HP1 AWVALID, input
.SAXIHP1AWREADY(), // AXI PS Slave HP1 AWREADY, output
.SAXIHP1AWID(), // AXI PS Slave HP1 AWID[5:0], input
.SAXIHP1AWLOCK(), // AXI PS Slave HP1 AWLOCK[1:0], input
.SAXIHP1AWCACHE(), // AXI PS Slave HP1 AWCACHE[3:0], input
.SAXIHP1AWPROT(), // AXI PS Slave HP1 AWPROT[2:0], input
.SAXIHP1AWLEN(), // AXI PS Slave HP1 AWLEN[3:0], input
.SAXIHP1AWSIZE(), // AXI PS Slave HP1 AWSIZE[1:0], input
.SAXIHP1AWBURST(), // AXI PS Slave HP1 AWBURST[1:0], input
.SAXIHP1AWQOS(), // AXI PS Slave HP1 AWQOS[3:0], input
// AXI PS Slave HP1: Write Data
.SAXIHP1WDATA(), // AXI PS Slave HP1 WDATA[63:0], input
.SAXIHP1WVALID(), // AXI PS Slave HP1 WVALID, input
.SAXIHP1WREADY(), // AXI PS Slave HP1 WREADY, output
.SAXIHP1WID(), // AXI PS Slave HP1 WID[5:0], input
.SAXIHP1WLAST(), // AXI PS Slave HP1 WLAST, input
.SAXIHP1WSTRB(), // AXI PS Slave HP1 WSTRB[7:0], input
.SAXIHP1WCOUNT(), // AXI PS Slave HP1 WCOUNT[7:0], output
.SAXIHP1WACOUNT(), // AXI PS Slave HP1 WACOUNT[5:0], output
.SAXIHP1WRISSUECAP1EN(), // AXI PS Slave HP1 WRISSUECAP1EN, input
// AXI PS Slave HP1: Write Responce
.SAXIHP1BVALID(), // AXI PS Slave HP1 BVALID, output
.SAXIHP1BREADY(), // AXI PS Slave HP1 BREADY, input
.SAXIHP1BID(), // AXI PS Slave HP1 BID[5:0], output
.SAXIHP1BRESP(), // AXI PS Slave HP1 BRESP[1:0], output
// AXI PS Slave HP2
// AXI PS Slave HP2: Clock, Reset
.SAXIHP2ACLK(), // AXI PS Slave HP2 Clock , input
.SAXIHP2ARESETN(), // AXI PS Slave HP2 Reset, output
// AXI PS Slave HP2: Read Address
.SAXIHP2ARADDR(), // AXI PS Slave HP2 ARADDR[31:0], input
.SAXIHP2ARVALID(), // AXI PS Slave HP2 ARVALID, input
.SAXIHP2ARREADY(), // AXI PS Slave HP2 ARREADY, output
.SAXIHP2ARID(), // AXI PS Slave HP2 ARID[5:0], input
.SAXIHP2ARLOCK(), // AXI PS Slave HP2 ARLOCK[1:0], input
.SAXIHP2ARCACHE(), // AXI PS Slave HP2 ARCACHE[3:0], input
.SAXIHP2ARPROT(), // AXI PS Slave HP2 ARPROT[2:0], input
.SAXIHP2ARLEN(), // AXI PS Slave HP2 ARLEN[3:0], input
.SAXIHP2ARSIZE(), // AXI PS Slave HP2 ARSIZE[2:0], input
.SAXIHP2ARBURST(), // AXI PS Slave HP2 ARBURST[1:0], input
.SAXIHP2ARQOS(), // AXI PS Slave HP2 ARQOS[3:0], input
// AXI PS Slave HP2: Read Data
.SAXIHP2RDATA(), // AXI PS Slave HP2 RDATA[63:0], output
.SAXIHP2RVALID(), // AXI PS Slave HP2 RVALID, output
.SAXIHP2RREADY(), // AXI PS Slave HP2 RREADY, input
.SAXIHP2RID(), // AXI PS Slave HP2 RID[5:0], output
.SAXIHP2RLAST(), // AXI PS Slave HP2 RLAST, output
.SAXIHP2RRESP(), // AXI PS Slave HP2 RRESP[1:0], output
.SAXIHP2RCOUNT(), // AXI PS Slave HP2 RCOUNT[7:0], output
.SAXIHP2RACOUNT(), // AXI PS Slave HP2 RACOUNT[2:0], output
.SAXIHP2RDISSUECAP1EN(), // AXI PS Slave HP2 RDISSUECAP1EN, input
// AXI PS Slave HP2: Write Address
.SAXIHP2AWADDR(), // AXI PS Slave HP2 AWADDR[31:0], input
.SAXIHP2AWVALID(), // AXI PS Slave HP2 AWVALID, input
.SAXIHP2AWREADY(), // AXI PS Slave HP2 AWREADY, output
.SAXIHP2AWID(), // AXI PS Slave HP2 AWID[5:0], input
.SAXIHP2AWLOCK(), // AXI PS Slave HP2 AWLOCK[1:0], input
.SAXIHP2AWCACHE(), // AXI PS Slave HP2 AWCACHE[3:0], input
.SAXIHP2AWPROT(), // AXI PS Slave HP2 AWPROT[2:0], input
.SAXIHP2AWLEN(), // AXI PS Slave HP2 AWLEN[3:0], input
.SAXIHP2AWSIZE(), // AXI PS Slave HP2 AWSIZE[1:0], input
.SAXIHP2AWBURST(), // AXI PS Slave HP2 AWBURST[1:0], input
.SAXIHP2AWQOS(), // AXI PS Slave HP2 AWQOS[3:0], input
// AXI PS Slave HP2: Write Data
.SAXIHP2WDATA(), // AXI PS Slave HP2 WDATA[63:0], input
.SAXIHP2WVALID(), // AXI PS Slave HP2 WVALID, input
.SAXIHP2WREADY(), // AXI PS Slave HP2 WREADY, output
.SAXIHP2WID(), // AXI PS Slave HP2 WID[5:0], input
.SAXIHP2WLAST(), // AXI PS Slave HP2 WLAST, input
.SAXIHP2WSTRB(), // AXI PS Slave HP2 WSTRB[7:0], input
.SAXIHP2WCOUNT(), // AXI PS Slave HP2 WCOUNT[7:0], output
.SAXIHP2WACOUNT(), // AXI PS Slave HP2 WACOUNT[5:0], output
.SAXIHP2WRISSUECAP1EN(), // AXI PS Slave HP2 WRISSUECAP1EN, input
// AXI PS Slave HP2: Write Responce
.SAXIHP2BVALID(), // AXI PS Slave HP2 BVALID, output
.SAXIHP2BREADY(), // AXI PS Slave HP2 BREADY, input
.SAXIHP2BID(), // AXI PS Slave HP2 BID[5:0], output
.SAXIHP2BRESP(), // AXI PS Slave HP2 BRESP[1:0], output
// AXI PS Slave HP3
// AXI PS Slave HP3: Clock, Reset
.SAXIHP3ACLK (hclk), // AXI PS Slave HP3 Clock , input
.SAXIHP3ARESETN(), // AXI PS Slave HP3 Reset, output
// AXI PS Slave HP3: Read Address
.SAXIHP3ARADDR (afi0_araddr), // AXI PS Slave HP3 ARADDR[31:0], input
.SAXIHP3ARVALID (afi0_arvalid), // AXI PS Slave HP3 ARVALID, input
.SAXIHP3ARREADY (afi0_arready), // AXI PS Slave HP3 ARREADY, output
.SAXIHP3ARID (afi0_arid), // AXI PS Slave HP3 ARID[5:0], input
.SAXIHP3ARLOCK (afi0_arlock), // AXI PS Slave HP3 ARLOCK[1:0], input
.SAXIHP3ARCACHE (afi0_arcache), // AXI PS Slave HP3 ARCACHE[3:0], input
.SAXIHP3ARPROT (afi0_arprot), // AXI PS Slave HP3 ARPROT[2:0], input
.SAXIHP3ARLEN (afi0_arlen), // AXI PS Slave HP3 ARLEN[3:0], input
.SAXIHP3ARSIZE (afi0_arsize), // AXI PS Slave HP3 ARSIZE[2:0], input
.SAXIHP3ARBURST (afi0_arburst), // AXI PS Slave HP3 ARBURST[1:0], input
.SAXIHP3ARQOS (afi0_arqos), // AXI PS Slave HP3 ARQOS[3:0], input
// AXI PS Slave HP3: Read Data
.SAXIHP3RDATA (afi0_rdata), // AXI PS Slave HP3 RDATA[63:0], output
.SAXIHP3RVALID (afi0_rvalid), // AXI PS Slave HP3 RVALID, output
.SAXIHP3RREADY (afi0_rready), // AXI PS Slave HP3 RREADY, input
.SAXIHP3RID (afi0_rid), // AXI PS Slave HP3 RID[5:0], output
.SAXIHP3RLAST (afi0_rlast), // AXI PS Slave HP3 RLAST, output
.SAXIHP3RRESP (afi0_rresp), // AXI PS Slave HP3 RRESP[1:0], output
.SAXIHP3RCOUNT (afi0_rcount), // AXI PS Slave HP3 RCOUNT[7:0], output
.SAXIHP3RACOUNT (afi0_racount), // AXI PS Slave HP3 RACOUNT[2:0], output
.SAXIHP3RDISSUECAP1EN (afi0_rdissuecap1en), // AXI PS Slave HP3 RDISSUECAP1EN, input
// AXI PS Slave HP3: Write Address
.SAXIHP3AWADDR (afi0_awaddr), // AXI PS Slave HP3 AWADDR[31:0], input
.SAXIHP3AWVALID (afi0_awvalid), // AXI PS Slave HP3 AWVALID, input
.SAXIHP3AWREADY (afi0_awready), // AXI PS Slave HP3 AWREADY, output
.SAXIHP3AWID (afi0_awid), // AXI PS Slave HP3 AWID[5:0], input
.SAXIHP3AWLOCK (afi0_awlock), // AXI PS Slave HP3 AWLOCK[1:0], input
.SAXIHP3AWCACHE (afi0_awcache), // AXI PS Slave HP3 AWCACHE[3:0], input
.SAXIHP3AWPROT (afi0_awprot), // AXI PS Slave HP3 AWPROT[2:0], input
.SAXIHP3AWLEN (afi0_awlen), // AXI PS Slave HP3 AWLEN[3:0], input
.SAXIHP3AWSIZE (afi0_awsize), // AXI PS Slave HP3 AWSIZE[1:0], input
.SAXIHP3AWBURST (afi0_awburst), // AXI PS Slave HP3 AWBURST[1:0], input
.SAXIHP3AWQOS (afi0_awqos), // AXI PS Slave HP3 AWQOS[3:0], input
// AXI PS Slave HP3: Write Data
.SAXIHP3WDATA (afi0_wdata), // AXI PS Slave HP3 WDATA[63:0], input
.SAXIHP3WVALID (afi0_wvalid), // AXI PS Slave HP3 WVALID, input
.SAXIHP3WREADY (afi0_wready), // AXI PS Slave HP3 WREADY, output
.SAXIHP3WID (afi0_wid), // AXI PS Slave HP3 WID[5:0], input
.SAXIHP3WLAST (afi0_wlast), // AXI PS Slave HP3 WLAST, input
.SAXIHP3WSTRB (afi0_wstrb), // AXI PS Slave HP3 WSTRB[7:0], input
.SAXIHP3WCOUNT (afi0_wcount), // AXI PS Slave HP3 WCOUNT[7:0], output
.SAXIHP3WACOUNT (afi0_wacount), // AXI PS Slave HP3 WACOUNT[5:0], output
.SAXIHP3WRISSUECAP1EN (afi0_wrissuecap1en), // AXI PS Slave HP3 WRISSUECAP1EN, input
// AXI PS Slave HP3: Write Responce
.SAXIHP3BVALID (afi0_bvalid), // AXI PS Slave HP3 BVALID, output
.SAXIHP3BREADY (afi0_bready), // AXI PS Slave HP3 BREADY, input
.SAXIHP3BID (afi0_bid), // AXI PS Slave HP3 BID[5:0], output
.SAXIHP3BRESP (afi0_bresp), // AXI PS Slave HP3 BRESP[1:0], output
// AXI PS Slave ACP
// AXI PS Slave ACP: Clock, Reset
.SAXIACPACLK(), // AXI PS Slave ACP Clock, input
.SAXIACPARESETN(), // AXI PS Slave ACP Reset, output
// AXI PS Slave ACP: Read Address
.SAXIACPARADDR(), // AXI PS Slave ACP ARADDR[31:0], input
.SAXIACPARVALID(), // AXI PS Slave ACP ARVALID, input
.SAXIACPARREADY(), // AXI PS Slave ACP ARREADY, output
.SAXIACPARID(), // AXI PS Slave ACP ARID[2:0], input
.SAXIACPARLOCK(), // AXI PS Slave ACP ARLOCK[1:0], input
.SAXIACPARCACHE(), // AXI PS Slave ACP ARCACHE[3:0], input
.SAXIACPARPROT(), // AXI PS Slave ACP ARPROT[2:0], input
.SAXIACPARLEN(), // AXI PS Slave ACP ARLEN[3:0], input
.SAXIACPARSIZE(), // AXI PS Slave ACP ARSIZE[2:0], input
.SAXIACPARBURST(), // AXI PS Slave ACP ARBURST[1:0], input
.SAXIACPARQOS(), // AXI PS Slave ACP ARQOS[3:0], input
.SAXIACPARUSER(), // AXI PS Slave ACP ARUSER[4:0], input
// AXI PS Slave ACP: Read Data
.SAXIACPRDATA(), // AXI PS Slave ACP RDATA[63:0], output
.SAXIACPRVALID(), // AXI PS Slave ACP RVALID, output
.SAXIACPRREADY(), // AXI PS Slave ACP RREADY, input
.SAXIACPRID(), // AXI PS Slave ACP RID[2:0], output
.SAXIACPRLAST(), // AXI PS Slave ACP RLAST, output
.SAXIACPRRESP(), // AXI PS Slave ACP RRESP[1:0], output
// AXI PS Slave ACP: Write Address
.SAXIACPAWADDR(), // AXI PS Slave ACP AWADDR[31:0], input
.SAXIACPAWVALID(), // AXI PS Slave ACP AWVALID, input
.SAXIACPAWREADY(), // AXI PS Slave ACP AWREADY, output
.SAXIACPAWID(), // AXI PS Slave ACP AWID[2:0], input
.SAXIACPAWLOCK(), // AXI PS Slave ACP AWLOCK[1:0], input
.SAXIACPAWCACHE(), // AXI PS Slave ACP AWCACHE[3:0], input
.SAXIACPAWPROT(), // AXI PS Slave ACP AWPROT[2:0], input
.SAXIACPAWLEN(), // AXI PS Slave ACP AWLEN[3:0], input
.SAXIACPAWSIZE(), // AXI PS Slave ACP AWSIZE[1:0], input
.SAXIACPAWBURST(), // AXI PS Slave ACP AWBURST[1:0], input
.SAXIACPAWQOS(), // AXI PS Slave ACP AWQOS[3:0], input
.SAXIACPAWUSER(), // AXI PS Slave ACP AWUSER[4:0], input
// AXI PS Slave ACP: Write Data
.SAXIACPWDATA(), // AXI PS Slave ACP WDATA[63:0], input
.SAXIACPWVALID(), // AXI PS Slave ACP WVALID, input
.SAXIACPWREADY(), // AXI PS Slave ACP WREADY, output
.SAXIACPWID(), // AXI PS Slave ACP WID[2:0], input
.SAXIACPWLAST(), // AXI PS Slave ACP WLAST, input
.SAXIACPWSTRB(), // AXI PS Slave ACP WSTRB[7:0], input
// AXI PS Slave ACP: Write Responce
.SAXIACPBVALID(), // AXI PS Slave ACP BVALID, output
.SAXIACPBREADY(), // AXI PS Slave ACP BREADY, input
.SAXIACPBID(), // AXI PS Slave ACP BID[2:0], output
.SAXIACPBRESP(), // AXI PS Slave ACP BRESP[1:0], output
// Direct connection to PS package pads
.DDRA(), // PS DDRA[14:0], inout
.DDRBA(), // PS DDRBA[2:0], inout
.DDRCASB(), // PS DDRCASB, inout
.DDRCKE(), // PS DDRCKE, inout
.DDRCKP(), // PS DDRCKP, inout
.DDRCKN(), // PS DDRCKN, inout
.DDRCSB(), // PS DDRCSB, inout
.DDRDM(), // PS DDRDM[3:0], inout
.DDRDQ(), // PS DDRDQ[31:0], inout
.DDRDQSP(), // PS DDRDQSP[3:0], inout
.DDRDQSN(), // PS DDRDQSN[3:0], inout
.DDRDRSTB(), // PS DDRDRSTB, inout
.DDRODT(), // PS DDRODT, inout
.DDRRASB(), // PS DDRRASB, inout
.DDRVRN(), // PS DDRVRN, inout
.DDRVRP(), // PS DDRVRP, inout
.DDRWEB(), // PS DDRWEB, inout
.MIO(), // PS MIO[53:0], inout // clg225 has less
.PSCLK(), // PS PSCLK, inout
.PSPORB(), // PS PSPORB, inout
.PSSRSTB() // PS PSSRSTB, inout
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/gtxe2_gpl/ 0000775 0000000 0000000 00000000000 12572445207 0021714 5 ustar 00root root 0000000 0000000 x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/ 0000775 0000000 0000000 00000000000 12572445207 0020776 5 ustar 00root root 0000000 0000000 x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/command.v 0000664 0000000 0000000 00000027756 12572445207 0022624 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: command
* Date: 2015-07-11
* Author: Alexey
* Description: sata command layer temporary implementation
*
* Copyright (c) 2015 Elphel, Inc.
* command.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* command.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/*
* For testing purposes almost neat, manually-controlled
*/
module command(
input rst,
input clk,
// tl cmd iface
output wire [2:0] cmd_type,
output wire cmd_val,
output wire [3:0] cmd_port,
input wire cmd_busy,
input wire cmd_done_good,
input wire cmd_done_bad,
// temporary TODO
input wire [31:0] al_cmd_in, // == {cmd_type, cmd_port, cmd_val, cmd_done_bad, cmd_done_good, cmd_busy}
input wire al_cmd_val_in,
output wire [31:0] al_cmd_out, // same
// data from tl
input wire [31:0] tl_data_in,
input wire tl_data_val_in,
input wire tl_data_last_in,
output wire tl_data_busy_out,
// to tl
output wire [31:0] tl_data_out,
output wire tl_data_last_out,
output wire tl_data_val_out,
input wire tl_data_strobe_in,
// tmp inputs directly from registers for each and every shadow register and control bit
// from al
input wire [31:0] al_sh_data_in, // write data
input wire al_sh_data_val_in, // write strobe
input wire al_sh_data_strobe_in, // read strobe
input wire [15:0] al_sh_feature_in,
input wire al_sh_feature_val_in,
input wire [23:0] al_sh_lba_lo_in,
input wire al_sh_lba_lo_val_in,
input wire [23:0] al_sh_lba_hi_in,
input wire al_sh_lba_hi_val_in,
input wire [15:0] al_sh_count_in,
input wire al_sh_count_val_in,
input wire [7:0] al_sh_command_in,
input wire al_sh_command_val_in,
input wire [7:0] al_sh_dev_in,
input wire al_sh_dev_val_in,
input wire [7:0] al_sh_control_in,
input wire al_sh_control_val_in,
input wire [31:0] al_sh_dma_id_lo_in,
input wire al_sh_dma_id_lo_val_in,
input wire [31:0] al_sh_dma_id_hi_in,
input wire al_sh_dma_id_hi_val_in,
input wire [31:0] al_sh_buf_off_in,
input wire al_sh_buf_off_val_in,
input wire [15:0] al_sh_tran_cnt_in,
input wire al_sh_tran_cnt_val_in,
input wire al_sh_autoact_in,
input wire al_sh_autoact_val_in,
input wire al_sh_inter_in,
input wire al_sh_inter_val_in,
input wire al_sh_dir_in,
input wire al_sh_dir_val_in,
input wire [31:0] al_sh_dma_cnt_in,
input wire al_sh_dma_cnt_val_in,
input wire al_sh_notif_in,
input wire al_sh_notif_val_in,
input wire [3:0] al_sh_port_in,
input wire al_sh_port_val_in,
// from tl
input wire [47:0] tl_sh_lba_in,
input wire [15:0] tl_sh_count_in,
input wire [7:0] tl_sh_command_in,
input wire [7:0] tl_sh_err_in,
input wire [7:0] tl_sh_status_in,
input wire [7:0] tl_sh_estatus_in, // E_Status
input wire [7:0] tl_sh_dev_in,
input wire [3:0] tl_sh_port_in,
input wire tl_sh_inter_in,
input wire tl_sh_dir_in,
input wire [63:0] tl_sh_dma_id_in,
input wire [31:0] tl_sh_dma_off_in,
input wire [31:0] tl_sh_dma_cnt_in,
input wire [15:0] tl_sh_tran_cnt_in, // Transfer Count
input wire tl_sh_notif_in,
input wire tl_sh_autoact_in,
input wire tl_sh_lba_val_in,
input wire tl_sh_count_val_in,
input wire tl_sh_command_val_in,
input wire tl_sh_err_val_in,
input wire tl_sh_status_val_in,
input wire tl_sh_estatus_val_in, // E_Status
input wire tl_sh_dev_val_in,
input wire tl_sh_port_val_in,
input wire tl_sh_inter_val_in,
input wire tl_sh_dir_val_in,
input wire tl_sh_dma_id_val_in,
input wire tl_sh_dma_off_val_in,
input wire tl_sh_dma_cnt_val_in,
input wire tl_sh_tran_cnt_val_in, // Transfer Count
input wire tl_sh_notif_val_in,
input wire tl_sh_autoact_val_in,
// all regs to output
output wire sh_data_val_out,
output wire [31:0] sh_data_out,
output wire [7:0] sh_control_out,
output wire [15:0] sh_feature_out,
output wire [47:0] sh_lba_out,
output wire [15:0] sh_count_out,
output wire [7:0] sh_command_out,
output wire [7:0] sh_err_out,
output wire [7:0] sh_status_out,
output wire [7:0] sh_estatus_out, // E_Status
output wire [7:0] sh_dev_out,
output wire [3:0] sh_port_out,
output wire sh_inter_out,
output wire sh_dir_out,
output wire [63:0] sh_dma_id_out,
output wire [31:0] sh_dma_off_out,
output wire [31:0] sh_dma_cnt_out,
output wire [15:0] sh_tran_cnt_out, // Transfer Count
output wire sh_notif_out,
output wire sh_autoact_out
);
// shadow registers
wire [31:0] sh_data;
reg [7:0] sh_control;
reg [15:0] sh_feature;
reg [47:0] sh_lba;
reg [15:0] sh_count;
reg [7:0] sh_command;
reg [7:0] sh_err;
reg [7:0] sh_status;
reg [7:0] sh_estatus; // E_Status
reg [7:0] sh_dev;
reg [3:0] sh_port;
reg sh_inter;
reg sh_dir;
reg [63:0] sh_dma_id;
reg [31:0] sh_dma_off;
reg [31:0] sh_dma_cnt;
reg [15:0] sh_tran_cnt; // Transfer Count
reg sh_notif;
reg sh_autoact;
always @ (posedge clk)
begin
// sh_data <= rst ? 32'h0 : al_sh_data_val_in ? al_sh_data_in : /*tl_sh_data_val_in ? tl_sh_data_in :*/ sh_data;
sh_control <= rst ? 8'h0 : al_sh_control_val_in ? al_sh_control_in : /*tl_sh_control_val_in ? tl_sh_control_in :*/ sh_control;
sh_feature <= rst ? 16'h0 : al_sh_feature_val_in ? al_sh_feature_in : /*tl_sh_feature_val_in ? tl_sh_feature_in :*/ sh_feature;
sh_lba[23:0] <= rst ? 24'h0 : al_sh_lba_lo_val_in ? al_sh_lba_lo_in : tl_sh_lba_val_in ? tl_sh_lba_in[23:0] : sh_lba[23:0];
sh_lba[47:24] <= rst ? 24'h0 : al_sh_lba_hi_val_in ? al_sh_lba_hi_in : tl_sh_lba_val_in ? tl_sh_lba_in[47:24] : sh_lba[47:24];
sh_count <= rst ? 16'h0 : al_sh_count_val_in ? al_sh_count_in : tl_sh_count_val_in ? tl_sh_count_in : sh_count;
sh_command <= rst ? 8'h0 : al_sh_command_val_in ? al_sh_command_in : tl_sh_command_val_in ? tl_sh_command_in : sh_command;
sh_err <= rst ? 8'h0 :/* al_sh_err_val_in ? al_sh_err_in :*/ tl_sh_err_val_in ? tl_sh_err_in : sh_err;
sh_status <= rst ? 8'h0 :/* al_sh_status_val_in ? al_sh_status_in :*/ tl_sh_status_val_in ? tl_sh_status_in : sh_status;
sh_estatus <= rst ? 8'h0 :/* al_sh_estatus_val_in ? al_sh_estatus_in :*/ tl_sh_estatus_val_in ? tl_sh_estatus_in : sh_estatus;
sh_dev <= rst ? 8'h0 : al_sh_dev_val_in ? al_sh_dev_in : tl_sh_dev_val_in ? tl_sh_dev_in : sh_dev;
sh_port <= rst ? 4'h0 : al_sh_port_val_in ? al_sh_port_in : tl_sh_port_val_in ? tl_sh_port_in : sh_port;
sh_inter <= rst ? 1'h0 : al_sh_inter_val_in ? al_sh_inter_in : tl_sh_inter_val_in ? tl_sh_inter_in : sh_inter;
sh_dir <= rst ? 1'h0 : al_sh_dir_val_in ? al_sh_dir_in : tl_sh_dir_val_in ? tl_sh_dir_in : sh_dir;
sh_dma_id[31:0] <= rst ? 32'h0 : al_sh_dma_id_lo_val_in ? al_sh_dma_id_lo_in : tl_sh_dma_id_val_in ? tl_sh_dma_id_in[31:0] : sh_dma_id[31:0];
sh_dma_id[63:32] <= rst ? 32'h0 : al_sh_dma_id_lo_val_in ? al_sh_dma_id_hi_in : tl_sh_dma_id_val_in ? tl_sh_dma_id_in[63:32] : sh_dma_id[63:32];
sh_dma_off <= rst ? 32'h0 : al_sh_buf_off_val_in ? al_sh_buf_off_in : tl_sh_dma_off_val_in ? tl_sh_dma_off_in : sh_dma_off;
sh_dma_cnt <= rst ? 32'h0 : al_sh_dma_cnt_val_in ? al_sh_dma_cnt_in : tl_sh_dma_cnt_val_in ? tl_sh_dma_cnt_in : sh_dma_cnt;
sh_tran_cnt <= rst ? 16'h0 : al_sh_tran_cnt_val_in ? al_sh_tran_cnt_in : tl_sh_tran_cnt_val_in ? tl_sh_tran_cnt_in : sh_tran_cnt;
sh_notif <= rst ? 1'h0 : al_sh_notif_val_in ? al_sh_notif_in : tl_sh_notif_val_in ? tl_sh_notif_in : sh_notif;
sh_autoact <= rst ? 1'h0 : al_sh_autoact_val_in ? al_sh_autoact_in : tl_sh_autoact_val_in ? tl_sh_autoact_in : sh_autoact;
end
// outputs assignment
assign sh_data_out = sh_data;
assign sh_control_out = sh_control;
assign sh_feature_out = sh_feature;
assign sh_lba_out = sh_lba;
assign sh_count_out = sh_count;
assign sh_command_out = sh_command;
assign sh_err_out = sh_err;
assign sh_status_out = sh_status;
assign sh_estatus_out = sh_estatus;
assign sh_dev_out = sh_dev;
assign sh_port_out = sh_port;
assign sh_inter_out = sh_inter;
assign sh_dir_out = sh_dir;
assign sh_dma_id_out = sh_dma_id;
assign sh_dma_off_out = sh_dma_off;
assign sh_dma_cnt_out = sh_dma_cnt;
assign sh_tran_cnt_out = sh_tran_cnt;
assign sh_notif_out = sh_notif;
assign sh_autoact_out = sh_autoact;
// temporaty command register TODO
reg [31:0] cmd;
assign al_cmd_out = cmd;
always @ (posedge clk)
begin
cmd[31:4] <= rst ? 28'h0 : al_cmd_val_in ? al_cmd_in[31:4] : cmd[31:4];
cmd[3] <= rst ? 1'b0 : al_cmd_val_in ? al_cmd_in[3] : cmd_val ? 1'b0 : cmd[3];
cmd[2] <= rst ? 1'b0 : al_cmd_val_in ? 1'b0 : cmd_done_bad ? 1'b1 : cmd[2];
cmd[1] <= rst ? 1'b0 : al_cmd_val_in ? 1'b0 : cmd_done_good ? 1'b1 : cmd[1];
cmd[0] <= rst ? 1'b0 : al_cmd_val_in ? 1'b0 : cmd_busy;
end
assign cmd_val = ~cmd_busy & cmd[3];
assign cmd_type = cmd[10:8];
assign cmd_port = cmd[7:4];
// data read buffer, 2048 dwords
reg [9:0] raddr;
reg [9:0] waddr;
assign tl_data_busy_out = 1'b0;
assign tl_data_out = 32'h0;
assign tl_data_last_out = 1'b0;
assign tl_data_val_out = 1'b0;
always @ (posedge clk)
waddr <= rst ? 1'b0 : ~tl_data_val_in ? waddr : (raddr == waddr + 1'b1) ? waddr : waddr + 1'b1;
always @ (posedge clk)
raddr <= rst ? 1'b0 : al_sh_data_strobe_in ? raddr + 1'b1 : raddr;
ram_1kx32_1kx32 rbuf(
.rclk (clk), // clock for read port
.raddr (raddr), // read address
.ren (al_sh_data_strobe_in), // read port enable
.regen (1'b0), // output register enable
.data_out (sh_data), // data out
.wclk (clk), // clock for read port
.waddr (waddr), // write address
.we (tl_data_val_in), // write port enable
.web (4'hf),
.data_in (tl_data_in) // data out
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/crc.v 0000664 0000000 0000000 00000022040 12572445207 0021732 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: crc
* Date: 2015-07-11
* Author: Alexey
* Description: crc calculations for the link layer
*
* Copyright (c) 2015 Elphel, Inc.
* crc.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* crc.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/* same as for a scrambler, @ doc p.561 */
// TODO make it parallel, make another widths support
module crc #(
parameter DATA_BYTE_WIDTH = 4
)
(
input wire clk,
input wire rst,
input wire val_in,
input wire [DATA_BYTE_WIDTH*8 - 1:0] data_in,
output wire [DATA_BYTE_WIDTH*8 - 1:0] crc_out
);
reg [31:0] crc;
wire[31:0] crc_bit;
reg [31:0] new_bit;
always @ (posedge clk)
crc <= rst ? 32'h52325032 : val_in ? new_bit : crc;
assign crc_bit = crc ^ data_in;
assign crc_out = crc;
always @ (*)
begin
new_bit[31] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^
crc_bit[23] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[5];
new_bit[30] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^
crc_bit[22] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[4];
new_bit[29] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^
crc_bit[22] ^ crc_bit[21] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[3];
new_bit[28] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^
crc_bit[21] ^ crc_bit[20] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[2];
new_bit[27] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^
crc_bit[20] ^ crc_bit[19] ^ crc_bit[11] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[1];
new_bit[26] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^
crc_bit[20] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[10] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
crc_bit[0];
new_bit[25] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ crc_bit[18] ^
crc_bit[17] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[3] ^ crc_bit[2];
new_bit[24] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[17] ^
crc_bit[16] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[2] ^ crc_bit[1];
new_bit[23] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^
crc_bit[16] ^ crc_bit[15] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
new_bit[22] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[19] ^
crc_bit[18] ^ crc_bit[16] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[0];
new_bit[21] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[18] ^
crc_bit[17] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[5];
new_bit[20] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[17] ^
crc_bit[16] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[4];
new_bit[19] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[20] ^ crc_bit[16] ^
crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3];
new_bit[18] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[19] ^
crc_bit[15] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2];
new_bit[17] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[20] ^
crc_bit[18] ^ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[1];
new_bit[16] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^
crc_bit[17] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[0];
new_bit[15] = crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[16] ^
crc_bit[15] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^
crc_bit[3];
new_bit[14] = crc_bit[29] ^ crc_bit[26] ^ crc_bit[23] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ crc_bit[15] ^
crc_bit[14] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
crc_bit[2];
new_bit[13] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[16] ^
crc_bit[14] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[3] ^
crc_bit[2] ^ crc_bit[1];
new_bit[12] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[18] ^ crc_bit[17] ^
crc_bit[15] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^
crc_bit[2] ^ crc_bit[1] ^ crc_bit[0];
new_bit[11] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^
crc_bit[17] ^ crc_bit[16] ^ crc_bit[15] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[4] ^
crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
new_bit[10] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[19] ^ crc_bit[16] ^ crc_bit[14] ^
crc_bit[13] ^ crc_bit[9] ^ crc_bit[5] ^ crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
new_bit[9] = crc_bit[29] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[18] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[11] ^
crc_bit[9] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^ crc_bit[1];
new_bit[8] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[17] ^ crc_bit[12] ^ crc_bit[11] ^
crc_bit[10] ^ crc_bit[8] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
new_bit[7] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[21] ^
crc_bit[16] ^ crc_bit[15] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[3] ^
crc_bit[2] ^ crc_bit[0];
new_bit[6] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[14] ^
crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^
crc_bit[1];
new_bit[5] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[13] ^
crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^
crc_bit[0];
new_bit[4] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ crc_bit[19] ^
crc_bit[18] ^ crc_bit[15] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[4] ^
crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
new_bit[3] = crc_bit[31] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[15] ^
crc_bit[14] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3] ^ crc_bit[2] ^
crc_bit[1];
new_bit[2] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[16] ^
crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2] ^
crc_bit[1] ^ crc_bit[0];
new_bit[1] = crc_bit[28] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[17] ^ crc_bit[16] ^ crc_bit[13] ^ crc_bit[12] ^
crc_bit[11] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
new_bit[0] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^
crc_bit[16] ^ crc_bit[12] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[0];
end
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_10x8dec.v 0000664 0000000 0000000 00000011161 12572445207 0023223 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: gtx_10x8dec
* Date: 2015-07-11
* Author: Alexey
* Description: 8x10 encoder implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_10x8dec.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* gtx_10x8dec.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
module gtx_10x8dec(
input wire rst,
input wire clk,
input wire [19:0] indata,
output wire [15:0] outdata,
output wire [1:0] outisk,
output wire [1:0] notintable,
output wire [1:0] disperror
/* uncomment if necessary
input wire [0:0] inaux,
output wire [0:0] outaux, */
);
/*
uncomment if necessary
// bypass auxilary informational signals
reg [0:0] aux_r;
reg [0:0] aux_rr;
always @ (posedge clk)
begin
aux_r <= inaux;
aux_rr <= aux_r;
end
assign outaux = aux_rr;
*/
// split incoming data in 2 bytes
wire [9:0] addr0;
wire [9:0] addr1;
assign addr0 = indata[9:0];
assign addr1 = indata[19:10];
// get decoded values after 2 clock cycles, all '1's = cannot be decoded
wire [15:0] table0_out;
wire [15:0] table1_out;
wire [10:0] table0;
wire [10:0] table1;
assign table0 = table0_out[10:0];
assign table1 = table1_out[10:0];
assign outdata = {table1[7:0], table0[7:0]};
assign outisk = {table1[8], table0[8]};
assign notintable = {&table1, &table0};
// disparity control
// last clock disparity
reg disparity;
// disparity after 1st byte
wire disparity_interm;
// delayed ones
reg disp0_r;
reg disp0_rr;
reg disp1_r;
reg disp1_rr;
always @ (posedge clk)
begin
disp0_r <= disparity;
disp0_rr <= disp0_r;
disp1_r <= disparity_interm;
disp1_rr <= disp1_r;
end
// overall expected disparity when the table values would apper - disp0_r.
// disp1_rr shows expected after 0st byte would be considered
wire expected_disparity;
wire expected_disparity_interm;
assign expected_disparity = disp0_rr ^ correct_table_disp;
assign expected_disparity_interm = disp1_rr ^ correct_table_disp;
// invert disparity after a byte
// if current encoded word containg an equal amount of 1s and 0s (i.e. 5 x '1'), disp shall stay the same
// if amounts are unequal, there are either 4 or 6 '1's. in either case disp shall be inverted
wire inv_disp0;
wire inv_disp1;
assign inv_disp0 = ~^(indata[9:0]);
assign inv_disp1 = ~^(indata[19:10]);
assign disparity_interm = inv_disp0 ? ~disparity : disparity;
always @ (posedge clk)
disparity <= rst ? 1'b0 : inv_disp1 ^ inv_disp0 ? ~disparity : disparity;
// to correct disparity if once an error occured
reg correct_table_disp;
always @ (posedge clk)
correct_table_disp <= rst ? 1'b0 : disperror[1] ? ~correct_table_disp : correct_table_disp;
// calculate disparity on table values
wire table_pos_disp0;
wire table_neg_disp0;
wire table_pos_disp1;
wire table_neg_disp1;
// table_pos_disp - for current 10-bit word disparity can be positive
// _neg_ - can be negative
// neg & pos - can be either of them
assign table_pos_disp0 = table0[10];
assign table_neg_disp0 = table0[9];
assign table_pos_disp1 = table1[10];
assign table_neg_disp1 = table1[9];
assign disperror = ~{table_pos_disp0 & expected_disparity | table_neg_disp0 & ~expected_disparity, table_pos_disp1 & expected_disparity_interm | table_neg_disp1 & ~expected_disparity_interm};
// TODO change mem to 18 instead of 36, so the highest address bit could be dropped
ramt_var_w_var_r #(
.REGISTERS_A (1),
.REGISTERS_B (1),
.LOG2WIDTH_A (4),
.LOG2WIDTH_B (4)
`include "gtx_10x8dec_init.v"
)
decoding_table(
.clk_a (clk),
.addr_a ({1'b0, addr0}),
.en_a (1'b1),
.regen_a (1'b1),
.we_a (1'b0),
.data_out_a (table0_out),
.data_in_a (16'h0),
.clk_b (clk),
.addr_b ({1'b0, addr1}),
.en_b (1'b1),
.regen_b (1'b1),
.we_b (1'b0),
.data_out_b (table1_out),
.data_in_b (16'h0)
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_10x8dec_geninit.py 0000664 0000000 0000000 00000004116 12572445207 0025125 0 ustar 00root root 0000000 0000000 # left_column[9] = disparity
# left_column[8] = conrtol
# left_column[7:0] = decoded 8
# right column[9:0] = encoded 10 in correct order : abcdefgh. Need to flip it, because gtx spits out flipped data with flipped bit order
#
mem7f = []
for i in range(0x80):
mem7f.append(0);
filecontent = {}
for line in open('gtx_10x8dec_init_stub.v').readlines():
address_flipped_str = line.split()[1];
address_str = address_flipped_str[::-1]
address = int('0b' + address_str, 2)
# retrieve everything but disparity - highest bit
value = int('0b' + line.split()[0][1:], 2)
# retrieve disparity
disparity = int('0b' + line.split()[0][0], 2)
# if disparity = 1 -> flag positive disparity, 0 -> flag negative one
disp_pos = 1 if disparity == 1 else 0
disp_neg = 1 if disparity == 0 else 0
if address_str in filecontent:
disp_pos = 1 if filecontent[address_str][1] == 1 or disp_pos else 0
disp_neg = 1 if filecontent[address_str][2] == 1 or disp_neg else 0
filecontent[address_str] = [address, disp_pos, disp_neg, value];
for key in filecontent:
(address, disp_pos, disp_neg, value) = filecontent[key]
# if address == 0x2aa:
# print '2AA: ADDR>>4 = %X' % (address >> 4),' ADDR = ', bin(address), ' POS DISP = ', bin(disp_pos), ' NEG DISP = ', bin(disp_neg), ' VALUE = ', bin(value)
# print 'ADDR = ', bin(address), ' POS DISP = ', bin(disp_pos), ' NEG DISP = ', bin(disp_neg), ' VALUE = ', bin(value)
to_mem = (disp_pos << 10) + (disp_neg << 9) + value
mem7f[address >> 4] = mem7f[address >> 4] + (to_mem << ((address % 16) * 16))
# if (address >> 4) == 0x2a:
# print '2AA: ADDR = %X, to mem = %X, total = %X ' % ((address ),to_mem, mem7f[address >> 4])#, ' ADDR = ', bin(address), ' POS DISP = ', bin(disp_pos), ' NEG DISP = ', bin(disp_neg), ' VALUE = ', bin(value)
# if addr == 0x2aa:
# print "FLIPPED ADDR %s " % address_flipped_str, "ADDR %x " % addr, "ADDR7f %x " % (addr >> 4), "VALUE %x " % a
for i in range(0x80):
print ', .INIT_%02X\t(256\'h%064X)' % (i, mem7f[i])
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_10x8dec_init.v 0000664 0000000 0000000 00000024600 12572445207 0024250 0 ustar 00root root 0000000 0000000 , .INIT_00 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_01 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_02 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_03 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_04 (256'h000004EE04ED000004EB00000000000000000000000000000000000000000000)
, .INIT_05 (256'h000003FE03FD000003FB00000000000003F70000000000000000000000000000)
, .INIT_06 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_07 (256'h00000000000003FC000000000000000000000000000000000000000000000000)
, .INIT_08 (256'h0000040E040D0000040B00000000000000000000000000000000000000000000)
, .INIT_09 (256'h0000021E021D041C021B041A0419000002170416041500000413000000000000)
, .INIT_0A (256'h000002010202040C0204040A0409000002080406040500000403000000000000)
, .INIT_0B (256'h000000000000031C0000020F0200040700000210021F04140218041204110000)
, .INIT_0C (256'h0000026E026D0478026B047F0470000002670460046F0000057C000000000000)
, .INIT_0D (256'h000000000000027C0000027A0279046800000276027504640273046204610000)
, .INIT_0E (256'h000000000000026C0000026A02690477000002660265047B0263047D047E0000)
, .INIT_0F (256'h0000000000000000000000000000000000000000000002740000027202710000)
, .INIT_10 (256'h0000048E048D0000048B00000000000000000000000000000000000000000000)
, .INIT_11 (256'h0000029E029D049C029B049A0499000002970496049500000493000000000000)
, .INIT_12 (256'h000002810282048C0284048A0489000002880486048500000483000000000000)
, .INIT_13 (256'h000000000000039C0000028F0280048700000290029F04940298049204910000)
, .INIT_14 (256'h000006AE06AD04B806AB04BF04B0000002A704A004AF0000055C000000000000)
, .INIT_15 (256'h000002BE02BD06BC02BB06BA06B904A802B706B606B504A406B304A204A10000)
, .INIT_16 (256'h000002A102A206AC02A406AA06A904B702A806A606A504BB06A304BD04BE0000)
, .INIT_17 (256'h00000000000003BC000002AF02A004A7000002B002BF06B402B806B206B10000)
, .INIT_18 (256'h000006CE06CD04D806CB04DF04D0000002C704C004CF0000053C000000000000)
, .INIT_19 (256'h000002DE02DD06DC02DB06DA06D904C802D706D606D504C406D304C204C10000)
, .INIT_1A (256'h000002C102C206CC02C406CA06C904D702C806C606C504DB06C304DD04DE0000)
, .INIT_1B (256'h00000000000003DC000002CF02C004C7000002D002DF06D402D806D206D10000)
, .INIT_1C (256'h000002EE02ED04F802EB04FF04F0000002E704E004EF00000000000000000000)
, .INIT_1D (256'h00000000000002FC000002FA02F904E8000002F602F504E402F304E204E10000)
, .INIT_1E (256'h00000000000002EC000002EA02E904F7000002E602E504FB02E304FD04FE0000)
, .INIT_1F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_20 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_21 (256'h000002FE02FD04FC02FB04FA04F9000002F704F604F5000004F3000000000000)
, .INIT_22 (256'h000002E102E204EC02E404EA04E9000002E804E604E5000004E3000000000000)
, .INIT_23 (256'h0000000000000000000002EF02E004E7000002F002FF04F402F804F204F10000)
, .INIT_24 (256'h0000062E062D0438062B043F0430000002270420042F000005DC000000000000)
, .INIT_25 (256'h0000023E023D063C023B063A0639042802370636063504240633042204210000)
, .INIT_26 (256'h000002210222062C0224062A06290437022806260625043B0623043D043E0000)
, .INIT_27 (256'h000000000000033C0000022F0220042700000230023F06340238063206310000)
, .INIT_28 (256'h0000064E064D0458064B045F0450000002470440044F000005BC000000000000)
, .INIT_29 (256'h0000025E025D065C025B065A0659044802570656065504440653044204410000)
, .INIT_2A (256'h000002410242064C0244064A06490457024806460645045B0643045D045E0000)
, .INIT_2B (256'h000000000000035C0000024F0240044700000250025F06540258065206510000)
, .INIT_2C (256'h0000028E028D0498028B049F0490000002870480048F0000059C000000000000)
, .INIT_2D (256'h000000000000029C0000029A0299048800000296029504840293048204810000)
, .INIT_2E (256'h000000000000028C0000028A02890497000002860285049B0283049D049E0000)
, .INIT_2F (256'h0000000000000000000000000000000000000000000002940000029202910000)
, .INIT_30 (256'h0000046E046D0000046B00000000000000000000000000000000000000000000)
, .INIT_31 (256'h0000027E027D047C027B047A0479000002770476047500000473000000000000)
, .INIT_32 (256'h000002610262046C0264046A0469000002680466046500000463000000000000)
, .INIT_33 (256'h000000000000037C0000026F0260046700000270027F04740278047204710000)
, .INIT_34 (256'h0000020E020D0418020B041F0410000002070400040F0000051C000000000000)
, .INIT_35 (256'h000000000000021C0000021A0219040800000216021504040213040204010000)
, .INIT_36 (256'h000000000000020C0000020A02090417000002060205041B0203041D041E0000)
, .INIT_37 (256'h0000000000000000000000000000000000000000000002140000021202110000)
, .INIT_38 (256'h00000000000000000000000000000000000000000000000005FC000000000000)
, .INIT_39 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3A (256'h000000000000000000000000000005F700000000000005FB000005FD05FE0000)
, .INIT_3B (256'h0000000000000000000000000000000000000000000002F4000002F202F10000)
, .INIT_3C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_40 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_41 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_42 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_43 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_44 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_45 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_46 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_47 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_48 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_49 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_50 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_51 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_52 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_53 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_54 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_55 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_56 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_57 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_58 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_59 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_60 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_61 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_62 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_63 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_64 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_65 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_66 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_67 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_68 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_69 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_70 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_71 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_72 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_73 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_74 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_75 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_76 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_77 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_78 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_79 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7F (256'h0000000000000000000000000000000000000000000000000000000000000000)
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_10x8dec_init_stub.v 0000664 0000000 0000000 00000027020 12572445207 0025304 0 ustar 00root root 0000000 0000000 0000000000 1001110100
1000000000 0110001011
0000000001 0111010100
1000000001 1000101011
0000000010 1011010100
1000000010 0100101011
0000000011 1100011011
1000000011 1100010100
0000000100 1101010100
1000000100 0010101011
0000000101 1010011011
1000000101 1010010100
0000000110 0110011011
1000000110 0110010100
0000000111 1110001011
1000000111 0001110100
0000001000 1110010100
1000001000 0001101011
0000001001 1001011011
1000001001 1001010100
0000001010 0101011011
1000001010 0101010100
0000001011 1101001011
1000001011 1101000100
0000001100 0011011011
1000001100 0011010100
0000001101 1011001011
1000001101 1011000100
0000001110 0111001011
1000001110 0111000100
0000001111 0101110100
1000001111 1010001011
0000010000 0110110100
1000010000 1001001011
0000010001 1000111011
1000010001 1000110100
0000010010 0100111011
1000010010 0100110100
0000010011 1100101011
1000010011 1100100100
0000010100 0010111011
1000010100 0010110100
0000010101 1010101011
1000010101 1010100100
0000010110 0110101011
1000010110 0110100100
0000010111 1110100100
1000010111 0001011011
0000011000 1100110100
1000011000 0011001011
0000011001 1001101011
1000011001 1001100100
0000011010 0101101011
1000011010 0101100100
0000011011 1101100100
1000011011 0010011011
0000011100 0011101011
1000011100 0011100100
0000011101 1011100100
1000011101 0100011011
0000011110 0111100100
1000011110 1000011011
0000011111 1010110100
1000011111 0101001011
0000100000 1001111001
1000100000 0110001001
0000100001 0111011001
1000100001 1000101001
0000100010 1011011001
1000100010 0100101001
0000100011 1100011001
1000100011 1100011001
0000100100 1101011001
1000100100 0010101001
0000100101 1010011001
1000100101 1010011001
0000100110 0110011001
1000100110 0110011001
0000100111 1110001001
1000100111 0001111001
0000101000 1110011001
1000101000 0001101001
0000101001 1001011001
1000101001 1001011001
0000101010 0101011001
1000101010 0101011001
0000101011 1101001001
1000101011 1101001001
0000101100 0011011001
1000101100 0011011001
0000101101 1011001001
1000101101 1011001001
0000101110 0111001001
1000101110 0111001001
0000101111 0101111001
1000101111 1010001001
0000110000 0110111001
1000110000 1001001001
0000110001 1000111001
1000110001 1000111001
0000110010 0100111001
1000110010 0100111001
0000110011 1100101001
1000110011 1100101001
0000110100 0010111001
1000110100 0010111001
0000110101 1010101001
1000110101 1010101001
0000110110 0110101001
1000110110 0110101001
0000110111 1110101001
1000110111 0001011001
0000111000 1100111001
1000111000 0011001001
0000111001 1001101001
1000111001 1001101001
0000111010 0101101001
1000111010 0101101001
0000111011 1101101001
1000111011 0010011001
0000111100 0011101001
1000111100 0011101001
0000111101 1011101001
1000111101 0100011001
0000111110 0111101001
1000111110 1000011001
0000111111 1010111001
1000111111 0101001001
0001000000 1001110101
1001000000 0110000101
0001000001 0111010101
1001000001 1000100101
0001000010 1011010101
1001000010 0100100101
0001000011 1100010101
1001000011 1100010101
0001000100 1101010101
1001000100 0010100101
0001000101 1010010101
1001000101 1010010101
0001000110 0110010101
1001000110 0110010101
0001000111 1110000101
1001000111 0001110101
0001001000 1110010101
1001001000 0001100101
0001001001 1001010101
1001001001 1001010101
0001001010 0101010101
1001001010 0101010101
0001001011 1101000101
1001001011 1101000101
0001001100 0011010101
1001001100 0011010101
0001001101 1011000101
1001001101 1011000101
0001001110 0111000101
1001001110 0111000101
0001001111 0101110101
1001001111 1010000101
0001010000 0110110101
1001010000 1001000101
0001010001 1000110101
1001010001 1000110101
0001010010 0100110101
1001010010 0100110101
0001010011 1100100101
1001010011 1100100101
0001010100 0010110101
1001010100 0010110101
0001010101 1010100101
1001010101 1010100101
0001010110 0110100101
1001010110 0110100101
0001010111 1110100101
1001010111 0001010101
0001011000 1100110101
1001011000 0011000101
0001011001 1001100101
1001011001 1001100101
0001011010 0101100101
1001011010 0101100101
0001011011 1101100101
1001011011 0010010101
0001011100 0011100101
1001011100 0011100101
0001011101 1011100101
1001011101 0100010101
0001011110 0111100101
1001011110 1000010101
0001011111 1010110101
1001011111 0101000101
0001100000 1001110011
1001100000 0110001100
0001100001 0111010011
1001100001 1000101100
0001100010 1011010011
1001100010 0100101100
0001100011 1100011100
1001100011 1100010011
0001100100 1101010011
1001100100 0010101100
0001100101 1010011100
1001100101 1010010011
0001100110 0110011100
1001100110 0110010011
0001100111 1110001100
1001100111 0001110011
0001101000 1110010011
1001101000 0001101100
0001101001 1001011100
1001101001 1001010011
0001101010 0101011100
1001101010 0101010011
0001101011 1101001100
1001101011 1101000011
0001101100 0011011100
1001101100 0011010011
0001101101 1011001100
1001101101 1011000011
0001101110 0111001100
1001101110 0111000011
0001101111 0101110011
1001101111 1010001100
0001110000 0110110011
1001110000 1001001100
0001110001 1000111100
1001110001 1000110011
0001110010 0100111100
1001110010 0100110011
0001110011 1100101100
1001110011 1100100011
0001110100 0010111100
1001110100 0010110011
0001110101 1010101100
1001110101 1010100011
0001110110 0110101100
1001110110 0110100011
0001110111 1110100011
1001110111 0001011100
0001111000 1100110011
1001111000 0011001100
0001111001 1001101100
1001111001 1001100011
0001111010 0101101100
1001111010 0101100011
0001111011 1101100011
1001111011 0010011100
0001111100 0011101100
1001111100 0011100011
0001111101 1011100011
1001111101 0100011100
0001111110 0111100011
1001111110 1000011100
0001111111 1010110011
1001111111 0101001100
0010000000 1001110010
1010000000 0110001101
0010000001 0111010010
1010000001 1000101101
0010000010 1011010010
1010000010 0100101101
0010000011 1100011101
1010000011 1100010010
0010000100 1101010010
1010000100 0010101101
0010000101 1010011101
1010000101 1010010010
0010000110 0110011101
1010000110 0110010010
0010000111 1110001101
1010000111 0001110010
0010001000 1110010010
1010001000 0001101101
0010001001 1001011101
1010001001 1001010010
0010001010 0101011101
1010001010 0101010010
0010001011 1101001101
1010001011 1101000010
0010001100 0011011101
1010001100 0011010010
0010001101 1011001101
1010001101 1011000010
0010001110 0111001101
1010001110 0111000010
0010001111 0101110010
1010001111 1010001101
0010010000 0110110010
1010010000 1001001101
0010010001 1000111101
1010010001 1000110010
0010010010 0100111101
1010010010 0100110010
0010010011 1100101101
1010010011 1100100010
0010010100 0010111101
1010010100 0010110010
0010010101 1010101101
1010010101 1010100010
0010010110 0110101101
1010010110 0110100010
0010010111 1110100010
1010010111 0001011101
0010011000 1100110010
1010011000 0011001101
0010011001 1001101101
1010011001 1001100010
0010011010 0101101101
1010011010 0101100010
0010011011 1101100010
1010011011 0010011101
0010011100 0011101101
1010011100 0011100010
0010011101 1011100010
1010011101 0100011101
0010011110 0111100010
1010011110 1000011101
0010011111 1010110010
1010011111 0101001101
0010100000 1001111010
1010100000 0110001010
0010100001 0111011010
1010100001 1000101010
0010100010 1011011010
1010100010 0100101010
0010100011 1100011010
1010100011 1100011010
0010100100 1101011010
1010100100 0010101010
0010100101 1010011010
1010100101 1010011010
0010100110 0110011010
1010100110 0110011010
0010100111 1110001010
1010100111 0001111010
0010101000 1110011010
1010101000 0001101010
0010101001 1001011010
1010101001 1001011010
0010101010 0101011010
1010101010 0101011010
0010101011 1101001010
1010101011 1101001010
0010101100 0011011010
1010101100 0011011010
0010101101 1011001010
1010101101 1011001010
0010101110 0111001010
1010101110 0111001010
0010101111 0101111010
1010101111 1010001010
0010110000 0110111010
1010110000 1001001010
0010110001 1000111010
1010110001 1000111010
0010110010 0100111010
1010110010 0100111010
0010110011 1100101010
1010110011 1100101010
0010110100 0010111010
1010110100 0010111010
0010110101 1010101010
1010110101 1010101010
0010110110 0110101010
1010110110 0110101010
0010110111 1110101010
1010110111 0001011010
0010111000 1100111010
1010111000 0011001010
0010111001 1001101010
1010111001 1001101010
0010111010 0101101010
1010111010 0101101010
0010111011 1101101010
1010111011 0010011010
0010111100 0011101010
1010111100 0011101010
0010111101 1011101010
1010111101 0100011010
0010111110 0111101010
1010111110 1000011010
0010111111 1010111010
1010111111 0101001010
0011000000 1001110110
1011000000 0110000110
0011000001 0111010110
1011000001 1000100110
0011000010 1011010110
1011000010 0100100110
0011000011 1100010110
1011000011 1100010110
0011000100 1101010110
1011000100 0010100110
0011000101 1010010110
1011000101 1010010110
0011000110 0110010110
1011000110 0110010110
0011000111 1110000110
1011000111 0001110110
0011001000 1110010110
1011001000 0001100110
0011001001 1001010110
1011001001 1001010110
0011001010 0101010110
1011001010 0101010110
0011001011 1101000110
1011001011 1101000110
0011001100 0011010110
1011001100 0011010110
0011001101 1011000110
1011001101 1011000110
0011001110 0111000110
1011001110 0111000110
0011001111 0101110110
1011001111 1010000110
0011010000 0110110110
1011010000 1001000110
0011010001 1000110110
1011010001 1000110110
0011010010 0100110110
1011010010 0100110110
0011010011 1100100110
1011010011 1100100110
0011010100 0010110110
1011010100 0010110110
0011010101 1010100110
1011010101 1010100110
0011010110 0110100110
1011010110 0110100110
0011010111 1110100110
1011010111 0001010110
0011011000 1100110110
1011011000 0011000110
0011011001 1001100110
1011011001 1001100110
0011011010 0101100110
1011011010 0101100110
0011011011 1101100110
1011011011 0010010110
0011011100 0011100110
1011011100 0011100110
0011011101 1011100110
1011011101 0100010110
0011011110 0111100110
1011011110 1000010110
0011011111 1010110110
1011011111 0101000110
0011100000 1001110001
1011100000 0110001110
0011100001 0111010001
1011100001 1000101110
0011100010 1011010001
1011100010 0100101110
0011100011 1100011110
1011100011 1100010001
0011100100 1101010001
1011100100 0010101110
0011100101 1010011110
1011100101 1010010001
0011100110 0110011110
1011100110 0110010001
0011100111 1110001110
1011100111 0001110001
0011101000 1110010001
1011101000 0001101110
0011101001 1001011110
1011101001 1001010001
0011101010 0101011110
1011101010 0101010001
0011101011 1101001110
1011101011 1101001000
0011101100 0011011110
1011101100 0011010001
0011101101 1011001110
1011101101 1011001000
0011101110 0111001110
1011101110 0111001000
0011101111 0101110001
1011101111 1010001110
0011110000 0110110001
1011110000 1001001110
0011110001 1000110111
1011110001 1000110001
0011110010 0100110111
1011110010 0100110001
0011110011 1100101110
1011110011 1100100001
0011110100 0010110111
1011110100 0010110001
0011110101 1010101110
1011110101 1010100001
0011110110 0110101110
1011110110 0110100001
0011110111 1110100001
1011110111 0001011110
0011111000 1100110001
1011111000 0011001110
0011111001 1001101110
1011111001 1001100001
0011111010 0101101110
1011111010 0101100001
0011111011 1101100001
1011111011 0010011110
0011111100 0011101110
1011111100 0011100001
0011111101 1011100001
1011111101 0100011110
0011111110 0111100001
1011111110 1000011110
0011111111 1010110001
1011111111 0101001110
0100011100 0011110100
1100011100 1100001011
0100111100 0011111001
1100111100 1100000110
0101011100 0011110101
1101011100 1100001010
0101111100 0011110011
1101111100 1100001100
0110011100 0011110010
1110011100 1100001101
0110111100 0011111010
1110111100 1100000101
0111011100 0011110110
1111011100 1100001001
0111111100 0011111000
1111111100 1100000111
0111110111 1110101000
1111110111 0001010111
0111111011 1101101000
1111111011 0010010111
0111111101 1011101000
1111111101 0100010111
0111111110 0111101000
1111111110 1000010111
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_8x10enc.v 0000664 0000000 0000000 00000010047 12572445207 0023237 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: gtx_8x10enc
* Date: 2015-07-11
* Author: Alexey
* Description: 8x10 encoder implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_8x10enc.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* gtx_8x10enc.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
module gtx_8x10enc(
input wire rst,
input wire clk,
input wire [1:0] inisk,
input wire [15:0] indata,
output wire [19:0] outdata
);
// addresses to reference an encoding table
wire [8:0] addr0;
wire [8:0] addr1;
assign addr0 = {inisk[0], indata[7:0]};
assign addr1 = {inisk[1], indata[15:8]};
// possible encoded data - both disparities, for both bytes
// due to registered memory output, this values will be valid after 2 clock cycles
// table[i] [9:0] in case of current disparity +, [19:10] in case of -
wire [31:0] table0_out;
wire [31:0] table1_out;
reg [19:0] table0_r;
reg [19:0] table1_r;
wire [19:0] table0;
wire [19:0] table1;
assign table0 = table0_out[19:0];
assign table1 = table1_out[19:0];
always @ (posedge clk)
begin
table0_r <= table0;
table1_r <= table1;
end
// encoded bytes
wire [9:0] enc0;
wire [9:0] enc1;
//reg [9:0] enc0_r;
//reg [9:0] enc1_r;
// running displarity, 0 = -, 1 = +
reg disparity;
// running disparity after encoding 1st byte
wire disparity_interm;
// invert disparity after a byte
// if current encoded word containg an equal amount of 1s and 0s (i.e. 5 x '1'), disp shall stay the same
// if amounts are unequal, there are either 4 or 6 '1's. in either case disp shall be inverted
wire inv_disp0;
wire inv_disp1;
assign inv_disp0 = ~^enc0;
assign inv_disp1 = ~^enc1;
assign disparity_interm = inv_disp0 ? ~disparity : disparity;
always @ (posedge clk)
disparity <= rst ? 1'b0 : inv_disp1 ^ inv_disp0 ? ~disparity : disparity;
// select encoded bytes depending on a previous disparity
assign enc0 = {10{~disparity}} & table0_r[19:10] | {10{disparity}} & table0_r[9:0];
assign enc1 = {10{~disparity_interm}} & table1_r[19:10] | {10{disparity_interm}} & table1_r[9:0];
// latch output data
reg [19:0] outdata_l;
assign outdata = outdata_l;
always @ (posedge clk)
outdata_l <= {enc1, enc0};
ramt_var_w_var_r #(
.REGISTERS_A (1),
.REGISTERS_B (1),
.LOG2WIDTH_A (5),
.LOG2WIDTH_B (5)
`include "gtx_8x10enc_init.v"
)
encoding_table(
.clk_a (clk),
.addr_a ({1'b0, addr0}),
.en_a (1'b1),
.regen_a (1'b1),
.we_a (1'b0),
.data_out_a (table0_out),
.data_in_a (32'h0),
.clk_b (clk),
.addr_b ({1'b0, addr1}),
.en_b (1'b1),
.regen_b (1'b1),
.we_b (1'b0),
.data_out_b (table1_out),
.data_in_b (32'h0)
);
`ifdef CHECKERS_ENABLED
reg [8:0] addr0_r;
reg [8:0] addr1_r;
reg [8:0] addr0_rr;
reg [8:0] addr1_rr;
always @ (posedge clk)
begin
addr0_r <= addr0;
addr1_r <= addr1;
addr0_rr <= addr0_r;
addr1_rr <= addr1_r;
end
always @ (posedge clk)
if (~rst)
if (|table0 | |table1) begin
// all good
end
else begin
// got xxxx or 0000, both cases tell us addresses were bad
$display("Error in %m: bad incoming data: 1) K = %h, Data = %h 2) K = %h, Data = %h", addr0_rr[8], addr0_rr[7:0], addr1_rr[8], addr1_rr[7:0]);
$finish;
end
`endif // CHECKERS_ENABLED
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_8x10enc_geninit.py 0000664 0000000 0000000 00000001073 12572445207 0025136 0 ustar 00root root 0000000 0000000 mem7f = []
for i in range(0x80):
mem7f.append(0);
for line in open('gtx_8x10enc_init_stub.v').readlines():
addr = int('0b' + line.split()[0], 2)
a = int('0b' + line.split()[1], 2)
b = int('0b' + line.split()[2], 2)
# mem7f[addr >> 3] = (((mem7f[addr >> 3] << 16) + b) << 16) + a
to_mem = (b << 10) + a
# if addr == 0x1bc or addr == 0x4a:
# print addr, ' = ', to_mem, ' : ', b, ' :', a
mem7f[addr >> 3] = mem7f[addr >> 3] + (to_mem << ((addr % 8) * 32))
for i in range(0x80):
print ', .INIT_%02X\t(256\'h%064X)' % (i, mem7f[i])
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_8x10enc_init.v 0000664 0000000 0000000 00000024600 12572445207 0024262 0 ustar 00root root 0000000 0000000 , .INIT_00 (256'h0002E34700029B6600029765000D50AB00028F63000D48AD000D44AE000D18B9)
, .INIT_01 (256'h000D14BA00023B4E0002374D0002B36C00022F4B0002AB6A0002A769000D60A7)
, .INIT_02 (256'h000DA09700025B56000257550002D37400024F530002CB720002C771000D24B6)
, .INIT_03 (256'h000D28B5000D849E000D889D0002735C000D909B00026B5A00026759000D30B3)
, .INIT_04 (256'h0009E24700099A66000996650009526B00098E6300094A6D0009466E00091A79)
, .INIT_05 (256'h0009167A00093A4E0009364D0009B26C00092E4B0009AA6A0009A66900096267)
, .INIT_06 (256'h0009A25700095A56000956550009D27400094E530009CA720009C67100092676)
, .INIT_07 (256'h00092A750009865E00098A5D0009725C0009925B00096A5A0009665900093273)
, .INIT_08 (256'h000AE287000A9AA6000A96A5000A52AB000A8EA3000A4AAD000A46AE000A1AB9)
, .INIT_09 (256'h000A16BA000A3A8E000A368D000AB2AC000A2E8B000AAAAA000AA6A9000A62A7)
, .INIT_0A (256'h000AA297000A5A96000A5695000AD2B4000A4E93000ACAB2000AC6B1000A26B6)
, .INIT_0B (256'h000A2AB5000A869E000A8A9D000A729C000A929B000A6A9A000A6699000A32B3)
, .INIT_0C (256'h000CE0C7000C98E6000C94E50003532B000C8CE300034B2D0003472E00031B39)
, .INIT_0D (256'h0003173A000C38CE000C34CD000CB0EC000C2CCB000CA8EA000CA4E900036327)
, .INIT_0E (256'h0003A317000C58D6000C54D5000CD0F4000C4CD3000CC8F2000CC4F100032736)
, .INIT_0F (256'h00032B350003871E00038B1D000C70DC0003931B000C68DA000C64D900033333)
, .INIT_10 (256'h0004E2C700049AE6000496E5000B512B00048EE3000B492D000B452E000B1939)
, .INIT_11 (256'h000B153A00043ACE000436CD0004B2EC00042ECB0004AAEA0004A6E9000B6127)
, .INIT_12 (256'h000BA11700045AD6000456D50004D2F400044ED30004CAF20004C6F1000B2536)
, .INIT_13 (256'h000B2935000B851E000B891D000472DC000B911B00046ADA000466D9000B3133)
, .INIT_14 (256'h0005E14700059966000595650005516B00058D630005496D0005456E00051979)
, .INIT_15 (256'h0005157A0005394E0005354D0005B16C00052D4B0005A96A0005A56900056167)
, .INIT_16 (256'h0005A15700055956000555550005D17400054D530005C9720005C57100052576)
, .INIT_17 (256'h000529750005855E0005895D0005715C0005915B0005695A0005655900053173)
, .INIT_18 (256'h0006E187000699A6000695A5000651AB00068DA3000649AD000645AE000619B9)
, .INIT_19 (256'h000615BA0006398E0006358D0006B1AC00062D8B0006A9AA0006A5A9000661A7)
, .INIT_1A (256'h0006A19700065996000655950006D1B400064D930006C9B20006C5B1000625B6)
, .INIT_1B (256'h000629B50006859E0006899D0006719C0006919B0006699A00066599000631B3)
, .INIT_1C (256'h0008E1C7000899E6000895E50007522B00088DE300074A2D0007462E00071A39)
, .INIT_1D (256'h0007163A000139CE000135CD0008B1EC00012DCB0008A9EA0008A5E900076227)
, .INIT_1E (256'h0007A217000859D6000855D50008D3B400084DD30008CBB20008C7B100072636)
, .INIT_1F (256'h00072A350007861E00078A1D000871DC0007921B000869DA000865D900073233)
, .INIT_20 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_21 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_22 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_23 (256'h000000000000000000000000000D0CBC00000000000000000000000000000000)
, .INIT_24 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_25 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_26 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_27 (256'h00000000000000000000000000060E7C00000000000000000000000000000000)
, .INIT_28 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_29 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2B (256'h00000000000000000000000000050EBC00000000000000000000000000000000)
, .INIT_2C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2F (256'h00000000000000000000000000030F3C00000000000000000000000000000000)
, .INIT_30 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_31 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_32 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_33 (256'h000000000000000000000000000B0D3C00000000000000000000000000000000)
, .INIT_34 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_35 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_36 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_37 (256'h000000000000000000000000000A0D7C00000000000000000000000000000000)
, .INIT_38 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_39 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3B (256'h00000000000000000000000000090DBC00000000000000000000000000000000)
, .INIT_3C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3E (256'h000EA05700000000000000000000000000000000000000000000000000000000)
, .INIT_3F (256'h00000000000E845E000E885D000E0C7C000E905B000000000000000000000000)
, .INIT_40 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_41 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_42 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_43 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_44 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_45 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_46 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_47 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_48 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_49 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_50 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_51 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_52 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_53 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_54 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_55 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_56 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_57 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_58 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_59 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_60 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_61 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_62 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_63 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_64 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_65 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_66 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_67 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_68 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_69 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_70 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_71 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_72 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_73 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_74 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_75 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_76 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_77 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_78 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_79 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7F (256'h0000000000000000000000000000000000000000000000000000000000000000)
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_8x10enc_init_stub.v 0000664 0000000 0000000 00000047204 12572445207 0025324 0 ustar 00root root 0000000 0000000 000000000 0010111001 1101000110 non-inverted values: 1001110100 0110001011
000000001 0010101110 1101010001 0111010100 1000101011
000000010 0010101101 1101010010 1011010100 0100101011
000000011 1101100011 0010100011 1100011011 1100010100
000000100 0010101011 1101010100 1101010100 0010101011
000000101 1101100101 0010100101 1010011011 1010010100
000000110 1101100110 0010100110 0110011011 0110010100
000000111 1101000111 0010111000 1110001011 0001110100
000001000 0010100111 1101011000 1110010100 0001101011
000001001 1101101001 0010101001 1001011011 1001010100
000001010 1101101010 0010101010 0101011011 0101010100
000001011 1101001011 0010001011 1101001011 1101000100
000001100 1101101100 0010101100 0011011011 0011010100
000001101 1101001101 0010001101 1011001011 1011000100
000001110 1101001110 0010001110 0111001011 0111000100
000001111 0010111010 1101000101 0101110100 1010001011
000010000 0010110110 1101001001 0110110100 1001001011
000010001 1101110001 0010110001 1000111011 1000110100
000010010 1101110010 0010110010 0100111011 0100110100
000010011 1101010011 0010010011 1100101011 1100100100
000010100 1101110100 0010110100 0010111011 0010110100
000010101 1101010101 0010010101 1010101011 1010100100
000010110 1101010110 0010010110 0110101011 0110100100
000010111 0010010111 1101101000 1110100100 0001011011
000011000 0010110011 1101001100 1100110100 0011001011
000011001 1101011001 0010011001 1001101011 1001100100
000011010 1101011010 0010011010 0101101011 0101100100
000011011 0010011011 1101100100 1101100100 0010011011
000011100 1101011100 0010011100 0011101011 0011100100
000011101 0010011101 1101100010 1011100100 0100011011
000011110 0010011110 1101100001 0111100100 1000011011
000011111 0010110101 1101001010 1010110100 0101001011
000100000 1001111001 1001000110 1001111001 0110001001
000100001 1001101110 1001010001 0111011001 1000101001
000100010 1001101101 1001010010 1011011001 0100101001
000100011 1001100011 1001100011 1100011001 1100011001
000100100 1001101011 1001010100 1101011001 0010101001
000100101 1001100101 1001100101 1010011001 1010011001
000100110 1001100110 1001100110 0110011001 0110011001
000100111 1001000111 1001111000 1110001001 0001111001
000101000 1001100111 1001011000 1110011001 0001101001
000101001 1001101001 1001101001 1001011001 1001011001
000101010 1001101010 1001101010 0101011001 0101011001
000101011 1001001011 1001001011 1101001001 1101001001
000101100 1001101100 1001101100 0011011001 0011011001
000101101 1001001101 1001001101 1011001001 1011001001
000101110 1001001110 1001001110 0111001001 0111001001
000101111 1001111010 1001000101 0101111001 1010001001
000110000 1001110110 1001001001 0110111001 1001001001
000110001 1001110001 1001110001 1000111001 1000111001
000110010 1001110010 1001110010 0100111001 0100111001
000110011 1001010011 1001010011 1100101001 1100101001
000110100 1001110100 1001110100 0010111001 0010111001
000110101 1001010101 1001010101 1010101001 1010101001
000110110 1001010110 1001010110 0110101001 0110101001
000110111 1001010111 1001101000 1110101001 0001011001
000111000 1001110011 1001001100 1100111001 0011001001
000111001 1001011001 1001011001 1001101001 1001101001
000111010 1001011010 1001011010 0101101001 0101101001
000111011 1001011011 1001100100 1101101001 0010011001
000111100 1001011100 1001011100 0011101001 0011101001
000111101 1001011101 1001100010 1011101001 0100011001
000111110 1001011110 1001100001 0111101001 1000011001
000111111 1001110101 1001001010 1010111001 0101001001
001000000 1010111001 1010000110 1001110101 0110000101
001000001 1010101110 1010010001 0111010101 1000100101
001000010 1010101101 1010010010 1011010101 0100100101
001000011 1010100011 1010100011 1100010101 1100010101
001000100 1010101011 1010010100 1101010101 0010100101
001000101 1010100101 1010100101 1010010101 1010010101
001000110 1010100110 1010100110 0110010101 0110010101
001000111 1010000111 1010111000 1110000101 0001110101
001001000 1010100111 1010011000 1110010101 0001100101
001001001 1010101001 1010101001 1001010101 1001010101
001001010 1010101010 1010101010 0101010101 0101010101
001001011 1010001011 1010001011 1101000101 1101000101
001001100 1010101100 1010101100 0011010101 0011010101
001001101 1010001101 1010001101 1011000101 1011000101
001001110 1010001110 1010001110 0111000101 0111000101
001001111 1010111010 1010000101 0101110101 1010000101
001010000 1010110110 1010001001 0110110101 1001000101
001010001 1010110001 1010110001 1000110101 1000110101
001010010 1010110010 1010110010 0100110101 0100110101
001010011 1010010011 1010010011 1100100101 1100100101
001010100 1010110100 1010110100 0010110101 0010110101
001010101 1010010101 1010010101 1010100101 1010100101
001010110 1010010110 1010010110 0110100101 0110100101
001010111 1010010111 1010101000 1110100101 0001010101
001011000 1010110011 1010001100 1100110101 0011000101
001011001 1010011001 1010011001 1001100101 1001100101
001011010 1010011010 1010011010 0101100101 0101100101
001011011 1010011011 1010100100 1101100101 0010010101
001011100 1010011100 1010011100 0011100101 0011100101
001011101 1010011101 1010100010 1011100101 0100010101
001011110 1010011110 1010100001 0111100101 1000010101
001011111 1010110101 1010001010 1010110101 0101000101
001100000 1100111001 0011000110 1001110011 0110001100
001100001 1100101110 0011010001 0111010011 1000101100
001100010 1100101101 0011010010 1011010011 0100101100
001100011 0011100011 1100100011 1100011100 1100010011
001100100 1100101011 0011010100 1101010011 0010101100
001100101 0011100101 1100100101 1010011100 1010010011
001100110 0011100110 1100100110 0110011100 0110010011
001100111 0011000111 1100111000 1110001100 0001110011
001101000 1100100111 0011011000 1110010011 0001101100
001101001 0011101001 1100101001 1001011100 1001010011
001101010 0011101010 1100101010 0101011100 0101010011
001101011 0011001011 1100001011 1101001100 1101000011
001101100 0011101100 1100101100 0011011100 0011010011
001101101 0011001101 1100001101 1011001100 1011000011
001101110 0011001110 1100001110 0111001100 0111000011
001101111 1100111010 0011000101 0101110011 1010001100
001110000 1100110110 0011001001 0110110011 1001001100
001110001 0011110001 1100110001 1000111100 1000110011
001110010 0011110010 1100110010 0100111100 0100110011
001110011 0011010011 1100010011 1100101100 1100100011
001110100 0011110100 1100110100 0010111100 0010110011
001110101 0011010101 1100010101 1010101100 1010100011
001110110 0011010110 1100010110 0110101100 0110100011
001110111 1100010111 0011101000 1110100011 0001011100
001111000 1100110011 0011001100 1100110011 0011001100
001111001 0011011001 1100011001 1001101100 1001100011
001111010 0011011010 1100011010 0101101100 0101100011
001111011 1100011011 0011100100 1101100011 0010011100
001111100 0011011100 1100011100 0011101100 0011100011
001111101 1100011101 0011100010 1011100011 0100011100
001111110 1100011110 0011100001 0111100011 1000011100
001111111 1100110101 0011001010 1010110011 0101001100
010000000 0100111001 1011000110 1001110010 0110001101
010000001 0100101110 1011010001 0111010010 1000101101
010000010 0100101101 1011010010 1011010010 0100101101
010000011 1011100011 0100100011 1100011101 1100010010
010000100 0100101011 1011010100 1101010010 0010101101
010000101 1011100101 0100100101 1010011101 1010010010
010000110 1011100110 0100100110 0110011101 0110010010
010000111 1011000111 0100111000 1110001101 0001110010
010001000 0100100111 1011011000 1110010010 0001101101
010001001 1011101001 0100101001 1001011101 1001010010
010001010 1011101010 0100101010 0101011101 0101010010
010001011 1011001011 0100001011 1101001101 1101000010
010001100 1011101100 0100101100 0011011101 0011010010
010001101 1011001101 0100001101 1011001101 1011000010
010001110 1011001110 0100001110 0111001101 0111000010
010001111 0100111010 1011000101 0101110010 1010001101
010010000 0100110110 1011001001 0110110010 1001001101
010010001 1011110001 0100110001 1000111101 1000110010
010010010 1011110010 0100110010 0100111101 0100110010
010010011 1011010011 0100010011 1100101101 1100100010
010010100 1011110100 0100110100 0010111101 0010110010
010010101 1011010101 0100010101 1010101101 1010100010
010010110 1011010110 0100010110 0110101101 0110100010
010010111 0100010111 1011101000 1110100010 0001011101
010011000 0100110011 1011001100 1100110010 0011001101
010011001 1011011001 0100011001 1001101101 1001100010
010011010 1011011010 0100011010 0101101101 0101100010
010011011 0100011011 1011100100 1101100010 0010011101
010011100 1011011100 0100011100 0011101101 0011100010
010011101 0100011101 1011100010 1011100010 0100011101
010011110 0100011110 1011100001 0111100010 1000011101
010011111 0100110101 1011001010 1010110010 0101001101
010100000 0101111001 0101000110 1001111010 0110001010
010100001 0101101110 0101010001 0111011010 1000101010
010100010 0101101101 0101010010 1011011010 0100101010
010100011 0101100011 0101100011 1100011010 1100011010
010100100 0101101011 0101010100 1101011010 0010101010
010100101 0101100101 0101100101 1010011010 1010011010
010100110 0101100110 0101100110 0110011010 0110011010
010100111 0101000111 0101111000 1110001010 0001111010
010101000 0101100111 0101011000 1110011010 0001101010
010101001 0101101001 0101101001 1001011010 1001011010
010101010 0101101010 0101101010 0101011010 0101011010
010101011 0101001011 0101001011 1101001010 1101001010
010101100 0101101100 0101101100 0011011010 0011011010
010101101 0101001101 0101001101 1011001010 1011001010
010101110 0101001110 0101001110 0111001010 0111001010
010101111 0101111010 0101000101 0101111010 1010001010
010110000 0101110110 0101001001 0110111010 1001001010
010110001 0101110001 0101110001 1000111010 1000111010
010110010 0101110010 0101110010 0100111010 0100111010
010110011 0101010011 0101010011 1100101010 1100101010
010110100 0101110100 0101110100 0010111010 0010111010
010110101 0101010101 0101010101 1010101010 1010101010
010110110 0101010110 0101010110 0110101010 0110101010
010110111 0101010111 0101101000 1110101010 0001011010
010111000 0101110011 0101001100 1100111010 0011001010
010111001 0101011001 0101011001 1001101010 1001101010
010111010 0101011010 0101011010 0101101010 0101101010
010111011 0101011011 0101100100 1101101010 0010011010
010111100 0101011100 0101011100 0011101010 0011101010
010111101 0101011101 0101100010 1011101010 0100011010
010111110 0101011110 0101100001 0111101010 1000011010
010111111 0101110101 0101001010 1010111010 0101001010
011000000 0110111001 0110000110 1001110110 0110000110
011000001 0110101110 0110010001 0111010110 1000100110
011000010 0110101101 0110010010 1011010110 0100100110
011000011 0110100011 0110100011 1100010110 1100010110
011000100 0110101011 0110010100 1101010110 0010100110
011000101 0110100101 0110100101 1010010110 1010010110
011000110 0110100110 0110100110 0110010110 0110010110
011000111 0110000111 0110111000 1110000110 0001110110
011001000 0110100111 0110011000 1110010110 0001100110
011001001 0110101001 0110101001 1001010110 1001010110
011001010 0110101010 0110101010 0101010110 0101010110
011001011 0110001011 0110001011 1101000110 1101000110
011001100 0110101100 0110101100 0011010110 0011010110
011001101 0110001101 0110001101 1011000110 1011000110
011001110 0110001110 0110001110 0111000110 0111000110
011001111 0110111010 0110000101 0101110110 1010000110
011010000 0110110110 0110001001 0110110110 1001000110
011010001 0110110001 0110110001 1000110110 1000110110
011010010 0110110010 0110110010 0100110110 0100110110
011010011 0110010011 0110010011 1100100110 1100100110
011010100 0110110100 0110110100 0010110110 0010110110
011010101 0110010101 0110010101 1010100110 1010100110
011010110 0110010110 0110010110 0110100110 0110100110
011010111 0110010111 0110101000 1110100110 0001010110
011011000 0110110011 0110001100 1100110110 0011000110
011011001 0110011001 0110011001 1001100110 1001100110
011011010 0110011010 0110011010 0101100110 0101100110
011011011 0110011011 0110100100 1101100110 0010010110
011011100 0110011100 0110011100 0011100110 0011100110
011011101 0110011101 0110100010 1011100110 0100010110
011011110 0110011110 0110100001 0111100110 1000010110
011011111 0110110101 0110001010 1010110110 0101000110
011100000 1000111001 0111000110 1001110001 0110001110
011100001 1000101110 0111010001 0111010001 1000101110
011100010 1000101101 0111010010 1011010001 0100101110
011100011 0111100011 1000100011 1100011110 1100010001
011100100 1000101011 0111010100 1101010001 0010101110
011100101 0111100101 1000100101 1010011110 1010010001
011100110 0111100110 1000100110 0110011110 0110010001
011100111 0111000111 1000111000 1110001110 0001110001
011101000 1000100111 0111011000 1110010001 0001101110
011101001 0111101001 1000101001 1001011110 1001010001
011101010 0111101010 1000101010 0101011110 0101010001
011101011 0111001011 0001001011 1101001110 1101001000
011101100 0111101100 1000101100 0011011110 0011010001
011101101 0111001101 0001001101 1011001110 1011001000
011101110 0111001110 0001001110 0111001110 0111001000
011101111 1000111010 0111000101 0101110001 1010001110
011110000 1000110110 0111001001 0110110001 1001001110
011110001 1110110001 1000110001 1000110111 1000110001
011110010 1110110010 1000110010 0100110111 0100110001
011110011 0111010011 1000010011 1100101110 1100100001
011110100 1110110100 1000110100 0010110111 0010110001
011110101 0111010101 1000010101 1010101110 1010100001
011110110 0111010110 1000010110 0110101110 0110100001
011110111 1000010111 0111101000 1110100001 0001011110
011111000 1000110011 0111001100 1100110001 0011001110
011111001 0111011001 1000011001 1001101110 1001100001
011111010 0111011010 1000011010 0101101110 0101100001
011111011 1000011011 0111100100 1101100001 0010011110
011111100 0111011100 1000011100 0011101110 0011100001
011111101 1000011101 0111100010 1011100001 0100011110
011111110 1000011110 0111100001 0111100001 1000011110
011111111 1000110101 0111001010 1010110001 0101001110
100011100 0010111100 1101000011 0011110100 1100001011
100111100 1001111100 0110000011 0011111001 1100000110
101011100 1010111100 0101000011 0011110101 1100001010
101111100 1100111100 0011000011 0011110011 1100001100
110011100 0100111100 1011000011 0011110010 1100001101
110111100 0101111100 1010000011 0011111010 1100000101
111011100 0110111100 1001000011 0011110110 1100001001
111111100 0001111100 1110000011 0011111000 1100000111
111110111 0001010111 1110101000 1110101000 0001010111
111111011 0001011011 1110100100 1101101000 0010010111
111111101 0001011101 1110100010 1011101000 0100010111
111111110 0001011110 1110100001 0111101000 1000010111
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_comma_align.v 0000664 0000000 0000000 00000012252 12572445207 0024317 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: gtx_comma_align
* Date: 2015-07-11
* Author: Alexey
* Description: comma aligner implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_comma_align.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* gtx_comma_align.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
module gtx_comma_align(
input wire rst,
input wire clk,
// input data comes this way (standart 8/10 bit notation)
// cycle 0: {[hgfedcba]=1st byte,[hgfedcba]=0st byte}
// cycle 1: {[hgfedcba]=3rd byte,[hgfedcba]=2dn byte}
// => {[cycle1 data], [cycle0 data]} = as if we were reading by dwords
input wire [19:0] indata,
output wire [19:0] outdata,
// outdata contains comma
output wire comma,
// pulse, indicating that stream was once again adjusted to a comma
// if asserted after link was down - OK
// if asserted during a work - most likely indicates an error in a stream
output wire realign
// asserted when input stream looks like comma, but it is not
// later on after 10/8 it would get something link NOTINTHETABLE error anyways
// output wire error
);
// only comma character = K28.5, has 5 '1's or 5 '0's in a row.
// after we met it, call it a comma group, we could compare other symbols
/*
// create a window
reg [19:0] indata_r;
wire [23:0] window;
always @ (posedge clk)
indata_r <= indata;
assign window = {indata_r[17:0], indata[19:14]};
// search for a comma group - parallel 24-bit window into 20 5-bit words
// transposed -> 5 x 20-bit words
wire [19:0] lane0;
wire [19:0] lane1;
wire [19:0] lane2;
wire [19:0] lane3;
wire [19:0] lane4;
assign lane0 = window[19:0];
assign lane1 = window[20:1];
assign lane2 = window[21:2];
assign lane3 = window[22:3];
assign lane4 = window[23:4];
// calcute at what position in a window comma group is detected,
// so the position in actual {indata_r, indata} would be +2 from the left side
wire [19:0] comma_pos;
assign comma_pos = lane0 & lane1 & lane2 & lane3 & lane4;
*/
// seach for a comma
// TODO make it less expensive
reg [19:0] indata_r;
wire [38:0] window;
always @ (posedge clk)
indata_r <= indata;
assign window = {indata, indata_r};
// there is only 1 matched subwindow due to 20-bit comma's non-repetative pattern
wire [19:0] subwindow [19:0];
wire [19:0] comma_match;
wire [19:0] comma_match_p;
reg [19:0] aligned_data;
reg [19:0] comma_match_prev;
wire comma_detected;
wire [19:0] comma_p = 20'b10101010100101111100;
wire [19:0] comma_n = 20'b10101010101010000011;
genvar ii;
generate
for (ii = 0; ii < 20; ii = ii + 1)
begin: look_for_comma
assign subwindow[ii] = window[ii + 19:ii];
// assign comma_match[ii] = subwindow[ii] == 20'b01010101010011111010 | subwindow[ii] == 20'b01010101011100000101;
// stream comes inverted
assign comma_match_p[ii] = subwindow[ii] == comma_p;
assign comma_match[ii] = comma_match_p[ii] | subwindow[ii] == comma_n;
end
endgenerate
assign comma_detected = |comma_match;
// save the shift count
always @ (posedge clk)
comma_match_prev <= rst ? 20'h1 : comma_detected ? comma_match : comma_match_prev;
// shift
/* TODO
wire [38:0] shifted_window;
assign shifted_window = comma_detected ? {window >> (comma_match - 1)} : {window >> (comma_match_prev - 1)};
*/
// temp shift
wire [19:0] shifted_window;
wire [19:0] ored_subwindow [19:0];
wire [19:0] ored_subwindow_comdet [19:0];
assign ored_subwindow_comdet[0] = {20{comma_match_p[0]}} & comma_p | {20{~comma_match_p[0] & comma_match[0]}} & comma_n;
assign ored_subwindow[0] = {20{comma_match_prev[0]}} & subwindow[0];
generate
for (ii = 1; ii < 20; ii = ii + 1)
begin: or_all_possible_windows
assign ored_subwindow_comdet[ii] = {20{comma_match_p[ii]}} & comma_p | {20{~comma_match_p[ii] & comma_match[ii]}} & comma_n | ored_subwindow_comdet[ii-1];
assign ored_subwindow[ii] = {20{comma_match_prev[ii]}} & subwindow[ii] | ored_subwindow[ii-1];
end
endgenerate
assign shifted_window = comma_detected ? ored_subwindow_comdet[19] : ored_subwindow[19];
always @ (posedge clk)
// aligned_data <= comma_detected ? {window >> (comma_match - 1)}[19:0] : {window >> (comma_match_prev - 1)}[19:0];
aligned_data <= shifted_window[19:0];
// form outputs
assign comma = comma_detected;
assign realign = comma_detected & |(comma_match_prev ^ comma_match);
assign outdata = aligned_data;
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_elastic.v 0000664 0000000 0000000 00000034471 12572445207 0023504 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: gtx_elastic
* Date: 2015-07-11
* Author: Alexey
* Description: elastic buffer implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_elastic.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* gtx_elastic.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
module gtx_elastic #(
parameter DEPTH_LOG2 = 3, // => 8 total rows
parameter OFFSET = 4 // distance between read and write pointers, = wr_ptr - rd_ptr
)
(
input wire rst,
input wire wclk,
input wire rclk,
input wire isaligned_in,
input wire [1:0] charisk_in,
input wire [1:0] notintable_in,
input wire [1:0] disperror_in,
input wire [15:0] data_in,
output wire isaligned_out,
output wire [1:0] charisk_out,
output wire [1:0] notintable_out,
output wire [1:0] disperror_out,
output wire [15:0] data_out,
// strobes LAST word in a dword primitive
output wire lword_strobe,
// status outputs, just in case
output wire full,
output wire empty
);
// gather inputs and outputs
wire [22:0] indata;
wire [22:0] outdata;
assign indata = {isaligned_in, notintable_in, disperror_in, charisk_in, data_in};
assign isaligned_out = outdata[22];
assign notintable_out = outdata[21:20];
assign disperror_out = outdata[19:18];
assign charisk_out = outdata[17:16];
assign data_out = outdata[15:0];
localparam HI = DEPTH_LOG2 - 1; // hi bus index
/*
* buffer itself
*/
// data storage
reg [22:0] ram [(1 << DEPTH_LOG2) - 1:0];
// data to/from fifo
wire [22:0] inram;
wire [22:0] outram;
// adresses in their natural clock domains
reg [HI:0] rd_addr;
reg [HI:0] wr_addr;
// incremened addresses
wire [HI:0] wr_next_addr;
wire [HI:0] rd_next_addr;
// gray coded addresses
reg [HI:0] rd_addr_gr;
reg [HI:0] wr_addr_gr;
// anti-metastability shift registers for gray-coded addresses
reg [HI:0] rd_addr_gr_r;
reg [HI:0] wr_addr_gr_r;
reg [HI:0] rd_addr_gr_rr;
reg [HI:0] wr_addr_gr_rr;
// resynced to opposite clks addresses
wire [HI:0] rd_addr_r;
wire [HI:0] wr_addr_r;
// fifo states
//wire full; // MAY BE full. ~full -> MUST NOT be full
//wire empty; // MAY BE empty. ~empty -> MUST NOT be empty
wire re;
wire we;
assign wr_next_addr = wr_addr + 1'b1;
assign rd_next_addr = rd_addr + 1'b1;
// wclk domain counters
always @ (posedge wclk)
begin
wr_addr <= rst ? {DEPTH_LOG2{1'b0}} : we ? wr_next_addr : wr_addr;
wr_addr_gr <= rst ? {DEPTH_LOG2{1'b0}} : we ? wr_next_addr ^ {1'b0, wr_next_addr[HI:1]} : wr_addr_gr;
end
// rclk domain counters
always @ (posedge rclk)
begin
rd_addr <= rst ? {DEPTH_LOG2{1'b0}} : re ? rd_next_addr : rd_addr;
rd_addr_gr <= rst ? {DEPTH_LOG2{1'b0}} : re ? rd_next_addr ^ {1'b0, rd_next_addr[HI:1]} : rd_addr_gr;
end
// write address -> rclk (rd) domain to compare
always @ (posedge rclk)
begin
wr_addr_gr_r <= rst ? {DEPTH_LOG2{1'b0}} : wr_addr_gr;
wr_addr_gr_rr <= rst ? {DEPTH_LOG2{1'b0}} : wr_addr_gr_r;
end
// read address -> wclk (wr) domain to compare
always @ (posedge wclk)
begin
rd_addr_gr_r <= rst ? {DEPTH_LOG2{1'b0}} : rd_addr_gr;
rd_addr_gr_rr <= rst ? {DEPTH_LOG2{1'b0}} : rd_addr_gr_r;
end
// translate resynced write address into ordinary (non-gray) address
genvar ii;
generate
for (ii = 0; ii <= HI; ii = ii + 1)
begin: wr_antigray
assign wr_addr_r[ii] = ^wr_addr_gr_rr[HI:ii];
end
endgenerate
// translate resynced read address into ordinary (non-gray) address
generate
for (ii = 0; ii <= HI; ii = ii + 1)
begin: rd_antigray
assign rd_addr_r[ii] = ^rd_addr_gr_rr[HI:ii];
end
endgenerate
// so we've got the following:
// wclk domain: wr_addr - current write address
// rd_addr_r - read address some wclk ticks ago
// => we can say if the fifo have the possibility to be full
// since actual rd_addr could only be incremented
//
// rclk domain: rd_addr - current read address
// wr_addr_r - write address some rclk ticks ago
// => we can say if the fifo have the possibility to be empty
// since actual wr_addr could only be incremented
assign full = {wr_addr, 1'b0} == rd_addr_r + 1'b1;
assign empty = {wr_addr_r, 1'b0} == rd_addr;
assign outram = ram[rd_addr];
always @ (posedge wclk)
if (we)
ram[wr_addr] <= inram;
// elactic part
// control fifo state @ rclk domain
// sends a pulse to wclk domain for every necessary ALIGNP removal
// waits for response from wclk domain of a successful removal
// pauses fifo read and inserts ALIGNP
// @ rclk
// calculating an offset - a distance between write and read pointers
wire [HI:0] current_offset;
assign current_offset = wr_addr_r - rd_addr;
// more records in fifo than expected on 1 primitive = 2 words = 2 records
wire offset_more_on_1;
// more records in fifo than expected on 2 primitives or more = 4 words + = 4 records +
wire offset_more_on_2;
// less records than expected - can insert a lot of alignes instantly, so exact count is not important
wire offset_less;
// doesnt bother if offset is more on 1 word.
assign offset_more_on_1 = current_offset == (OFFSET + 2) | current_offset == (OFFSET + 3);
assign offset_more_on_2 = (current_offset > (OFFSET + 1)) & ~offset_more_on_1;
assign offset_less = current_offset < OFFSET;
`ifdef ENABLE_CHECKERS
always @ (posedge clk)
if (offset_less & (offset_more_on_1 | offset_more_on_1)) begin
$display("Error in %m. Wrong offset calculations");
$finish;
end
`endif
/*
* Case when we need to get rid of extra elements in fifo
*/
// control part @ rclk
wire rmv_ack_rclk;
wire state_idle_rmv;
reg state_rmv1_req;
reg state_rmv2_req;
reg state_wait_ack;
wire set_rmv1_req;
wire set_rmv2_req;
wire set_wait_ack;
wire clr_rmv1_req;
wire clr_rmv2_req;
wire clr_wait_ack;
assign state_idle_rmv = ~state_rmv1_req & ~state_rmv2_req & ~state_wait_ack;
assign set_rmv1_req = state_idle_rmv & offset_more_on_1;
assign set_rmv2_req = state_idle_rmv & offset_more_on_2;
assign set_wait_ack = state_rmv1_req | state_rmv2_req;
assign clr_rmv1_req = set_wait_ack;
assign clr_rmv2_req = set_wait_ack;
assign clr_wait_ack = rmv_ack_rclk;
always @ (posedge rclk)
begin
state_rmv1_req <= (state_rmv1_req | set_rmv1_req) & ~clr_rmv1_req & ~rst;
state_rmv2_req <= (state_rmv2_req | set_rmv2_req) & ~clr_rmv2_req & ~rst;
state_wait_ack <= (state_wait_ack | set_wait_ack) & ~clr_wait_ack & ~rst;
end
`ifdef ENABLE_CHECKERS
always @ (posedge rclk)
if (~rst)
if ((4'h0
+ state_rmv1_req
+ state_rmv2_req
+ state_wait_ack
+ state_idle_rmv
) == 4'h1) begin
// all good
end
else
begin
$display("Error in %m: wrong fsm states: %b", {state_rmv1_req, state_rmv2_req, state_wait_ack, state_idle_rmv});
$finish;
end
`endif
// align removal logic @ wclk
// we MUST compare current and next data pack even if the current one is a comma because
// the next data word could be either valid ALIGNP's or any other 2 bytes, which shall tell
// link layer that incorrect primitive has been received, so it can't be skipped
// also NO DISPARITY ERROR would be dropped
reg [22:0] indata_r;
always @ (posedge wclk)
indata_r <= indata;
// align is stored in a buffer right now
// ALIGNP = 7B4A4ABC
// charisk : 0 0 0 1
// notintbl: 0 0 0 0
// disperr: 0 0 0 0
wire align_det;
assign align_det = {indata[15:0], indata_r[15:0]} == 32'h7B4A4ABC
& {indata[17:16], indata_r[17:16]} == 4'b0001
& {indata[19:18], indata_r[19:18]} == 4'b0000
& {indata[21:20], indata_r[21:20]} == 4'b0000;
// fsm
/*
* bypass --req1--> wait for align --------------------------------------------------------> skip 1 primitive -> send ack -> bypass
* \ | /\
* req2--> wait for align -> skip 1 primitive -> wait until next ------align in buf--+ |
* prim is in buffer --not align in buf------------------------------+
*/
wire skip_write;
wire rmv1_req_wclk;
wire rmv2_req_wclk;
reg next_prim_loaded;
always @ (wclk)
next_prim_loaded <= state_wait_next_p;
wire state_bypass_rmv;
reg state_wait1_align;
reg state_skip1_align;
reg state_wait2_align;
reg state_skip2_align;
reg state_wait_next_p;
reg state_send_ack;
wire set_wait1_align;
wire set_skip1_align;
wire set_wait2_align;
wire set_skip2_align;
wire set_wait_next_p;
wire set_send_ack;
wire clr_wait1_align;
wire clr_skip1_align;
wire clr_wait2_align;
wire clr_skip2_align;
wire clr_wait_next_p;
wire clr_send_ack;
assign state_bypass_rmv = ~state_wait1_align & ~state_skip1_align & ~state_wait2_align & ~state_skip2_align & ~state_wait_next_p & ~state_send_ack;
assign set_wait1_align = state_bypass_rmv & rmv1_req_wclk & ~rmv2_req_wclk;
assign set_skip1_align = state_wait1_align & align_det | state_wait_next_p & next_prim_loaded & align_det;
assign set_wait2_align = state_bypass_rmv & rmv2_req_wclk;
assign set_skip2_align = state_wait2_align & align_det;
assign set_wait_next_p = state_skip2_align;
assign set_send_ack = state_skip1_align | state_wait_next_p & next_prim_loaded & ~align_det; // 1 cycle skip - while set_skip1, 2nd cycle - while state_skip1
assign clr_wait1_align = set_skip1_align;
assign clr_skip1_align = set_send_ack;
assign clr_wait2_align = set_skip2_align;
assign clr_skip2_align = set_wait_next_p;
assign clr_wait_next_p = set_send_ack | set_skip1_align;
assign clr_send_ack = state_send_ack;
always @ (posedge wclk)
begin
state_wait1_align <= (state_wait1_align | set_wait1_align) & ~clr_wait1_align & ~rst;
state_skip1_align <= (state_skip1_align | set_skip1_align) & ~clr_skip1_align & ~rst;
state_wait2_align <= (state_wait2_align | set_wait2_align) & ~clr_wait2_align & ~rst;
state_skip2_align <= (state_skip2_align | set_skip2_align) & ~clr_skip2_align & ~rst;
state_wait_next_p <= (state_wait_next_p | set_wait_next_p) & ~clr_wait_next_p & ~rst;
state_send_ack <= (state_send_ack | set_send_ack ) & ~clr_send_ack & ~rst;
end
assign skip_write = set_skip1_align | state_skip1_align;
assign inram = indata_r;
assign we = ~skip_write;
// cross-domain messaging
// just to simplify an algorithm, we don't serialize a request to remove 2 ALIGNP,
// instead make 2 independent request lines
pulse_cross_clock remove1_req(
.rst (rst),
.src_clk (rclk),
.dst_clk (wclk),
.in_pulse (state_rmv1_req),
.out_pulse (rmv1_req_wclk),
.busy ()
);
pulse_cross_clock remove2_req(
.rst (rst),
.src_clk (rclk),
.dst_clk (wclk),
.in_pulse (state_rmv2_req),
.out_pulse (rmv2_req_wclk),
.busy ()
);
// removal request ack
pulse_cross_clock remove_ack(
.rst (rst),
.src_clk (wclk),
.dst_clk (rclk),
.in_pulse (state_send_ack),
.out_pulse (rmv_ack_rclk),
.busy ()
);
// insert additional ALINGPs to head @ rclk
// 1 way to implement - search for align primitive at the head of fifo, and insert enough alignes right after detected one
// 2nd way - continiously send a pulse, indicating 1st word of each primitive.
// Choosing the 1st way
// start algorithm after fifo gets in a stable state - let it fill to predefined offset count
reg fifo_stable;
always @ (posedge rclk)
fifo_stable <= rst ? 1'b0 : ~fifo_stable & ~offset_less | fifo_stable;
// once again check if the current half-primitive is a part of an align
// no need to latch the whole outram
// indicator, that @ previous clock cycle there was a first word of ALIGNP
reg align_1st;
always @ (posedge rclk)
align_1st <= outram[15:0] == 16'h4ABC
& outram[17:16] == 2'b01
& outram[19:18] == 2'b00
& outram[21:20] == 2'b00;
// indicates that current word is a second word of ALIGNP
wire align_2nd;
assign align_2nd = outram[15:0] == 16'h7B4A
& outram[17:16] == 2'b00
& outram[19:18] == 2'b00
& outram[21:20] == 2'b00;
// whole align primitive is the last thing we read from fifo
reg read_align;
always @ (posedge rclk)
read_align <= rst ? 1'b0 : pause_read | align_1st & align_2nd;
// just to alternate alignp's words, = 0 => 1st word, = 1 => 2nd word
reg align_altern;
wire pause_read;
// also pause when offset gets ok, but only 1st word of alignp is sent - need to send 2nd word
assign pause_read = read_align & offset_less & fifo_stable | align_altern;
always @ (posedge rclk)
align_altern <= rst | ~pause_read ? 1'b0 : ~align_altern;
// choose 1 of 2 words of ALIGNP
wire [22:0] align_word;
assign align_word = {outram[22], 22'h007B4A} & {23{~align_altern}} | {outram[22], 22'h014ABC} & {23{align_altern}};
// read when compensation is not issued and when fifo gets required fullfillment
assign re = ~pause_read & fifo_stable;
assign outdata = {23{~pause_read}} & outram | {23{pause_read}} & align_word;
// indicates last cycle before the next primitive
wire fword_strobe_correction;
reg fword_strobe;
`ifdef SIMULATION
assign fword_strobe_correction = (align_1st === 1'bx || align_2nd === 1'bx) ? 1'b0 : align_1st & align_2nd ;
`else
assign fword_strobe_correction = align_1st & align_2nd;
`endif
always @ (posedge rclk)
fword_strobe <= rst ? 1'b0 : fword_strobe_correction ? 1'b1 : lword_strobe;
assign lword_strobe = ~fword_strobe;
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/gtx_wrap.v 0000664 0000000 0000000 00000105645 12572445207 0023033 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: gtx_wrap
* Date: 2015-08-24
* Author: Alexey
* Description: shall replace gtx's PCS part functions, bypassing PCS itself in gtx
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_wrap.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* gtx_wrap.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`include "gtx_8x10enc.v"
`include "gtx_10x8dec.v"
`include "gtx_comma_align.v"
`include "gtx_elastic.v"
// All computations have been done in assumption of GTX interface being 20 bits wide!
module gtx_wrap #(
parameter DATA_BYTE_WIDTH = 4,
parameter TXPMARESET_TIME = 5'h1,
parameter RXPMARESET_TIME = 5'h11,
parameter RXCDRPHRESET_TIME = 5'h1,
parameter RXCDRFREQRESET_TIME = 5'h1,
parameter RXDFELPMRESET_TIME = 7'hf,
parameter RXISCANRESET_TIME = 5'h1,
parameter RXEYERESET_TIME = 7'h25
)
(
output wire cplllock,
input wire cplllockdetclk,
input wire cpllreset,
input wire gtrefclk,
input wire drpclk,
input wire rxuserrdy,
input wire txuserrdy,
input wire rxusrclk,
input wire rxusrclk2,
input wire rxp,
input wire rxn,
output wire rxbyteisaligned,
input wire rxreset,
output wire rxcomwakedet,
output wire rxcominitdet,
output wire rxelecidle,
output wire rxresetdone,
input wire txreset,
input wire txusrclk,
input wire txusrclk2,
input wire txelecidle,
output wire txp,
output wire txn,
output wire txoutclk,
input wire txpcsreset,
output wire txresetdone,
input wire txcominit,
input wire txcomwake,
// elastic buffer status
output wire rxelsfull,
output wire rxelsempty,
input wire [DATA_BYTE_WIDTH * 8 - 1:0] txdata,
input wire [DATA_BYTE_WIDTH - 1:0] txcharisk,
output wire [DATA_BYTE_WIDTH * 8 - 1:0] rxdata,
output wire [DATA_BYTE_WIDTH - 1:0] rxcharisk,
output wire [DATA_BYTE_WIDTH - 1:0] rxnotintable,
output wire [DATA_BYTE_WIDTH - 1:0] rxdisperr
);
// resets while PCS resets
assign wrap_rxreset_ = rxuserrdy & rxresetdone_gtx;
assign wrap_txreset_ = txuserrdy & txresetdone_gtx;
wire [63:0] rxdata_gtx;
wire [7:0] rxcharisk_gtx;
wire [7:0] rxdisperr_gtx;
wire [63:0] txdata_gtx;
wire [7:0] txcharisk_gtx;
wire [7:0] txchardispval_gtx;
wire [7:0] txchardispmode_gtx;
// 8/10 encoder ifaces
wire [19:0] txdata_enc_out;
wire [15:0] txdata_enc_in;
wire [1:0] txcharisk_enc_in;
/*
* TX PCS, minor changes: 8/10 encoder + user interface resync
*/
// assuming GTX interface width = 20 bits
assign txdata_gtx = {48'h0, txdata_enc_out[17:10], txdata_enc_out[7:0]};
assign txcharisk_gtx = 8'h0; // 8/10 encoder is bypassed in gtx
assign txchardispmode_gtx = {6'h0, txdata_enc_out[19], txdata_enc_out[9]};
assign txchardispval_gtx = {6'h0, txdata_enc_out[18], txdata_enc_out[8]};
// Interface part
/*
input wire cpllreset, - async
input wire wrap_rxreset_, - async
input wire wrap_txreset_, - async
input wire rxreset, - async
input wire txreset, - async
input wire txelecidle, - txusrclk2 - need to resync to gtx iface clk - txusrclk
input wire txpcsreset, - async
input wire txcominit, - txusrclk2 - need to resync to gtx iface clk - txusrclk
input wire txcomwake, - txusrclk2 - need to resync to gtx iface clk - txusrclk
*/
// @ gtx iface clk
wire txcominit_gtx;
wire txcomwake_gtx;
wire txelecidle_gtx;
// insert resync if it's necessary
generate
if (DATA_BYTE_WIDTH == 4) begin
// resync to txusrclk
// 2*Fin = Fout => WIDTHin = 2*WIDTHout
wire txdata_resync_nempty;
reg txdata_resync_nempty_r;
reg txdata_resync_nempty_rr;
reg txdata_resync_strobe;
wire [38:0] txdata_resync_out;
reg [35:0] txdata_resync;
assign txdata_enc_in = {16{~txdata_resync_strobe}} & txdata_resync[15:0] | {16{txdata_resync_strobe}} & txdata_resync[31:16];
assign txcharisk_enc_in = {2{~txdata_resync_strobe}} & txdata_resync[33:32] | {2{txdata_resync_strobe}} & txdata_resync[35:34];
always @ (posedge txusrclk)
begin
txdata_resync <= ~wrap_txreset_ ? 36'h0 : txdata_resync_nempty & txdata_resync_strobe ? txdata_resync_out[35:0] : txdata_resync;
txdata_resync_strobe <= ~wrap_txreset_ ? 1'b0 : ~txdata_resync_nempty ? txdata_resync_strobe : ~txdata_resync_strobe; // -> 1 once every resynced dword = signal to latch it
end
// nempty_rr & nempty => shall be at least 2 elements in fifo - safe to read
always @ (posedge txusrclk2)
begin
txdata_resync_nempty_r <= txdata_resync_nempty;
txdata_resync_nempty_rr <= txdata_resync_nempty_r;
end
fifo_cross_clocks #(
.DATA_WIDTH (39),
.DATA_DEPTH (4)
)
txdata_resynchro(
.rst (txreset),
.rclk (txusrclk),
.wclk (txusrclk2),
.we (1'b1),
.re (txdata_resync_nempty & txdata_resync_nempty_rr & txdata_resync_strobe),
.data_in ({txelecidle, txcominit, txcomwake, txcharisk, txdata}),
.data_out (txdata_resync_out),
.nempty (txdata_resync_nempty),
.half_empty ()
);
assign txcomwake_gtx = txdata_resync_out[36];
assign txcominit_gtx = txdata_resync_out[37];
assign txelecidle_gtx = txdata_resync_out[38];
end
else
if (DATA_BYTE_WIDTH == 2) begin
// no resync is needed => straightforward assignments
assign txdata_enc_in = txdata;
assign txcharisk_enc_in = txcharisk;
assign txcominit_gtx = txcominit;
assign txcomwake_gtx = txcomwake;
assign txelecidle_gtx = txelecidle;
end
else begin
// unconsidered case
always @ (posedge txusrclk)
begin
$display("Wrong width set in %m, value is %d", DATA_BYTE_WIDTH);
end
end
endgenerate
// 8/10 encoder @ txusrclk, 16 + 1 bits -> 20
gtx_8x10enc gtx_8x10enc(
.rst (~wrap_txreset_),
.clk (txusrclk),
.indata (txdata_enc_in),
.inisk (txcharisk_enc_in),
.outdata (txdata_enc_out)
);
/*
* RX PCS part: comma detect + align module, 10/8 decoder, elastic buffer, interface resynchronisation
* all modules before elastic buffer shall work on a restored clock - xclk
*/
wire xclk;
// assuming GTX interface width = 20 bits
// comma aligner
reg [19:0] rxdata_comma_in;
wire [19:0] rxdata_comma_out;
always @ (posedge xclk)
rxdata_comma_in <= {rxdisperr_gtx[1], rxcharisk_gtx[1], rxdata_gtx[15:8], rxdisperr_gtx[0], rxcharisk_gtx[0], rxdata_gtx[7:0]};
// aligner status generation
// if we detected comma & there was 1st realign after non-aligned state -> triggered, we wait until the next comma
// if no realign would be issued, assumes, that we've aligned to the stream otherwise go back to non-aligned state
wire comma;
wire realign;
wire state_nonaligned;
reg state_aligned;
reg state_triggered;
wire set_aligned;
wire set_triggered;
wire clr_aligned;
wire clr_triggered;
assign state_nonaligned = ~state_aligned & ~state_triggered;
assign set_aligned = state_triggered & comma & ~realign;
assign set_triggered = state_nonaligned & comma;
assign clr_aligned = realign;
assign clr_triggered = realign;
always @ (posedge xclk)
begin
state_aligned <= (set_aligned | state_aligned ) & wrap_rxreset_ & ~clr_aligned;
state_triggered <= (set_triggered | state_triggered) & wrap_rxreset_ & ~clr_triggered;
end
gtx_comma_align gtx_comma_align(
.rst (~wrap_rxreset_),
.clk (xclk),
.indata (rxdata_comma_in),
.outdata (rxdata_comma_out),
.comma (comma),
.realign (realign)
);
//
// 10x8 decoder
wire [15:0] rxdata_dec_out;
wire [1:0] rxcharisk_dec_out;
wire [1:0] rxnotintable_dec_out;
wire [1:0] rxdisperr_dec_out;
gtx_10x8dec gtx_10x8dec(
.rst (~wrap_rxreset_),
.clk (xclk),
.indata (rxdata_comma_out),
.outdata (rxdata_dec_out),
.outisk (rxcharisk_dec_out),
.notintable (rxnotintable_dec_out),
.disperror (rxdisperr_dec_out)
);
// elastic buffer: transition from xclk to rxusrclk
wire [15:0] rxdata_els_out;
wire [1:0] rxcharisk_els_out;
wire [1:0] rxnotintable_els_out;
wire [1:0] rxdisperr_els_out;
wire lword_strobe;
wire isaligned;
gtx_elastic #(
.DEPTH_LOG2 (3),
.OFFSET (4)
)
gtx_elastic(
.rst (~wrap_rxreset_),
.wclk (xclk),
.rclk (rxusrclk),
.isaligned_in (state_aligned),
.charisk_in (rxcharisk_dec_out),
.notintable_in (rxnotintable_dec_out),
.disperror_in (rxdisperr_dec_out),
.data_in (rxdata_dec_out),
.isaligned_out (isaligned),
.charisk_out (rxcharisk_els_out),
.notintable_out (rxnotintable_els_out),
.disperror_out (rxdisperr_els_out),
.data_out (rxdata_els_out),
.lword_strobe (lword_strobe),
.full (elastic_full),
.empty (elastic_empty)
);
// iface resync
/*
output wire cplllock, - async
output wire rxbyteisaligned,- rxusrclk2
output wire rxcomwakedet, - rxusrclk2
output wire rxcominitdet, - rxusrclk2
output wire rxelecidle, - async
output wire rxresetdone, - rxusrclk2
output wire txresetdone, - txusrclk2
*/
wire rxcomwakedet_gtx;
wire rxcominitdet_gtx;
wire rxresetdone_gtx;
wire txresetdone_gtx;
// insert resync if it's necessary
generate
if (DATA_BYTE_WIDTH == 4) begin
// resync to rxusrclk
// Fin = 2*Fout => 2*WIDTHin = WIDTHout
// first data word arrived = last word of a primitive, second arrived - first one
// lword_strobe indicates that second data word is arrived
wire rxdata_resync_nempty;
reg rxdata_resync_nempty_r;
wire rxdata_resync_strobe;
wire [50:0] rxdata_resync_in;
wire [50:0] rxdata_resync_out;
reg [23:0] rxdata_resync_buf;
assign rxdata_resync_strobe = lword_strobe;
assign rxdata_resync_in = {
isaligned, // 1
rxcomwakedet_gtx, // 1
rxcominitdet_gtx, // 1
rxresetdone_gtx, // 1
txresetdone_gtx, // 1
elastic_full | rxdata_resync_buf[23], // 1
elastic_empty | rxdata_resync_buf[22], // 1
rxdisperr_els_out, // 2
rxnotintable_els_out, // 2
rxcharisk_els_out, // 2
rxdata_els_out, // 16
rxdata_resync_buf[21:0]}; // 22 / 51 total
always @ (posedge rxusrclk)
rxdata_resync_buf <= ~wrap_rxreset_ ? 36'h0 : ~rxdata_resync_strobe ? {elastic_full, elastic_empty, rxdisperr_els_out, rxnotintable_els_out, rxcharisk_els_out, rxdata_els_out} : rxdata_resync_buf;
always @ (posedge rxusrclk2)
rxdata_resync_nempty_r <= rxdata_resync_nempty;
fifo_cross_clocks #(
.DATA_WIDTH (51),
.DATA_DEPTH (4)
)
rxdata_resynchro(
.rst (~wrap_rxreset_),
.rclk (rxusrclk2),
.wclk (rxusrclk),
.we (rxdata_resync_strobe),
.re (rxdata_resync_nempty & rxdata_resync_nempty_r),
.data_in (rxdata_resync_in),
.data_out (rxdata_resync_out),
.nempty (rxdata_resync_nempty),
.half_empty ()
);
assign rxbyteisaligned = rxdata_resync_out[50];
assign rxcomwakedet = rxdata_resync_out[49];
assign rxcominitdet = rxdata_resync_out[48];
assign rxresetdone = rxdata_resync_out[47];
assign txresetdone = rxdata_resync_out[46];
assign rxelsfull = rxdata_resync_out[45];
assign rxelsempty = rxdata_resync_out[44];
assign rxdisperr = {rxdata_resync_out[43:42], rxdata_resync_out[20:20]};
assign rxnotintable = {rxdata_resync_out[41:40], rxdata_resync_out[19:18]};
assign rxcharisk = {rxdata_resync_out[39:38], rxdata_resync_out[17:16]};
assign rxdata = {rxdata_resync_out[37:22], rxdata_resync_out[15:0] };
end
else
if (DATA_BYTE_WIDTH == 2) begin
// no resync is needed => straightforward assignments
assign rxbyteisaligned = isaligned;
assign rxcomwakedet = rxcomwakedet_gtx;
assign rxcominitdet = rxcominitdet_gtx;
assign rxresetdone = rxresetdone_gtx;
assign txresetdone = txresetdone_gtx;
assign rxelsfull = elastic_full;
assign rxelsempty = elastic_empty;
assign rxdisperr = rxdisperr_els_out;
assign rxnotintable = rxnotintable_els_out;
assign rxcharisk = rxcharisk_els_out;
assign rxdata = rxdata_els_out;
end
else begin
// unconsidered case
always @ (posedge txusrclk)
begin
$display("Wrong width set in %m, value is %d", DATA_BYTE_WIDTH);
end
end
endgenerate
GTXE2_CHANNEL #(
.SIM_RECEIVER_DETECT_PASS ("TRUE"),
.SIM_TX_EIDLE_DRIVE_LEVEL ("X"),
.SIM_RESET_SPEEDUP ("FALSE"),
.SIM_CPLLREFCLK_SEL (3'b001),
.SIM_VERSION ("4.0"),
.ALIGN_COMMA_DOUBLE ("FALSE"),
.ALIGN_COMMA_ENABLE (10'b1111111111),
.ALIGN_COMMA_WORD (1),
.ALIGN_MCOMMA_DET ("TRUE"),
.ALIGN_MCOMMA_VALUE (10'b1010000011),
.ALIGN_PCOMMA_DET ("TRUE"),
.ALIGN_PCOMMA_VALUE (10'b0101111100),
.SHOW_REALIGN_COMMA ("TRUE"),
.RXSLIDE_AUTO_WAIT (7),
.RXSLIDE_MODE ("OFF"),
.RX_SIG_VALID_DLY (10),
.RX_DISPERR_SEQ_MATCH ("TRUE"),
.DEC_MCOMMA_DETECT ("TRUE"),
.DEC_PCOMMA_DETECT ("TRUE"),
.DEC_VALID_COMMA_ONLY ("FALSE"),
.CBCC_DATA_SOURCE_SEL ("DECODED"),
.CLK_COR_SEQ_2_USE ("FALSE"),
.CLK_COR_KEEP_IDLE ("FALSE"),
.CLK_COR_MAX_LAT (9),
.CLK_COR_MIN_LAT (7),
.CLK_COR_PRECEDENCE ("TRUE"),
.CLK_COR_REPEAT_WAIT (0),
.CLK_COR_SEQ_LEN (1),
.CLK_COR_SEQ_1_ENABLE (4'b1111),
.CLK_COR_SEQ_1_1 (10'b0100000000),
.CLK_COR_SEQ_1_2 (10'b0000000000),
.CLK_COR_SEQ_1_3 (10'b0000000000),
.CLK_COR_SEQ_1_4 (10'b0000000000),
.CLK_CORRECT_USE ("FALSE"),
.CLK_COR_SEQ_2_ENABLE (4'b1111),
.CLK_COR_SEQ_2_1 (10'b0100000000),
.CLK_COR_SEQ_2_2 (10'b0000000000),
.CLK_COR_SEQ_2_3 (10'b0000000000),
.CLK_COR_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_KEEP_ALIGN ("FALSE"),
.CHAN_BOND_MAX_SKEW (1),
.CHAN_BOND_SEQ_LEN (1),
.CHAN_BOND_SEQ_1_1 (10'b0000000000),
.CHAN_BOND_SEQ_1_2 (10'b0000000000),
.CHAN_BOND_SEQ_1_3 (10'b0000000000),
.CHAN_BOND_SEQ_1_4 (10'b0000000000),
.CHAN_BOND_SEQ_1_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_1 (10'b0000000000),
.CHAN_BOND_SEQ_2_2 (10'b0000000000),
.CHAN_BOND_SEQ_2_3 (10'b0000000000),
.CHAN_BOND_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_SEQ_2_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_USE ("FALSE"),
.FTS_DESKEW_SEQ_ENABLE (4'b1111),
.FTS_LANE_DESKEW_CFG (4'b1111),
.FTS_LANE_DESKEW_EN ("FALSE"),
.ES_CONTROL (6'b000000),
.ES_ERRDET_EN ("FALSE"),
.ES_EYE_SCAN_EN ("TRUE"),
.ES_HORZ_OFFSET (12'h000),
.ES_PMA_CFG (10'b0000000000),
.ES_PRESCALE (5'b00000),
.ES_QUALIFIER (80'h00000000000000000000),
.ES_QUAL_MASK (80'h00000000000000000000),
.ES_SDATA_MASK (80'h00000000000000000000),
.ES_VERT_OFFSET (9'b000000000),
.RX_DATA_WIDTH (20),
.OUTREFCLK_SEL_INV (2'b11),
.PMA_RSV (32'h00018480),
.PMA_RSV2 (16'h2050),
.PMA_RSV3 (2'b00),
.PMA_RSV4 (32'h00000000),
.RX_BIAS_CFG (12'b000000000100),
.DMONITOR_CFG (24'h000A00),
.RX_CM_SEL (2'b11),
.RX_CM_TRIM (3'b010),
.RX_DEBUG_CFG (12'b000000000000),
.RX_OS_CFG (13'b0000010000000),
.TERM_RCAL_CFG (5'b10000),
.TERM_RCAL_OVRD (1'b0),
.TST_RSV (32'h00000000),
.RX_CLK25_DIV (6),
.TX_CLK25_DIV (6),
.UCODEER_CLR (1'b0),
.PCS_PCIE_EN ("FALSE"),
.PCS_RSVD_ATTR (48'h0100),
.RXBUF_ADDR_MODE ("FAST"),
.RXBUF_EIDLE_HI_CNT (4'b1000),
.RXBUF_EIDLE_LO_CNT (4'b0000),
.RXBUF_EN ("FALSE"),
.RX_BUFFER_CFG (6'b000000),
.RXBUF_RESET_ON_CB_CHANGE ("TRUE"),
.RXBUF_RESET_ON_COMMAALIGN ("FALSE"),
.RXBUF_RESET_ON_EIDLE ("FALSE"),
.RXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.RXBUFRESET_TIME (5'b00001),
.RXBUF_THRESH_OVFLW (61),
.RXBUF_THRESH_OVRD ("FALSE"),
.RXBUF_THRESH_UNDFLW (4),
.RXDLY_CFG (16'h001F),
.RXDLY_LCFG (9'h030),
.RXDLY_TAP_CFG (16'h0000),
.RXPH_CFG (24'h000000),
.RXPHDLY_CFG (24'h084020),
.RXPH_MONITOR_SEL (5'b00000),
.RX_XCLK_SEL ("RXREC"),
.RX_DDI_SEL (6'b000000),
.RX_DEFER_RESET_BUF_EN ("TRUE"),
.RXCDR_CFG (72'h03000023ff10200020),
.RXCDR_FR_RESET_ON_EIDLE (1'b0),
.RXCDR_HOLD_DURING_EIDLE (1'b0),
.RXCDR_PH_RESET_ON_EIDLE (1'b0),
.RXCDR_LOCK_CFG (6'b010101),
.RXCDRFREQRESET_TIME (RXCDRFREQRESET_TIME),
.RXCDRPHRESET_TIME (RXCDRPHRESET_TIME),
.RXISCANRESET_TIME (RXISCANRESET_TIME),
.RXPCSRESET_TIME (5'b00001),
.RXPMARESET_TIME (RXPMARESET_TIME),
.RXOOB_CFG (7'b0000110),
.RXGEARBOX_EN ("FALSE"),
.GEARBOX_MODE (3'b000),
.RXPRBS_ERR_LOOPBACK (1'b0),
.PD_TRANS_TIME_FROM_P2 (12'h03c),
.PD_TRANS_TIME_NONE_P2 (8'h3c),
.PD_TRANS_TIME_TO_P2 (8'h64),
.SAS_MAX_COM (64),
.SAS_MIN_COM (36),
.SATA_BURST_SEQ_LEN (4'b0110),
.SATA_BURST_VAL (3'b110),
.SATA_EIDLE_VAL (3'b110),
.SATA_MAX_BURST (8),
.SATA_MAX_INIT (21),
.SATA_MAX_WAKE (7),
.SATA_MIN_BURST (4),
.SATA_MIN_INIT (12),
.SATA_MIN_WAKE (4),
.TRANS_TIME_RATE (8'h0E),
.TXBUF_EN ("TRUE"),
.TXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.TXDLY_CFG (16'h001F),
.TXDLY_LCFG (9'h030),
.TXDLY_TAP_CFG (16'h0000),
.TXPH_CFG (16'h0780),
.TXPHDLY_CFG (24'h084020),
.TXPH_MONITOR_SEL (5'b00000),
.TX_XCLK_SEL ("TXOUT"),
.TX_DATA_WIDTH (20),
.TX_DEEMPH0 (5'b00000),
.TX_DEEMPH1 (5'b00000),
.TX_EIDLE_ASSERT_DELAY (3'b110),
.TX_EIDLE_DEASSERT_DELAY (3'b100),
.TX_LOOPBACK_DRIVE_HIZ ("FALSE"),
.TX_MAINCURSOR_SEL (1'b0),
.TX_DRIVE_MODE ("DIRECT"),
.TX_MARGIN_FULL_0 (7'b1001110),
.TX_MARGIN_FULL_1 (7'b1001001),
.TX_MARGIN_FULL_2 (7'b1000101),
.TX_MARGIN_FULL_3 (7'b1000010),
.TX_MARGIN_FULL_4 (7'b1000000),
.TX_MARGIN_LOW_0 (7'b1000110),
.TX_MARGIN_LOW_1 (7'b1000100),
.TX_MARGIN_LOW_2 (7'b1000010),
.TX_MARGIN_LOW_3 (7'b1000000),
.TX_MARGIN_LOW_4 (7'b1000000),
.TXGEARBOX_EN ("FALSE"),
.TXPCSRESET_TIME (5'b00001),
.TXPMARESET_TIME (TXPMARESET_TIME),
.TX_RXDETECT_CFG (14'h1832),
.TX_RXDETECT_REF (3'b100),
.CPLL_CFG (24'hBC07DC),
.CPLL_FBDIV (4),
.CPLL_FBDIV_45 (5),
.CPLL_INIT_CFG (24'h00001E),
.CPLL_LOCK_CFG (16'h01E8),
.CPLL_REFCLK_DIV (1),
.RXOUT_DIV (2),
.TXOUT_DIV (2),
.SATA_CPLL_CFG ("VCO_3000MHZ"),
.RXDFELPMRESET_TIME (RXDFELPMRESET_TIME),
.RXLPM_HF_CFG (14'b00000011110000),
.RXLPM_LF_CFG (14'b00000011110000),
.RX_DFE_GAIN_CFG (23'h020FEA),
.RX_DFE_H2_CFG (12'b000000000000),
.RX_DFE_H3_CFG (12'b000001000000),
.RX_DFE_H4_CFG (11'b00011110000),
.RX_DFE_H5_CFG (11'b00011100000),
.RX_DFE_KL_CFG (13'b0000011111110),
.RX_DFE_LPM_CFG (16'h0954),
.RX_DFE_LPM_HOLD_DURING_EIDLE (1'b0),
.RX_DFE_UT_CFG (17'b10001111000000000),
.RX_DFE_VP_CFG (17'b00011111100000011),
.RX_CLKMUX_PD (1'b1),
.TX_CLKMUX_PD (1'b1),
.RX_INT_DATAWIDTH (0),
.TX_INT_DATAWIDTH (0),
.TX_QPI_STATUS_EN (1'b0),
.RX_DFE_KL_CFG2 (32'h301148AC),
.RX_DFE_XYD_CFG (13'b0000000000000),
.TX_PREDRIVER_MODE (1'b0)
)
gtx(
.CPLLFBCLKLOST (),
.CPLLLOCK (cplllock),
.CPLLLOCKDETCLK (cplllockdetclk),
.CPLLLOCKEN (1'b1),
.CPLLPD (1'b0),
.CPLLREFCLKLOST (),
.CPLLREFCLKSEL (3'b001),
.CPLLRESET (cpllreset),
.GTRSVD (1'b0),
.PCSRSVDIN (1'b0),
.PCSRSVDIN2 (1'b0),
.PMARSVDIN (1'b0),
.PMARSVDIN2 (1'b0),
.TSTIN (1'b1),
.TSTOUT (),
.CLKRSVD (4'b0000),
.GTGREFCLK (1'b0),
.GTNORTHREFCLK0 (1'b0),
.GTNORTHREFCLK1 (1'b0),
.GTREFCLK0 (gtrefclk),
.GTREFCLK1 (1'b0),
.GTSOUTHREFCLK0 (1'b0),
.GTSOUTHREFCLK1 (1'b0),
.DRPADDR (9'b0),
.DRPCLK (drpclk),
.DRPDI (16'b0),
.DRPDO (),
.DRPEN (1'b0),
.DRPRDY (),
.DRPWE (1'b0),
.GTREFCLKMONITOR (),
.QPLLCLK (gtrefclk),
.QPLLREFCLK (gtrefclk),
.RXSYSCLKSEL (2'b00),
.TXSYSCLKSEL (2'b00),
.DMONITOROUT (),
.TX8B10BEN (1'b0),
.LOOPBACK (3'd0),
.PHYSTATUS (),
.RXRATE (3'd0),
.RXVALID (),
.RXPD (2'b00),
.TXPD (2'b00),
.SETERRSTATUS (1'b0),
.EYESCANRESET (1'b0),//rxreset), // p78
.RXUSERRDY (rxuserrdy),
.EYESCANDATAERROR (),
.EYESCANMODE (1'b0),
.EYESCANTRIGGER (1'b0),
.RXCDRFREQRESET (1'b0),
.RXCDRHOLD (1'b0),
.RXCDRLOCK (),
.RXCDROVRDEN (1'b0),
.RXCDRRESET (1'b0),
.RXCDRRESETRSV (1'b0),
.RXCLKCORCNT (),
.RX8B10BEN (1'b0),
.RXUSRCLK (rxusrclk),
.RXUSRCLK2 (rxusrclk),
.RXDATA (rxdata_gtx),
.RXPRBSERR (),
.RXPRBSSEL (3'd0),
.RXPRBSCNTRESET (1'b0),
.RXDFEXYDEN (1'b1),
.RXDFEXYDHOLD (1'b0),
.RXDFEXYDOVRDEN (1'b0),
.RXDISPERR (rxdisperr_gtx),
.RXNOTINTABLE (),
.GTXRXP (rxp),
.GTXRXN (rxn),
.RXBUFRESET (1'b0),
.RXBUFSTATUS (),
.RXDDIEN (1'b0),
.RXDLYBYPASS (1'b1),
.RXDLYEN (1'b0),
.RXDLYOVRDEN (1'b0),
.RXDLYSRESET (1'b0),
.RXDLYSRESETDONE (),
.RXPHALIGN (1'b0),
.RXPHALIGNDONE (),
.RXPHALIGNEN (1'b0),
.RXPHDLYPD (1'b0),
.RXPHDLYRESET (1'b0),
.RXPHMONITOR (),
.RXPHOVRDEN (1'b0),
.RXPHSLIPMONITOR (),
.RXSTATUS (),
.RXBYTEISALIGNED (),
.RXBYTEREALIGN (),
.RXCOMMADET (),
.RXCOMMADETEN (1'b0),
.RXMCOMMAALIGNEN (1'b0),
.RXPCOMMAALIGNEN (1'b0),
.RXCHANBONDSEQ (),
.RXCHBONDEN (1'b0),
.RXCHBONDLEVEL (3'd0),
.RXCHBONDMASTER (1'b0),
.RXCHBONDO (),
.RXCHBONDSLAVE (1'b0),
.RXCHANISALIGNED (),
.RXCHANREALIGN (),
.RXLPMHFHOLD (1'b0),
.RXLPMHFOVRDEN (1'b0),
.RXLPMLFHOLD (1'b0),
.RXDFEAGCHOLD (1'b0),
.RXDFEAGCOVRDEN (1'b0),
.RXDFECM1EN (1'b0),
.RXDFELFHOLD (1'b0),
.RXDFELFOVRDEN (1'b1),
.RXDFELPMRESET (rxreset),
.RXDFETAP2HOLD (1'b0),
.RXDFETAP2OVRDEN (1'b0),
.RXDFETAP3HOLD (1'b0),
.RXDFETAP3OVRDEN (1'b0),
.RXDFETAP4HOLD (1'b0),
.RXDFETAP4OVRDEN (1'b0),
.RXDFETAP5HOLD (1'b0),
.RXDFETAP5OVRDEN (1'b0),
.RXDFEUTHOLD (1'b0),
.RXDFEUTOVRDEN (1'b0),
.RXDFEVPHOLD (1'b0),
.RXDFEVPOVRDEN (1'b0),
// .RXDFEVSEN (1'b0),
.RXLPMLFKLOVRDEN (1'b0),
.RXMONITOROUT (),
.RXMONITORSEL (2'b01),
.RXOSHOLD (1'b0),
.RXOSOVRDEN (1'b0),
.RXRATEDONE (),
.RXOUTCLK (xclk),
.RXOUTCLKFABRIC (),
.RXOUTCLKPCS (),
.RXOUTCLKSEL (3'b010),
.RXDATAVALID (),
.RXHEADER (),
.RXHEADERVALID (),
.RXSTARTOFSEQ (),
.RXGEARBOXSLIP (1'b0),
.GTRXRESET (rxreset),
.RXOOBRESET (1'b0),
.RXPCSRESET (1'b0),
.RXPMARESET (1'b0),//rxreset), // p78
.RXLPMEN (1'b0),
.RXCOMSASDET (),
.RXCOMWAKEDET (rxcomwakedet_gtx),
.RXCOMINITDET (rxcominitdet_gtx),
.RXELECIDLE (rxelecidle),
.RXELECIDLEMODE (2'b00),
.RXPOLARITY (1'b0),
.RXSLIDE (1'b0),
.RXCHARISCOMMA (),
.RXCHARISK (rxcharisk_gtx),
.RXCHBONDI (5'b00000),
.RXRESETDONE (rxresetdone_gtx),
.RXQPIEN (1'b0),
.RXQPISENN (),
.RXQPISENP (),
.TXPHDLYTSTCLK (1'b0),
.TXPOSTCURSOR (5'b00000),
.TXPOSTCURSORINV (1'b0),
.TXPRECURSOR (5'd0),
.TXPRECURSORINV (1'b0),
.TXQPIBIASEN (1'b0),
.TXQPISTRONGPDOWN (1'b0),
.TXQPIWEAKPUP (1'b0),
.CFGRESET (1'b0),
.GTTXRESET (txreset),
.PCSRSVDOUT (),
.TXUSERRDY (txuserrdy),
.GTRESETSEL (1'b0),
.RESETOVRD (1'b0),
.TXCHARDISPMODE (txchardispmode_gtx),
.TXCHARDISPVAL (txchardispval_gtx),
.TXUSRCLK (txusrclk),
.TXUSRCLK2 (txusrclk),
.TXELECIDLE (txelecidle),
.TXMARGIN (3'd0),
.TXRATE (3'd0),
.TXSWING (1'b0),
.TXPRBSFORCEERR (1'b0),
.TXDLYBYPASS (1'b1),
.TXDLYEN (1'b0),
.TXDLYHOLD (1'b0),
.TXDLYOVRDEN (1'b0),
.TXDLYSRESET (1'b0),
.TXDLYSRESETDONE (),
.TXDLYUPDOWN (1'b0),
.TXPHALIGN (1'b0),
.TXPHALIGNDONE (),
.TXPHALIGNEN (1'b0),
.TXPHDLYPD (1'b0),
.TXPHDLYRESET (1'b0),
.TXPHINIT (1'b0),
.TXPHINITDONE (),
.TXPHOVRDEN (1'b0),
.TXBUFSTATUS (),
.TXBUFDIFFCTRL (3'b100),
.TXDEEMPH (1'b0),
.TXDIFFCTRL (4'b1000),
.TXDIFFPD (1'b0),
.TXINHIBIT (1'b0),
.TXMAINCURSOR (7'b0000000),
.TXPISOPD (1'b0),
.TXDATA (txdata_gtx),
.GTXTXN (txn),
.GTXTXP (txp),
.TXOUTCLK (txoutclk),
.TXOUTCLKFABRIC (),
.TXOUTCLKPCS (),
.TXOUTCLKSEL (3'b010),
.TXRATEDONE (),
.TXCHARISK (txcharisk_gtx),
.TXGEARBOXREADY (),
.TXHEADER (3'd0),
.TXSEQUENCE (7'd0),
.TXSTARTSEQ (1'b0),
.TXPCSRESET (txpcsreset),
.TXPMARESET (1'b0),
.TXRESETDONE (txresetdone_gtx),
.TXCOMFINISH (),
.TXCOMINIT (txcominit_gtx),
.TXCOMSAS (1'b0),
.TXCOMWAKE (txcomwake_gtx),
.TXPDELECIDLEMODE (1'b0),
.TXPOLARITY (1'b0),
.TXDETECTRX (1'b0),
.TX8B10BBYPASS (8'd0),
.TXPRBSSEL (3'd0),
.TXQPISENN (),
.TXQPISENP ()
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/link.v 0000664 0000000 0000000 00000102233 12572445207 0022123 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: link
* Date: 2015-07-11
* Author: Alexey
* Description: sata link layer implementation
*
* Copyright (c) 2015 Elphel, Inc.
* link.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* link.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`include "scrambler.v"
`include "crc.v"
module link #(
// 4 = dword. 4-bytes aligned data transfers TODO 2 = word - easy, 8 = qword - difficult
parameter DATA_BYTE_WIDTH = 4
)
(
// TODO insert watchdogs
input wire rst,
input wire clk,
// data inputs from transport layer
// input data stream (if any data during OOB setting => ignored)
input wire [DATA_BYTE_WIDTH*8 - 1:0] data_in,
// in case of strange data aligments and size (1st mentioned @ doc, p.310, odd number of words case)
// Actually, only last data bundle shall be masked, others are always valid.
// Mask could be encoded into 3 bits instead of 4 for qword, but encoding+decoding aren't worth the bit
// TODO, for now not supported, all mask bits are assumed to be set
input wire [DATA_BYTE_WIDTH/2 - 1:0] data_mask_in,
// buffer read strobe
output wire data_strobe_out,
// transaction's last data budle pulse
input wire data_last_in,
// read data is valid (if 0 while last pulse wasn't received => need to hold the line)
input wire data_val_in,
// data outputs to transport layer
// read data, same as related inputs
output wire [DATA_BYTE_WIDTH*8 - 1:0] data_out,
// same thing - all 1s for now. TODO
output wire [DATA_BYTE_WIDTH/2 - 1:0] data_mask_out,
// count every data bundle read by transport layer, even if busy flag is set
// let the transport layer handle oveflows by himself
output wire data_val_out,
// transport layer tells if its inner buffer is almost full
input wire data_busy_in,
output wire data_last_out,
// request for a new frame transition
input wire frame_req,
// a little bit of overkill with the cound of response signals, think of throwing out 1 of them
// LL tells back if it cant handle the request for now
output wire frame_busy,
// LL tells if the request is transmitting
output wire frame_ack,
// or if it was cancelled because of simultanious incoming transmission
output wire frame_rej,
// TL tell if the outcoming transaction is done and how it was done
output wire frame_done_good,
output wire frame_done_bad,
// if started an incoming transaction
output wire incom_start,
// if incoming transition was completed
output wire incom_done,
// if incoming transition had errors
output wire incom_invalidate,
// transport layer responds on a completion of a FIS
input wire incom_ack_good,
input wire incom_ack_bad,
// oob sequence is reinitiated and link now is not established or rxelecidle
input wire link_reset,
// TL demands to brutally cancel current transaction
input wire sync_escape_req,
// acknowlegement of a successful reception
output wire sync_escape_ack,
// TL demands to stop current recieving session
input wire incom_stop_req,
// inputs from phy
// phy is ready - link is established
input wire phy_ready,
// data-primitives stream from phy
input wire [DATA_BYTE_WIDTH*8 - 1:0] phy_data_in,
input wire [DATA_BYTE_WIDTH - 1:0] phy_isk_in, // charisk
input wire [DATA_BYTE_WIDTH - 1:0] phy_err_in, // disperr | notintable
// to phy
output wire [DATA_BYTE_WIDTH*8 - 1:0] phy_data_out,
output wire [DATA_BYTE_WIDTH - 1:0] phy_isk_out // charisk
);
// scrambled data
wire [DATA_BYTE_WIDTH*8 - 1:0] scrambler_out;
wire dec_err; // doc, p.311
// while receiving session shows crc check status
wire crc_good;
wire crc_bad;
// current crc
wire [31:0] crc_dword;
reg data_txing; // if there are still some data to transmit and the transaction wasn't cancelled
always @ (posedge clk)
data_txing <= rst | (data_last_in & data_strobe_out | dword_val & rcvd_dword[CODE_DMATP]) ? 1'b0 : frame_req ? 1'b1 : data_txing;
// send primitives variety count, including CRC and DATA as primitives
localparam PRIM_NUM = 15;
// list of bits of rcvd_dword
wire [PRIM_NUM - 1:0] rcvd_dword; // shows current processing primitive (or just data dword)
wire dword_val;
localparam CODE_DATA = 0;
localparam CODE_CRC = 1;
localparam CODE_SYNCP = 2;
localparam CODE_ALIGNP = 3;
localparam CODE_XRDYP = 4;
localparam CODE_SOFP = 5;
localparam CODE_HOLDAP = 6;
localparam CODE_HOLDP = 7;
localparam CODE_EOFP = 8;
localparam CODE_WTRMP = 9;
localparam CODE_RRDYP = 10;
localparam CODE_IPP = 11;
localparam CODE_DMATP = 12;
localparam CODE_OKP = 13;
localparam CODE_ERRP = 14;
// fsm
// states and transitions are taken from the doc, "Link Layer State Machine" chapter
// power mode states are not implemented. TODO insert them as an additional branch of fsm
// !!!IMPORTANT!!! If add/remove any states, dont forget to change this parameter value
localparam STATES_COUNT = 23;
// idle state
wire state_idle;
reg state_sync_esc; // SyncEscape
reg state_nocommerr; // NoComErr
reg state_nocomm; // NoComm
reg state_align; // SendAlign
reg state_reset; // RESET
// tranmitter branch
reg state_send_rdy; // SendChkRdy
reg state_send_sof; // SendSOF
reg state_send_data; // SendData
reg state_send_rhold; // RcvrHold - hold initiated by current data reciever
reg state_send_shold; // SendHold - hold initiated by current data sender
reg state_send_crc; // SendCVC
reg state_send_eof; // SendEOF
reg state_wait; // Wait
// receiver branch
reg state_rcvr_wait; // RcvWaitFifo
reg state_rcvr_rdy; // RcvChkRdy
reg state_rcvr_data; // RcvData
reg state_rcvr_rhold; // Hold - hold initiated by current data reciever
reg state_rcvr_shold; // RcvHold - hold initiated by current data sender
reg state_rcvr_eof; // RcvEOF
reg state_rcvr_goodcrc; // GoodCRC
reg state_rcvr_goodend; // GoodEnd
reg state_rcvr_badend; // BadEnd
wire set_sync_esc;
wire set_nocommerr;
wire set_nocomm;
wire set_align;
wire set_reset;
wire set_send_rdy;
wire set_send_sof;
wire set_send_data;
wire set_send_rhold;
wire set_send_shold;
wire set_send_crc;
wire set_send_eof;
wire set_wait;
wire set_rcvr_wait;
wire set_rcvr_rdy;
wire set_rcvr_data;
wire set_rcvr_rhold;
wire set_rcvr_shold;
wire set_rcvr_eof;
wire set_rcvr_goodcrc;
wire set_rcvr_goodend;
wire set_rcvr_badend;
wire clr_sync_esc;
wire clr_nocommerr;
wire clr_nocomm;
wire clr_align;
wire clr_reset;
wire clr_send_rdy;
wire clr_send_sof;
wire clr_send_data;
wire clr_send_rhold;
wire clr_send_shold;
wire clr_send_crc;
wire clr_send_eof;
wire clr_wait;
wire clr_rcvr_wait;
wire clr_rcvr_rdy;
wire clr_rcvr_data;
wire clr_rcvr_rhold;
wire clr_rcvr_shold;
wire clr_rcvr_eof;
wire clr_rcvr_goodcrc;
wire clr_rcvr_goodend;
wire clr_rcvr_badend;
assign state_idle = ~state_sync_esc
& ~state_nocommerr
& ~state_nocomm
& ~state_align
& ~state_reset
& ~state_send_rdy
& ~state_send_sof
& ~state_send_data
& ~state_send_rhold
& ~state_send_shold
& ~state_send_crc
& ~state_send_eof
& ~state_wait
& ~state_rcvr_wait
& ~state_rcvr_rdy
& ~state_rcvr_data
& ~state_rcvr_rhold
& ~state_rcvr_shold
& ~state_rcvr_eof
& ~state_rcvr_goodcrc
& ~state_rcvr_goodend
& ~state_rcvr_badend;
// got an escaping primitive = request to cancel the transmission
wire alignes_pair; // pauses every state go give a chance to insert 2 align primitives on a line at least every 256 dwords due to spec
wire alignes_pair_0; // time for 1st align primitive
wire alignes_pair_1; // time for 2nd align primitive
reg [8:0] alignes_timer;
assign alignes_pair_0 = alignes_timer == 9'd252;
assign alignes_pair_1 = alignes_timer == 9'd253;
assign alignes_pair = alignes_pair_0 | alignes_pair_1;
always @ (posedge clk)
alignes_timer <= rst | alignes_pair_1 | state_reset ? 9'h0 : alignes_timer + 1'b1;
wire got_escape;
assign got_escape = dword_val & rcvd_dword[CODE_SYNCP];
// escaping is done
assign sync_escape_ack = state_sync_esc;
// Whole transitions table, literally from doc pages 311-328
assign set_sync_esc = sync_escape_req;
assign set_nocommerr = ~phy_ready & ~state_nocomm & ~state_reset;
assign set_nocomm = state_nocommerr;
assign set_align = state_reset & ~link_reset;
assign set_reset = link_reset;
assign set_send_rdy = state_idle & frame_req;
assign set_send_sof = state_send_rdy & phy_ready & dword_val & rcvd_dword[CODE_RRDYP];
assign set_send_data = state_send_sof & phy_ready
| state_send_rhold & data_txing & ~dec_err & dword_val & ~rcvd_dword[CODE_HOLDP] & ~rcvd_dword[CODE_SYNCP] & ~rcvd_dword[CODE_DMATP]
| state_send_shold & data_txing & data_val_in & dword_val & ~rcvd_dword[CODE_HOLDP] & ~rcvd_dword[CODE_SYNCP];
assign set_send_rhold = state_send_data & data_txing & data_val_in & ~data_last_in & dword_val & rcvd_dword[CODE_HOLDP]
| state_send_shold & data_txing & data_val_in & dword_val & rcvd_dword[CODE_HOLDP];
assign set_send_shold = state_send_data & data_txing & ~data_val_in & dword_val & ~rcvd_dword[CODE_SYNCP];
assign set_send_crc = state_send_data & data_txing & data_val_in & data_last_in & dword_val & ~rcvd_dword[CODE_SYNCP]
| state_send_data & dword_val & rcvd_dword[CODE_DMATP];
assign set_send_eof = state_send_crc & phy_ready & dword_val & ~rcvd_dword[CODE_SYNCP];
assign set_wait = state_send_eof & phy_ready & dword_val & ~rcvd_dword[CODE_SYNCP];
// receiver's branch
assign set_rcvr_wait = state_idle & dword_val & rcvd_dword[CODE_XRDYP]
| state_send_rdy & dword_val & rcvd_dword[CODE_XRDYP];
assign set_rcvr_rdy = state_rcvr_wait & dword_val & rcvd_dword[CODE_XRDYP] & ~data_busy_in;
assign set_rcvr_data = state_rcvr_rdy & dword_val & rcvd_dword[CODE_SOFP]
| state_rcvr_rhold & dword_val & ~rcvd_dword[CODE_HOLDP] & ~rcvd_dword[CODE_EOFP] & ~rcvd_dword[CODE_SYNCP] & ~data_busy_in
| state_rcvr_shold & dword_val & ~rcvd_dword[CODE_HOLDP] & ~rcvd_dword[CODE_EOFP] & ~rcvd_dword[CODE_SYNCP];
assign set_rcvr_rhold = state_rcvr_data & dword_val & rcvd_dword[CODE_DATA] & data_busy_in;
assign set_rcvr_shold = state_rcvr_data & dword_val & rcvd_dword[CODE_HOLDP]
| state_rcvr_rhold & dword_val & rcvd_dword[CODE_HOLDP] & ~data_busy_in;
assign set_rcvr_eof = state_rcvr_data & dword_val & rcvd_dword[CODE_EOFP]
| state_rcvr_rhold & dword_val & rcvd_dword[CODE_EOFP]
| state_rcvr_shold & dword_val & rcvd_dword[CODE_EOFP];
assign set_rcvr_goodcrc = state_rcvr_eof & crc_good;
assign set_rcvr_goodend = state_rcvr_goodcrc& incom_ack_good;
assign set_rcvr_badend = state_rcvr_data & dword_val & rcvd_dword[CODE_WTRMP]
| state_rcvr_eof & crc_bad
| state_rcvr_goodcrc& incom_ack_bad;
assign clr_sync_esc = set_nocommerr | set_reset | dword_val & (rcvd_dword[CODE_RRDYP] | rcvd_dword[CODE_SYNCP]);
assign clr_nocommerr = set_reset | set_nocomm;
assign clr_nocomm = set_reset | set_align;
assign clr_align = set_nocommerr | set_reset | phy_ready;
assign clr_reset = ~link_reset;
assign clr_send_rdy = set_nocommerr | set_reset | set_sync_esc | set_send_sof | set_rcvr_wait;
assign clr_send_sof = set_nocommerr | set_reset | set_sync_esc | set_send_data | got_escape;
assign clr_send_data = set_nocommerr | set_reset | set_sync_esc | set_send_rhold | set_send_shold | set_send_crc | got_escape;
assign clr_send_rhold = set_nocommerr | set_reset | set_sync_esc | set_send_data | set_send_crc | got_escape;
assign clr_send_shold = set_nocommerr | set_reset | set_sync_esc | set_send_data | set_send_rhold | set_send_crc | got_escape;
assign clr_send_crc = set_nocommerr | set_reset | set_sync_esc | set_send_eof | got_escape;
assign clr_send_eof = set_nocommerr | set_reset | set_sync_esc | set_wait | got_escape;
assign clr_wait = set_nocommerr | set_reset | set_sync_esc | frame_done | got_escape;
assign clr_rcvr_wait = set_nocommerr | set_reset | set_sync_esc | set_rcvr_rdy | dword_val & ~rcvd_dword[CODE_XRDYP];
assign clr_rcvr_rdy = set_nocommerr | set_reset | set_sync_esc | set_rcvr_data | dword_val & ~rcvd_dword[CODE_XRDYP] & ~rcvd_dword[CODE_SOFP];
assign clr_rcvr_data = set_nocommerr | set_reset | set_sync_esc | set_rcvr_rhold | set_rcvr_shold | set_rcvr_eof | set_rcvr_badend | got_escape;
assign clr_rcvr_rhold = set_nocommerr | set_reset | set_sync_esc | set_rcvr_data | set_rcvr_eof | set_rcvr_shold | got_escape;
assign clr_rcvr_shold = set_nocommerr | set_reset | set_sync_esc | set_rcvr_data | set_rcvr_eof | got_escape;
assign clr_rcvr_eof = set_nocommerr | set_reset | set_sync_esc | set_rcvr_goodcrc | set_rcvr_badend;
assign clr_rcvr_goodcrc = set_nocommerr | set_reset | set_sync_esc | set_rcvr_goodend | set_rcvr_badend | got_escape;
assign clr_rcvr_goodend = set_nocommerr | set_reset | set_sync_esc | got_escape;
assign clr_rcvr_badend = set_nocommerr | set_reset | set_sync_esc | got_escape;
// the only truely asynchronous transaction between states is -> state_ reset. It shall not be delayed by sending alignes
// Luckily, while in that state, the line is off, so we dont need to care about merging alignes and state-bounded primitives
// Others transitions are straightforward
always @ (posedge clk)
begin
state_sync_esc <= (state_sync_esc | set_sync_esc & ~alignes_pair) & ~clr_sync_esc & ~rst;
state_nocommerr <= (state_nocommerr | set_nocommerr & ~alignes_pair) & ~clr_nocommerr & ~rst;
state_nocomm <= (state_nocomm | set_nocomm & ~alignes_pair) & ~clr_nocomm & ~rst;
state_align <= (state_align | set_align & ~alignes_pair) & ~clr_align & ~rst;
state_reset <= (state_reset | set_reset ) & ~clr_reset & ~rst;
state_send_rdy <= (state_send_rdy | set_send_rdy & ~alignes_pair) & ~clr_send_rdy & ~rst;
state_send_sof <= (state_send_sof | set_send_sof & ~alignes_pair) & ~clr_send_sof & ~rst;
state_send_data <= (state_send_data | set_send_data & ~alignes_pair) & ~clr_send_data & ~rst;
state_send_rhold <= (state_send_rhold | set_send_rhold & ~alignes_pair) & ~clr_send_rhold & ~rst;
state_send_shold <= (state_send_shold | set_send_shold & ~alignes_pair) & ~clr_send_shold & ~rst;
state_send_crc <= (state_send_crc | set_send_crc & ~alignes_pair) & ~clr_send_crc & ~rst;
state_send_eof <= (state_send_eof | set_send_eof & ~alignes_pair) & ~clr_send_eof & ~rst;
state_wait <= (state_wait | set_wait & ~alignes_pair) & ~clr_wait & ~rst;
state_rcvr_wait <= (state_rcvr_wait | set_rcvr_wait & ~alignes_pair) & ~clr_rcvr_wait & ~rst;
state_rcvr_rdy <= (state_rcvr_rdy | set_rcvr_rdy & ~alignes_pair) & ~clr_rcvr_rdy & ~rst;
state_rcvr_data <= (state_rcvr_data | set_rcvr_data & ~alignes_pair) & ~clr_rcvr_data & ~rst;
state_rcvr_rhold <= (state_rcvr_rhold | set_rcvr_rhold & ~alignes_pair) & ~clr_rcvr_rhold & ~rst;
state_rcvr_shold <= (state_rcvr_shold | set_rcvr_shold & ~alignes_pair) & ~clr_rcvr_shold & ~rst;
state_rcvr_eof <= (state_rcvr_eof | set_rcvr_eof & ~alignes_pair) & ~clr_rcvr_eof & ~rst;
state_rcvr_goodcrc <= (state_rcvr_goodcrc | set_rcvr_goodcrc & ~alignes_pair) & ~clr_rcvr_goodcrc & ~rst;
state_rcvr_goodend <= (state_rcvr_goodend | set_rcvr_goodend & ~alignes_pair) & ~clr_rcvr_goodend & ~rst;
state_rcvr_badend <= (state_rcvr_badend | set_rcvr_badend & ~alignes_pair) & ~clr_rcvr_badend & ~rst;
end
// flag if incoming request to terminate current transaction came from TL
reg incom_stop_f;
always @ (posedge clk)
incom_stop_f <= rst | incom_done | ~frame_busy ? 1'b0 : incom_stop_req ? 1'b1 : incom_stop_f;
// form data to phy
reg [DATA_BYTE_WIDTH*8 - 1:0] to_phy_data;
reg [DATA_BYTE_WIDTH - 1:0] to_phy_isk;
// TODO implement CONTP
localparam [15:0] PRIM_SYNCP_HI = {3'd5, 5'd21, 3'd5, 5'd21};
localparam [15:0] PRIM_SYNCP_LO = {3'd4, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_ALIGNP_HI = {3'd3, 5'd27, 3'd2, 5'd10};
localparam [15:0] PRIM_ALIGNP_LO = {3'd2, 5'd10, 3'd5, 5'd28};
localparam [15:0] PRIM_XRDYP_HI = {3'd2, 5'd23, 3'd2, 5'd23};
localparam [15:0] PRIM_XRDYP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_SOFP_HI = {3'd1, 5'd23, 3'd1, 5'd23};
localparam [15:0] PRIM_SOFP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_HOLDAP_HI = {3'd4, 5'd21, 3'd4, 5'd21};
localparam [15:0] PRIM_HOLDAP_LO = {3'd5, 5'd10, 3'd3, 5'd28};
localparam [15:0] PRIM_HOLDP_HI = {3'd6, 5'd21, 3'd6, 5'd21};
localparam [15:0] PRIM_HOLDP_LO = {3'd5, 5'd10, 3'd3, 5'd28};
localparam [15:0] PRIM_EOFP_HI = {3'd6, 5'd21, 3'd6, 5'd21};
localparam [15:0] PRIM_EOFP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_WTRMP_HI = {3'd2, 5'd24, 3'd2, 5'd24};
localparam [15:0] PRIM_WTRMP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_RRDYP_HI = {3'd2, 5'd10, 3'd2, 5'd10};
localparam [15:0] PRIM_RRDYP_LO = {3'd4, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_IPP_HI = {3'd2, 5'd21, 3'd2, 5'd21};
localparam [15:0] PRIM_IPP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_DMATP_HI = {3'd1, 5'd22, 3'd1, 5'd22};
localparam [15:0] PRIM_DMATP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_OKP_HI = {3'd1, 5'd21, 3'd1, 5'd21};
localparam [15:0] PRIM_OKP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_ERRP_HI = {3'd2, 5'd22, 3'd2, 5'd22};
localparam [15:0] PRIM_ERRP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
wire [DATA_BYTE_WIDTH*8 - 1:0] prim_data [PRIM_NUM - 1:0];
// fill all possible output primitives to choose from them after
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg prim_word; // word counter in a primitive TODO logic
assign prim_data[CODE_SYNCP] = prim_word ? PRIM_SYNCP_HI : PRIM_SYNCP_LO;
assign prim_data[CODE_ALIGNP] = prim_word ? PRIM_ALIGNP_HI : PRIM_ALIGNP_LO;
assign prim_data[CODE_XRDYP] = prim_word ? PRIM_XRDYP_HI : PRIM_XRDYP_LO;
assign prim_data[CODE_SOFP] = prim_word ? PRIM_SOFP_HI : PRIM_SOFP_LO;
assign prim_data[CODE_DATA] = scrambler_out;
assign prim_data[CODE_HOLDAP] = prim_word ? PRIM_HOLDAP_HI : PRIM_HOLDAP_LO;
assign prim_data[CODE_HOLDP] = prim_word ? PRIM_HOLDP_HI : PRIM_HOLDP_LO;
assign prim_data[CODE_CRC] = scrambler_out;
assign prim_data[CODE_EOFP] = prim_word ? PRIM_EOFP_HI : PRIM_EOFP_LO;
assign prim_data[CODE_WTRMP] = prim_word ? PRIM_WTRMP_HI : PRIM_WTRMP_LO;
assign prim_data[CODE_RRDYP] = prim_word ? PRIM_RRDYP_HI : PRIM_RRDYP_LO;
assign prim_data[CODE_IPP] = prim_word ? PRIM_IPP_HI : PRIM_IPP_LO;
assign prim_data[CODE_DMATP] = prim_word ? PRIM_DMATP_HI : PRIM_DMATP_LO;
assign prim_data[CODE_OKP] = prim_word ? PRIM_OKP_HI : PRIM_OKP_LO;
assign prim_data[CODE_ERRP] = prim_word ? PRIM_ERRP_HI : PRIM_ERRP_LO;
always @ (posedge clk)
begin
$display("%m: unsupported data width");
$finish;
end
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign prim_data[CODE_SYNCP] = {PRIM_SYNCP_HI , PRIM_SYNCP_LO};
assign prim_data[CODE_ALIGNP] = {PRIM_ALIGNP_HI , PRIM_ALIGNP_LO};
assign prim_data[CODE_XRDYP] = {PRIM_XRDYP_HI , PRIM_XRDYP_LO};
assign prim_data[CODE_SOFP] = {PRIM_SOFP_HI , PRIM_SOFP_LO};
assign prim_data[CODE_DATA] = scrambler_out;
assign prim_data[CODE_HOLDAP] = {PRIM_HOLDAP_HI , PRIM_HOLDAP_LO};
assign prim_data[CODE_HOLDP] = {PRIM_HOLDP_HI , PRIM_HOLDP_LO};
assign prim_data[CODE_CRC] = scrambler_out;
assign prim_data[CODE_EOFP] = {PRIM_EOFP_HI , PRIM_EOFP_LO};
assign prim_data[CODE_WTRMP] = {PRIM_WTRMP_HI , PRIM_WTRMP_LO};
assign prim_data[CODE_RRDYP] = {PRIM_RRDYP_HI , PRIM_RRDYP_LO};
assign prim_data[CODE_IPP] = {PRIM_IPP_HI , PRIM_IPP_LO};
assign prim_data[CODE_DMATP] = {PRIM_DMATP_HI , PRIM_DMATP_LO};
assign prim_data[CODE_OKP] = {PRIM_OKP_HI , PRIM_OKP_LO};
assign prim_data[CODE_ERRP] = {PRIM_ERRP_HI , PRIM_ERRP_LO};
end
else
begin
always @ (posedge clk)
begin
$display("%m: unsupported data width");
$finish;
end
end
endgenerate
// select which primitive shall be sent
wire [PRIM_NUM - 1:0] select_prim;
assign select_prim[CODE_SYNCP] = ~alignes_pair & (state_idle | state_sync_esc | state_rcvr_wait | state_reset);
assign select_prim[CODE_ALIGNP] = alignes_pair | (state_nocomm | state_nocommerr | state_align);
assign select_prim[CODE_XRDYP] = ~alignes_pair & (state_send_rdy);
assign select_prim[CODE_SOFP] = ~alignes_pair & (state_send_sof);
assign select_prim[CODE_DATA] = ~alignes_pair & (state_send_data & ~set_send_shold); // if there's no data availible for a transmission, fsm still = state_send_data. Need to explicitly count this case.
assign select_prim[CODE_HOLDAP] = ~alignes_pair & (state_send_rhold | state_rcvr_shold & ~incom_stop_f);
assign select_prim[CODE_HOLDP] = ~alignes_pair & (state_send_shold | state_rcvr_rhold | state_send_data & set_send_shold); // the case mentioned 2 lines upper
assign select_prim[CODE_CRC] = ~alignes_pair & (state_send_crc);
assign select_prim[CODE_EOFP] = ~alignes_pair & (state_send_eof);
assign select_prim[CODE_WTRMP] = ~alignes_pair & (state_wait);
assign select_prim[CODE_RRDYP] = ~alignes_pair & (state_rcvr_rdy);
assign select_prim[CODE_IPP] = ~alignes_pair & (state_rcvr_data & ~incom_stop_f | state_rcvr_eof | state_rcvr_goodcrc);
assign select_prim[CODE_DMATP] = ~alignes_pair & (state_rcvr_data & incom_stop_f | state_rcvr_shold & incom_stop_f);
assign select_prim[CODE_OKP] = ~alignes_pair & (state_rcvr_goodend);
assign select_prim[CODE_ERRP] = ~alignes_pair & (state_rcvr_badend);
// primitive selector MUX
always @ (posedge clk)
to_phy_data <= rst ? {DATA_BYTE_WIDTH*8{1'b0}}:
{DATA_BYTE_WIDTH*8{select_prim[CODE_SYNCP]}} & prim_data[CODE_SYNCP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_ALIGNP]}} & prim_data[CODE_ALIGNP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_RRDYP]}} & prim_data[CODE_RRDYP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_SOFP]}} & prim_data[CODE_SOFP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_HOLDAP]}} & prim_data[CODE_HOLDAP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_HOLDP]}} & prim_data[CODE_HOLDP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_EOFP]}} & prim_data[CODE_EOFP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_WTRMP]}} & prim_data[CODE_WTRMP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_XRDYP]}} & prim_data[CODE_XRDYP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_IPP]}} & prim_data[CODE_IPP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_DMATP]}} & prim_data[CODE_DMATP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_OKP]}} & prim_data[CODE_OKP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_ERRP]}} & prim_data[CODE_ERRP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_CRC]}} & prim_data[CODE_CRC] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_DATA]}} & prim_data[CODE_DATA];
always @ (posedge clk)
to_phy_isk <= rst | ~select_prim[CODE_DATA] & ~select_prim[CODE_CRC] ? {{(DATA_BYTE_WIDTH - 1){1'b0}}, 1'b1} : {DATA_BYTE_WIDTH{1'b0}} ;
// incoming data is data
wire inc_is_data;
assign inc_is_data = dword_val & rcvd_dword[CODE_DATA] & (state_rcvr_data | state_rcvr_rhold);
/*
* Scrambler can work both as a scrambler and a descramler, because data stream could be
* one direction at a time
*/
scrambler scrambler(
.rst (select_prim[CODE_SOFP] | dword_val & rcvd_dword[CODE_SOFP]),
.clk (clk),
.val_in (select_prim[CODE_DATA] | inc_is_data),
.data_in (crc_dword & {DATA_BYTE_WIDTH*8{select_prim[CODE_CRC]}} |
data_in & {DATA_BYTE_WIDTH*8{select_prim[CODE_DATA]}} |
phy_data_in & {DATA_BYTE_WIDTH*8{inc_is_data}}),
.data_out (scrambler_out)
);
/*
* Same as for scrambler, crc computation for both directions
*/
crc crc(
.clk (clk),
.rst (select_prim[CODE_SOFP] | dword_val & rcvd_dword[CODE_SOFP]),
.val_in (select_prim[CODE_DATA] | inc_is_data),
.data_in (data_in & {DATA_BYTE_WIDTH*8{select_prim[CODE_DATA]}} | scrambler_out & {DATA_BYTE_WIDTH*8{inc_is_data}}),
.crc_out (crc_dword)
);
// the output of crc module shall be 0 if 1 tick later reciever got a crc checksum and no errors occured
assign crc_good = ~|crc_dword & state_rcvr_eof;
assign crc_bad = |crc_dword & state_rcvr_eof;
// to TL data outputs assigment
// delay outputs so the last data would be marked
reg [31:0] data_out_r;
reg data_val_out_r;
reg [31:0] data_out_rr;
reg data_val_out_rr;
// if current == EOF => _r == CRC and _rr == last data piece
always @ (posedge clk)
begin
data_out_r <= scrambler_out;
data_out_rr <= data_out_r;
data_val_out_r <= inc_is_data;
data_val_out_rr <= data_val_out_r & ~set_rcvr_eof; // means that @ previous clock cycle the delivered data was crc
end
assign data_out = data_out_rr;
assign data_mask_out = 2'b11;//{DATA_BYTE_WIDTH/2{1'b1}};
assign data_val_out = data_val_out_rr;
assign data_last_out = set_rcvr_eof;
// from TL data
// gives a strobe everytime data is present and we're at a corresponding state.
assign data_strobe_out = select_prim[CODE_DATA];
// assign phy data outputs
assign phy_data_out = to_phy_data;
assign phy_isk_out = to_phy_isk;
assign frame_busy = ~state_idle;
assign frame_ack = state_send_sof;
assign frame_rej = set_rcvr_wait & state_send_rdy & ~alignes_pair;
// incoming fises detected
assign incom_start = set_rcvr_wait & ~alignes_pair;
// ... and processed
assign incom_done = set_rcvr_goodcrc & ~alignes_pair;
// or the FIS had errors
assign incom_invalidate = state_rcvr_eof & crc_bad & ~alignes_pair | state_rcvr_data & dword_val & rcvd_dword[CODE_WTRMP]
| (state_rcvr_wait | state_rcvr_rdy | state_rcvr_data | state_rcvr_rhold | state_rcvr_shold | state_rcvr_eof | state_rcvr_goodcrc) & got_escape;
// shows that incoming primitive or data is ready to be processed // TODO somehow move alignes_pair into dword_val
assign dword_val = |rcvd_dword & phy_ready & ~rcvd_dword[CODE_ALIGNP];
// determine imcoming primitive type
assign rcvd_dword[CODE_DATA] = ~|phy_isk_in;
assign rcvd_dword[CODE_CRC] = 1'b0;
assign rcvd_dword[CODE_SYNCP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_SYNCP ] == phy_data_in;
assign rcvd_dword[CODE_ALIGNP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_ALIGNP] == phy_data_in;
assign rcvd_dword[CODE_XRDYP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_XRDYP ] == phy_data_in;
assign rcvd_dword[CODE_SOFP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_SOFP ] == phy_data_in;
assign rcvd_dword[CODE_HOLDAP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_HOLDAP] == phy_data_in;
assign rcvd_dword[CODE_HOLDP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_HOLDP ] == phy_data_in;
assign rcvd_dword[CODE_EOFP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_EOFP ] == phy_data_in;
assign rcvd_dword[CODE_WTRMP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_WTRMP ] == phy_data_in;
assign rcvd_dword[CODE_RRDYP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_RRDYP ] == phy_data_in;
assign rcvd_dword[CODE_IPP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_IPP ] == phy_data_in;
assign rcvd_dword[CODE_DMATP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_DMATP ] == phy_data_in;
assign rcvd_dword[CODE_OKP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_OKP ] == phy_data_in;
assign rcvd_dword[CODE_ERRP] = phy_isk_in[0] == 1'b1 & ~|phy_isk_in[DATA_BYTE_WIDTH-1:1] & prim_data[CODE_ERRP ] == phy_data_in;
// phy level errors handling TODO
assign dec_err = |phy_err_in;
// form a response to transport layer
wire frame_done;
assign frame_done = frame_done_good | frame_done_bad;
assign frame_done_good = state_wait & dword_val & rcvd_dword[CODE_OKP];
assign frame_done_bad = state_wait & dword_val & rcvd_dword[CODE_ERRP];
`ifdef CHECKERS_ENABLED
// incoming primitives
always @ (posedge clk)
if (~|rcvd_dword & phy_ready)
begin
$display("%m: invalid primitive recieved : %h, conrol : %h, err : %h", phy_data_in, phy_isk_in, phy_err_in);
$finish;
end
// States checker
reg [STATES_COUNT - 1:0] sim_states_concat;
always @ (posedge clk)
if (~rst)
if (( 32'h0
+ state_idle
+ state_sync_esc
+ state_nocommerr
+ state_nocomm
+ state_align
+ state_reset
+ state_send_rdy
+ state_send_sof
+ state_send_data
+ state_send_rhold
+ state_send_shold
+ state_send_crc
+ state_send_eof
+ state_wait
+ state_rcvr_wait
+ state_rcvr_rdy
+ state_rcvr_data
+ state_rcvr_rhold
+ state_rcvr_shold
+ state_rcvr_eof
+ state_rcvr_goodcrc
+ state_rcvr_goodend
+ state_rcvr_badend
) != 1)
begin
sim_states_concat = {
state_idle
, state_sync_esc
, state_nocommerr
, state_nocomm
, state_align
, state_reset
, state_send_rdy
, state_send_sof
, state_send_data
, state_send_rhold
, state_send_shold
, state_send_crc
, state_send_eof
, state_wait
, state_rcvr_wait
, state_rcvr_rdy
, state_rcvr_data
, state_rcvr_rhold
, state_rcvr_shold
, state_rcvr_eof
, state_rcvr_goodcrc
, state_rcvr_goodend
, state_rcvr_badend
};
$display("%m: invalid states: %b", sim_states_concat);
$finish;
end
`endif
`ifdef SIMULATION
always @ (posedge clk)
begin
if (data_val_out) begin
$display("[Host] LINK: From device - received data = %h", data_out);
end
// if (inc_is_data) begin
// $display("[Host] LINK: From device - received raw data = %h", phy_data_in);
// end
end
`endif
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/oob.v 0000664 0000000 0000000 00000040171 12572445207 0021747 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: oob
* Date: 2015-07-11
* Author: Alexey
* Description: sata oob unit implementation
*
* Copyright (c) 2015 Elphel, Inc.
* oob.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* oob.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/*
* For now both device and host shall be set up to SATA2 speeds.
* Need to think how to change speed grades on fly (either to broaden
* data iface width or to change RXRATE/TXRATE)
*/
// All references to doc = to SerialATA_Revision_2_6_Gold.pdf
module oob #(
parameter DATA_BYTE_WIDTH = 4,
parameter CLK_SPEED_GRADE = 1 // 1 - 75 Mhz, 2 - 150Mhz, 4 - 300Mhz
)
(
// sata clk = usrclk2
input wire clk,
// reset oob
input wire rst,
// oob responces
input wire rxcominitdet_in,
input wire rxcomwakedet_in,
input wire rxelecidle_in,
// oob issues
output wire txcominit,
output wire txcomwake,
output wire txelecidle,
// partial tx reset
output wire txpcsreset_req,
input wire recal_tx_done,
// rx reset (after rxelecidle -> 0)
output wire rxreset_req,
input wire rxreset_ack,
// input data stream (if any data during OOB setting => ignored)
input wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_in,
input wire [DATA_BYTE_WIDTH - 1:0] txcharisk_in,
// output data stream to gtx
output wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_out,
output wire [DATA_BYTE_WIDTH - 1:0] txcharisk_out,
// input data from gtx
input wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_in,
input wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_in,
// bypassed data from gtx
output wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_out,
output wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_out,
// oob sequence needs to be issued
input wire oob_start,
// connection established, all further data is valid
output wire oob_done,
// oob can't handle new start request
output wire oob_busy,
// doc p265, link is established after 3back-to-back non-ALIGNp
output wire link_up,
// link goes down - if rxelecidle
output wire link_down,
// the device itself sends cominit
output wire cominit_req,
// allow to respond to cominit
input wire cominit_allow,
// status information to handle by a control block if any exists
// incompatible host-device speed grades (host cannot lock to alignp)
output wire oob_incompatible,
// timeout in an unexpected place
output wire oob_error,
// noone responds to our cominits
output wire oob_silence
`ifdef OOB_MULTISPEED
//TODO
// !!Implement it later on, ref to gen.adjustment fsm in the notebook!!
// speed grade control
,
// current speed grade, dynamic instead of static parameter
input wire [2:0] speed_grade,
// clock to be adjusted to best speed
input wire adj_clk,
// ask for slower protocol clock
output wire speed_down_req,
input wire speed_down_ack,
// reset speedgrade to the fastest one
output wire speed_rst_req,
input wire speed_rst_ack
`endif //OOB_MULTISPEED
);
// 873.8 us error timer
// = 2621400 SATA2 serial ticks (period = 0.000333 us)
// = 131070 ticks @ 150Mhz
// = 65535 ticks @ 75Mhz
localparam [19:0] CLK_TO_TIMER_CONTRIB = CLK_SPEED_GRADE == 1 ? 20'h4 :
CLK_SPEED_GRADE == 2 ? 20'h2 :
CLK_SPEED_GRADE == 4 ? 20'h1 : 20'h1;
`ifdef SIMULATION
localparam [19:0] TIMER_LIMIT = 19'd20000;
`else
localparam [19:0] TIMER_LIMIT = 19'd262140;
`endif
reg [19:0] timer;
wire timer_clr;
wire timer_fin;
// latching inputs from gtx
reg rxcominitdet;
reg rxcomwakedet;
reg rxelecidle;
reg [DATA_BYTE_WIDTH*8 - 1:0] rxdata;
reg [DATA_BYTE_WIDTH - 1:0] rxcharisk;
// primitives detection
wire detected_alignp;
wire detected_syncp;
// wait until device's cominit is done
reg cominit_req_l;
reg rxcominitdet_l;
reg rxcomwakedet_l;
wire rxcominit_done;
wire rxcomwake_done;
reg [9:0] rxcom_timer;
// for 75MHz : period of cominit = 426.7 ns = 32 ticks => need to wait x6 pulses + 1 as an insurance => 224 clock cycles. Same thoughts for comwake
localparam COMINIT_DONE_TIME = 896; // 300Mhz cycles
localparam COMWAKE_DONE_TIME = 448; // 300Mhz cycles
// wait until rxelecidle is not stable (more or less) deasserted
// let's say, if rxelecidle = 0 longer, than 2 comwake burst duration (2 * 106.7 ns), elecidle is stable and we're receiving some data
// 2 * 106.7ns = 64 clock cycles @ 300 MHz, 32 @ 150, 16 @ 75
// rxelecidle is synchronous to sata host clk, sooo some idle raises can occur insensibly. Still, it means line issues,
// not affecting the fact, oob was done and a stage when device sends alignps started
reg [7:0] eidle_timer;
wire eidle_timer_done;
// fsm, doc p265,266
wire state_idle;
reg state_wait_cominit;
reg state_wait_comwake;
reg state_recal_tx;
reg state_wait_eidle;
reg state_wait_rxrst;
reg state_wait_align;
reg state_wait_synp;
reg state_wait_linkup;
reg state_error;
wire set_wait_cominit;
wire set_wait_comwake;
wire set_recal_tx;
wire set_wait_eidle;
wire set_wait_rxrst;
wire set_wait_align;
wire set_wait_synp;
wire set_wait_linkup;
wire set_error;
wire clr_wait_cominit;
wire clr_wait_comwake;
wire clr_recal_tx;
wire clr_wait_eidle;
wire clr_wait_rxrst;
wire clr_wait_align;
wire clr_wait_synp;
wire clr_wait_linkup;
wire clr_error;
assign state_idle = ~state_wait_cominit & ~state_wait_comwake & ~state_wait_align & ~state_wait_synp & ~state_wait_linkup & ~state_error & ~state_recal_tx & ~state_wait_rxrst & ~state_wait_eidle;
always @ (posedge clk)
begin
state_wait_cominit <= (state_wait_cominit | set_wait_cominit) & ~clr_wait_cominit & ~rst;
state_wait_comwake <= (state_wait_comwake | set_wait_comwake) & ~clr_wait_comwake & ~rst;
state_recal_tx <= (state_recal_tx | set_recal_tx ) & ~clr_recal_tx & ~rst;
state_wait_eidle <= (state_wait_eidle | set_wait_eidle ) & ~clr_wait_eidle & ~rst;
state_wait_rxrst <= (state_wait_rxrst | set_wait_rxrst ) & ~clr_wait_rxrst & ~rst;
state_wait_align <= (state_wait_align | set_wait_align ) & ~clr_wait_align & ~rst;
state_wait_synp <= (state_wait_synp | set_wait_synp ) & ~clr_wait_synp & ~rst;
state_wait_linkup <= (state_wait_linkup | set_wait_linkup ) & ~clr_wait_linkup & ~rst;
state_error <= (state_error | set_error ) & ~clr_error & ~rst;
end
assign set_wait_cominit = state_idle & oob_start & ~cominit_req;
assign set_wait_comwake = state_idle & cominit_req_l & cominit_allow & rxcominit_done | state_wait_cominit & rxcominitdet_l & rxcominit_done;
assign set_recal_tx = state_wait_comwake & rxcomwakedet_l & rxcomwake_done;
assign set_wait_eidle = state_recal_tx & recal_tx_done;
assign set_wait_rxrst = state_wait_eidle & eidle_timer_done;
assign set_wait_align = state_wait_rxrst & rxreset_ack;
assign set_wait_synp = state_wait_align & detected_alignp;
assign set_wait_linkup = state_wait_synp & detected_syncp;
assign set_error = timer_fin & (state_wait_cominit | state_wait_comwake | state_recal_tx | state_wait_eidle | state_wait_rxrst | state_wait_align | state_wait_synp/* | state_wait_linkup*/);
assign clr_wait_cominit = set_wait_comwake | set_error;
assign clr_wait_comwake = set_recal_tx | set_error;
assign clr_recal_tx = set_wait_eidle | set_error;
assign clr_wait_eidle = set_wait_rxrst | set_error;
assign clr_wait_rxrst = set_wait_align | set_error;
assign clr_wait_align = set_wait_synp | set_error;
assign clr_wait_synp = set_wait_linkup | set_error;
assign clr_wait_linkup = state_wait_linkup; //TODO not so important, but still have to trace 3 back-to-back non alignp primitives
assign clr_error = state_error;
// waiting timeout timer
assign timer_fin = timer == TIMER_LIMIT;
assign timer_clr = set_error | state_error | state_idle;
always @ (posedge clk)
timer <= rst | timer_clr ? 20'h0 : timer + CLK_TO_TIMER_CONTRIB;
// something is wrong with speed grades if the host cannot lock to device's alignp stream
assign oob_incompatible = state_wait_align & set_error;
// oob sequence is done, everything is okay
assign oob_done = set_wait_linkup;
// noone responds to cominits
assign oob_silence = set_error & state_wait_cominit;
// other timeouts
assign oob_error = set_error & ~oob_silence & ~oob_incompatible;
// obvioud
assign oob_busy = ~state_idle;
// ask for recalibration
assign txpcsreset_req = state_recal_tx;
// ask for rxreset
assign rxreset_req = state_wait_rxrst;
// set gtx controls
reg txelecidle_r;
always @ (posedge clk)
txelecidle_r <= rst ? 1'b1 : /*clr_wait_cominit */ clr_wait_comwake ? 1'b0 : set_wait_cominit ? 1'b1 : txelecidle_r;
assign txcominit = set_wait_cominit;
assign txcomwake = set_wait_comwake;
assign txelecidle = set_wait_cominit | txelecidle_r;
// indicate if link up condition was made
assign link_up = clr_wait_linkup;
// link goes down when line is idle
reg rxelecidle_r;
reg rxelecidle_rr;
always @ (posedge clk)
begin
rxelecidle_rr <= rxelecidle_r;
rxelecidle_r <= rxelecidle;
end
assign link_down = rxelecidle_rr;
// indicate that device is requesting for oob
reg cominit_req_r;
wire cominit_req_set;
assign cominit_req_set = state_idle & rxcominitdet;
always @ (posedge clk)
cominit_req_r <= (cominit_req_r | cominit_req_set) & ~(cominit_allow & cominit_req) & ~rst;
assign cominit_req = cominit_req_set | cominit_req_r;
// detect which primitives sends the device after comwake was done
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg detected_alignp_f;
always @ (posedge clk)
detected_alignp_f <= rst | ~state_wait_align ? 1'b0 :
~|(rxdata ^ {8'b01001010, 8'b10111100}) & ~|(rxcharisk ^ 2'b01); // {D10.2, K28.5}
assign detected_alignp = detected_alignp_f & ~|(rxdata ^ {8'b01111011, 8'b01001010}) & ~|(rxcharisk ^ 2'b00); // {D27.3, D10.2}
reg detected_syncp_f;
always @ (posedge clk)
detected_syncp_f <= rst | ~state_wait_synp ? 1'b0 :
~|(rxdata ^ {8'b10010101, 8'b01111100}) & ~|(rxcharisk ^ 2'b01); // {D21.4, K28.3}
assign detected_syncp = detected_syncp_f & ~|(rxdata ^ {8'b10110101, 8'b10110101}) & ~|(rxcharisk ^ 2'b00); // {D21.5, D21.5}
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign detected_alignp = ~|(rxdata ^ {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}) & ~|(rxcharisk ^ 4'h1); // {D27.3, D10.2, D10.2, K28.5}
assign detected_syncp = ~|(rxdata ^ {8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}) & ~|(rxcharisk ^ 4'h1); // {D21.5, D21.5, D21.4, K28.3}
end
else
if (DATA_BYTE_WIDTH == 8)
begin
assign detected_alignp = ~|(rxdata ^ {2{8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}}) & ~|(rxcharisk ^ 8'h11); // {D27.3, D10.2, D10.2, K28.5}
assign detected_syncp = ~|(rxdata ^ {2{8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}}) & ~|(rxcharisk ^ 8'h11); // {D21.5, D21.5, D21.4, K28.3}
end
else
begin
always @ (posedge clk)
begin
$display("%m oob module works only with 16/32/64 gtx input data width");
$finish;
end
end
endgenerate
// calculate an aproximate time when oob burst shall be done
assign rxcominit_done = rxcom_timer == COMINIT_DONE_TIME & state_wait_cominit;
assign rxcomwake_done = rxcom_timer == COMWAKE_DONE_TIME & state_wait_comwake;
always @ (posedge clk) begin
cominit_req_l <= rst | rxcominit_done | ~state_idle ? 1'b0 : cominit_req ? 1'b1 : cominit_req_l;
rxcominitdet_l <= rst | rxcominit_done | ~state_wait_cominit ? 1'b0 : rxcominitdet ? 1'b1 : rxcominitdet_l;
rxcomwakedet_l <= rst | rxcomwake_done | ~state_wait_comwake ? 1'b0 : rxcomwakedet ? 1'b1 : rxcomwakedet_l;
end
// buf inputs from gtx
always @ (posedge clk)
begin
rxcominitdet <= rxcominitdet_in;
rxcomwakedet <= rxcomwakedet_in;
rxelecidle <= rxelecidle_in;
rxdata <= rxdata_in;
rxcharisk <= rxcharisk_in;
end
// set data outputs to upper levels
assign rxdata_out = rxdata;
assign rxcharisk_out = rxcharisk;
// as depicted @ doc, p264, figure 163, have to insert D10.2 and align primitives after
// getting comwake from device
reg [DATA_BYTE_WIDTH*8 - 1:0] txdata;
reg [DATA_BYTE_WIDTH - 1:0] txcharisk;
wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_d102;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_d102;
wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_align;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_align;
always @ (posedge clk)
begin
txdata <= state_wait_align ? txdata_d102 :
state_wait_rxrst ? txdata_d102 :
state_wait_synp ? txdata_align : txdata_in;
txcharisk <= state_wait_align ? txcharisk_d102 :
state_wait_rxrst ? txcharisk_d102 :
state_wait_synp ? txcharisk_align : txcharisk_in;
end
// Continious D10.2 primitive
assign txcharisk_d102 = {DATA_BYTE_WIDTH{1'b0}};
assign txdata_d102 = {DATA_BYTE_WIDTH{8'b01001010}};
// Align primitive: K28.5 + D10.2 + D10.2 + D27.3
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg align_odd;
always @ (posedge clk)
align_odd <= rst | ~state_wait_synp ? 1'b0 : ~align_odd;
assign txcharisk_align = align_odd ? 2'b01 : 2'b00;
assign txdata_align = align_odd ? {8'b01001010, 8'b10111100} : // {D10.2, K28.5}
{8'b01111011, 8'b01001010}; // {D27.3, D10.2}
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign txcharisk_align = 4'h1;
assign txdata_align = {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}; // {D27.3, D10.2, D10.2, K28.5}
end
else
if (DATA_BYTE_WIDTH == 8)
begin
assign txcharisk_align = 8'h11;
assign txdata_align = {2{8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}}; // 2x{D27.3, D10.2, D10.2, K28.5}
end
else
always @ (posedge clk)
begin
$display("%m oob module works only with 16/32/64 gtx input data width");
$finish;
end
endgenerate
`ifdef SIMULATION
// info msgs
always @ (posedge clk)
begin
if (txcominit) begin
$display("[Host] OOB: Issued cominit");
end
if (txcomwake) begin
$display("[Host] OOB: Issued comwake");
end
if (state_wait_linkup) begin
$display("[Host] OOB: Link is up");
end
if (set_wait_synp) begin
$display("[Host] OOB: Started continious align sending");
end
end
`endif
always @ (posedge clk)
rxcom_timer <= rst | rxcominit_done & state_wait_cominit | rxcomwake_done & state_wait_comwake | rxcominitdet & state_wait_cominit | rxcomwakedet & state_wait_comwake ? 10'h0 : cominit_req_l & state_idle | rxcominitdet_l & state_wait_cominit | rxcomwakedet_l & state_wait_comwake ? rxcom_timer + CLK_TO_TIMER_CONTRIB : 10'h0;
// set data outputs to gtx
assign txdata_out = txdata;
assign txcharisk_out = txcharisk;
// rxelectidle timer logic
assign eidle_timer_done = eidle_timer == 64;
always @ (posedge clk)
eidle_timer <= rst | rxelecidle | ~state_wait_eidle ? 8'b0 : eidle_timer + CLK_TO_TIMER_CONTRIB;
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/oob_ctrl.v 0000664 0000000 0000000 00000014304 12572445207 0022772 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: oob_ctrl
* Date: 2015-07-11
* Author: Alexey
* Description: module to start oob sequences and to handle errors
*
* Copyright (c) 2015 Elphel, Inc.
* oob_ctrl.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* oob_ctrl.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`include "oob.v"
module oob_ctrl #(
parameter DATA_BYTE_WIDTH = 4,
parameter CLK_SPEED_GRADE = 1 // 1 - 75 Mhz, 2 - 150Mhz, 4 - 300Mhz
)
(
// sata clk = usrclk2
input wire clk,
// reset oob
input wire rst,
// gtx is ready = all resets are done
input wire gtx_ready,
// oob responces
input wire rxcominitdet_in,
input wire rxcomwakedet_in,
input wire rxelecidle_in,
// oob issues
output wire txcominit,
output wire txcomwake,
output wire txelecidle,
// partial tx reset
output wire txpcsreset_req,
input wire recal_tx_done,
// rx reset (after rxelecidle -> 0)
output wire rxreset_req,
input wire rxreset_ack,
// input data stream (if any data during OOB setting => ignored)
input wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_in,
input wire [DATA_BYTE_WIDTH - 1:0] txcharisk_in,
// output data stream to gtx
output wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_out,
output wire [DATA_BYTE_WIDTH - 1:0] txcharisk_out,
// input data from gtx
input wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_in,
input wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_in,
// bypassed data from gtx
output wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_out,
output wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_out,
// obvious
input wire rxbyteisaligned,
// shows if channel is ready
output wire phy_ready
);
// oob sequence needs to be issued
wire oob_start;
// connection established, all further data is valid
wire oob_done;
// doc p265, link is established after 3back-to-back non-ALIGNp
wire link_up;
wire link_down;
// the device itself sends cominit
wire cominit_req;
// allow to respond to cominit
wire cominit_allow;
// status information to handle by a control block if any exists
// incompatible host-device speed grades (host cannot lock to alignp)
wire oob_incompatible; // TODO
// timeout in an unexpected place
wire oob_error;
// noone responds to our cominits
wire oob_silence;
// obvious
wire oob_busy;
// 1 - link is up and running, 0 - probably not
reg link_state;
// 1 - connection is being established OR already established, 0 - is not
reg oob_state;
assign phy_ready = link_state & gtx_ready & rxbyteisaligned;
always @ (posedge clk)
link_state <= (link_state | link_up) & ~link_down & ~rst;
always @ (posedge clk)
oob_state <= (oob_state | oob_start | cominit_req & cominit_allow) & ~oob_error & ~oob_silence & ~(link_down & ~oob_busy & ~oob_start) & ~rst;
// decide when to issue oob: always when gtx is ready
assign oob_start = gtx_ready & ~oob_state & ~oob_busy;
// set line to idle state before if we're waiting for a device to answer AND while oob sequence
wire txelecidle_inner;
assign txelecidle = /*~oob_state |*/ txelecidle_inner;
// let devices always begin oob sequence, if only it's not a glitch
assign cominit_allow = cominit_req & link_state;
oob #(
.DATA_BYTE_WIDTH (DATA_BYTE_WIDTH),
.CLK_SPEED_GRADE (CLK_SPEED_GRADE)
)
oob
(
// sata clk = usrclk2
.clk (clk),
// reset oob
.rst (rst),
// oob responces
.rxcominitdet_in (rxcominitdet_in),
.rxcomwakedet_in (rxcomwakedet_in),
.rxelecidle_in (rxelecidle_in),
// oob issues
.txcominit (txcominit),
.txcomwake (txcomwake),
.txelecidle (txelecidle_inner),
.txpcsreset_req (txpcsreset_req),
.recal_tx_done (recal_tx_done),
.rxreset_req (rxreset_req),
.rxreset_ack (rxreset_ack),
// input data stream (if any data during OOB setting => ignored)
.txdata_in (txdata_in),
.txcharisk_in (txcharisk_in),
// output data stream to gtx
.txdata_out (txdata_out),
.txcharisk_out (txcharisk_out),
// input data from gtx
.rxdata_in (rxdata_in),
.rxcharisk_in (rxcharisk_in),
// bypassed data from gtx
.rxdata_out (rxdata_out),
.rxcharisk_out (rxcharisk_out),
// oob sequence needs to be issued
.oob_start (oob_start),
// connection established, all further data is valid
.oob_done (oob_done),
// doc p265, link is established after 3back-to-back non-ALIGNp
.link_up (link_up),
.link_down (link_down),
// the device itself sends cominit
.cominit_req (cominit_req),
// allow to respond to cominit
.cominit_allow (cominit_allow),
// status information to handle by a control block if any exists
// incompatible host-device speed grades (host cannot lock to alignp)
.oob_incompatible (oob_incompatible),
// timeout in an unexpected place
.oob_error (oob_error),
// noone responds to our cominits
.oob_silence (oob_silence),
// oob can't handle new start request
.oob_busy (oob_busy)
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/sata_host.v 0000664 0000000 0000000 00000072522 12572445207 0023162 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: sata_host
* Date: 2015-07-11
* Author: Alexey
* Description: is a wrapper for command + transport + link + phy levels
*
* Copyright (c) 2015 Elphel, Inc.
* sata_host.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sata_host.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`include "sata_phy.v"
`include "link.v"
`include "transport.v"
`include "command.v"
module sata_host(
input wire extrst,
// sata rst
output wire rst,
// sata clk
output wire clk,
// temporary
input wire [31:0] al_cmd_in, // == {cmd_type, cmd_port, cmd_val, cmd_done_bad, cmd_done_good; cmd_busy}
input wire al_cmd_val_in,
output wire [31:0] al_cmd_out, // same
// tmp inputs directly from registers for each and every shadow register and control bit
// from al
input wire [31:0] al_sh_data_in, // write data
input wire al_sh_data_val_in, // write strobe
input wire al_sh_data_strobe_in, // read strobe
input wire [15:0] al_sh_feature_in,
input wire al_sh_feature_val_in,
input wire [23:0] al_sh_lba_lo_in,
input wire al_sh_lba_lo_val_in,
input wire [23:0] al_sh_lba_hi_in,
input wire al_sh_lba_hi_val_in,
input wire [15:0] al_sh_count_in,
input wire al_sh_count_val_in,
input wire [7:0] al_sh_command_in,
input wire al_sh_command_val_in,
input wire [7:0] al_sh_dev_in,
input wire al_sh_dev_val_in,
input wire [7:0] al_sh_control_in,
input wire al_sh_control_val_in,
input wire [31:0] al_sh_dma_id_lo_in,
input wire al_sh_dma_id_lo_val_in,
input wire [31:0] al_sh_dma_id_hi_in,
input wire al_sh_dma_id_hi_val_in,
input wire [31:0] al_sh_buf_off_in,
input wire al_sh_buf_off_val_in,
input wire [15:0] al_sh_tran_cnt_in,
input wire al_sh_tran_cnt_val_in,
input wire al_sh_autoact_in,
input wire al_sh_autoact_val_in,
input wire al_sh_inter_in,
input wire al_sh_inter_val_in,
input wire al_sh_dir_in,
input wire al_sh_dir_val_in,
input wire [31:0] al_sh_dma_cnt_in,
input wire al_sh_dma_cnt_val_in,
input wire al_sh_notif_in,
input wire al_sh_notif_val_in,
input wire [3:0] al_sh_port_in,
input wire al_sh_port_val_in,
// outputs from shadow registers
output wire sh_data_val_out,
output wire [31:0] sh_data_out,
output wire [7:0] sh_control_out,
output wire [15:0] sh_feature_out,
output wire [47:0] sh_lba_out,
output wire [15:0] sh_count_out,
output wire [7:0] sh_command_out,
output wire [7:0] sh_err_out,
output wire [7:0] sh_status_out,
output wire [7:0] sh_estatus_out, // E_Status
output wire [7:0] sh_dev_out,
output wire [3:0] sh_port_out,
output wire sh_inter_out,
output wire sh_dir_out,
output wire [63:0] sh_dma_id_out,
output wire [31:0] sh_dma_off_out,
output wire [31:0] sh_dma_cnt_out,
output wire [15:0] sh_tran_cnt_out, // Transfer Count
output wire sh_notif_out,
output wire sh_autoact_out,
// top-level ifaces
// ref clk from an external source, shall be connected to pads
input wire extclk_p,
input wire extclk_n,
// sata physical link data pins
output wire txp_out,
output wire txn_out,
input wire rxp_in,
input wire rxn_in
);
/*
initial
begin
$dumpfile("dump.vcd");
$dumpvars(0, sata_host);
end
*/
parameter DATA_BYTE_WIDTH = 4;
// tl cmd iface
wire [2:0] cl2tl_cmd_type;
wire cl2tl_cmd_val;
wire [3:0] cl2tl_cmd_port;
wire cl2tl_cmd_busy;
wire cl2tl_cmd_done_good;
wire cl2tl_cmd_done_bad;
// data from tl
wire [31:0] tl2cl_data;
wire tl2cl_data_val;
wire tl2cl_data_last;
wire tl2cl_data_busy;
// to tl
wire [31:0] cl2tl_data;
wire cl2tl_data_last;
wire cl2tl_data_val;
wire cl2tl_data_strobe;
// from tl
wire [47:0] tl2cl_sh_lba;
wire [15:0] tl2cl_sh_count;
wire [7:0] tl2cl_sh_command;
wire [7:0] tl2cl_sh_err;
wire [7:0] tl2cl_sh_status;
wire [7:0] tl2cl_sh_estatus; // E_Status
wire [7:0] tl2cl_sh_dev;
wire [3:0] tl2cl_sh_port;
wire tl2cl_shter_in;
wire tl2cl_sh_dir;
wire tl2cl_sh_inter;
wire [63:0] tl2cl_sh_dma_id;
wire [31:0] tl2cl_sh_dma_off;
wire [31:0] tl2cl_sh_dma_cnt;
wire [15:0] tl2cl_sh_tran_cnt; // Transfer Count
wire tl2cl_sh_notif;
wire tl2cl_sh_autoact;
wire tl2cl_sh_lba_val;
wire tl2cl_sh_count_val;
wire tl2cl_sh_command_val;
wire tl2cl_sh_err_val;
wire tl2cl_sh_status_val;
wire tl2cl_sh_estatus_val; // E_Status
wire tl2cl_sh_dev_val;
wire tl2cl_sh_port_val;
wire tl2cl_shter_val_in;
wire tl2cl_sh_dir_val;
wire tl2cl_sh_inter_val;
wire tl2cl_sh_dma_id_val;
wire tl2cl_sh_dma_off_val;
wire tl2cl_sh_dma_cnt_val;
wire tl2cl_sh_tran_cnt_val; // Transfer Count
wire tl2cl_sh_notif_val;
wire tl2cl_sh_autoact_val;
// all regs to output
wire sh_data_val;
wire [31:0] sh_data;
wire [7:0] sh_control;
wire [15:0] sh_feature;
wire [47:0] sh_lba;
wire [15:0] sh_count;
wire [7:0] sh_command;
wire [7:0] sh_err;
wire [7:0] sh_status;
wire [7:0] sh_estatus; // E_Status
wire [7:0] sh_dev;
wire [3:0] sh_port;
wire sh_inter;
wire sh_dir;
wire [63:0] sh_dma_id;
wire [31:0] sh_dma_off;
wire [31:0] sh_dma_cnt;
wire [15:0] sh_tran_cnt; // Transfer Count
wire sh_notif;
wire sh_autoact;
assign sh_data_val_out = sh_data_val;
assign sh_data_out = sh_data;
assign sh_control_out = sh_control;
assign sh_feature_out = sh_feature;
assign sh_lba_out = sh_lba;
assign sh_count_out = sh_count;
assign sh_command_out = sh_command;
assign sh_err_out = sh_err;
assign sh_status_out = sh_status;
assign sh_estatus_out = sh_estatus;
assign sh_dev_out = sh_dev;
assign sh_port_out = sh_port;
assign sh_inter_out = sh_inter;
assign sh_dir_out = sh_dir;
assign sh_dma_id_out = sh_dma_id;
assign sh_dma_off_out = sh_dma_off;
assign sh_dma_cnt_out = sh_dma_cnt;
assign sh_tran_cnt_out = sh_tran_cnt;
assign sh_notif_out = sh_notif;
assign sh_autoact_out = sh_autoact;
command command(
.rst (rst),
.clk (clk),
// tl cmd iface
.cmd_type (cl2tl_cmd_type),
.cmd_val (cl2tl_cmd_val),
.cmd_port (cl2tl_cmd_port),
.cmd_busy (cl2tl_cmd_busy),
.cmd_done_good (cl2tl_cmd_done_good),
.cmd_done_bad (cl2tl_cmd_done_bad),
// temporary TODO
.al_cmd_in (al_cmd_in), // == {cmd_type, cmd_port, cmd_val, cmd_done_bad, cmd_done_good, cmd_busy}
.al_cmd_val_in (al_cmd_val_in),
.al_cmd_out (al_cmd_out), // same
// data from tl
.tl_data_in (tl2cl_data),
.tl_data_val_in (tl2cl_data_val),
.tl_data_last_in (tl2cl_data_last),
.tl_data_busy_out (tl2cl_data_busy),
// to tl
.tl_data_out (cl2tl_data),
.tl_data_last_out (cl2tl_data_last),
.tl_data_val_out (cl2tl_data_val),
.tl_data_strobe_in (cl2tl_data_strobe),
// tmp inputs directly from registers for each and every shadow register and control bit
// from al
.al_sh_data_in (al_sh_data_in), // write data
.al_sh_data_val_in (al_sh_data_val_in), // write strobe
.al_sh_data_strobe_in (al_sh_data_strobe_in), // read strobe
.al_sh_feature_in (al_sh_feature_in),
.al_sh_feature_val_in (al_sh_feature_val_in),
.al_sh_lba_lo_in (al_sh_lba_lo_in),
.al_sh_lba_lo_val_in (al_sh_lba_lo_val_in),
.al_sh_lba_hi_in (al_sh_lba_hi_in),
.al_sh_lba_hi_val_in (al_sh_lba_hi_val_in),
.al_sh_count_in (al_sh_count_in),
.al_sh_count_val_in (al_sh_count_val_in),
.al_sh_command_in (al_sh_command_in),
.al_sh_command_val_in (al_sh_command_val_in),
.al_sh_dev_in (al_sh_dev_in),
.al_sh_dev_val_in (al_sh_dev_val_in),
.al_sh_control_in (al_sh_control_in),
.al_sh_control_val_in (al_sh_control_val_in),
.al_sh_dma_id_lo_in (al_sh_dma_id_lo_in),
.al_sh_dma_id_lo_val_in (al_sh_dma_id_lo_val_in),
.al_sh_dma_id_hi_in (al_sh_dma_id_hi_in),
.al_sh_dma_id_hi_val_in (al_sh_dma_id_hi_val_in),
.al_sh_buf_off_in (al_sh_buf_off_in),
.al_sh_buf_off_val_in (al_sh_buf_off_val_in),
.al_sh_tran_cnt_in (al_sh_tran_cnt_in),
.al_sh_tran_cnt_val_in (al_sh_tran_cnt_val_in),
.al_sh_autoact_in (al_sh_autoact_in),
.al_sh_autoact_val_in (al_sh_autoact_val_in),
.al_sh_inter_in (al_sh_inter_in),
.al_sh_inter_val_in (al_sh_inter_val_in),
.al_sh_dir_in (al_sh_dir_in),
.al_sh_dir_val_in (al_sh_dir_val_in),
.al_sh_dma_cnt_in (al_sh_dma_cnt_in),
.al_sh_dma_cnt_val_in (al_sh_dma_cnt_val_in),
.al_sh_notif_in (al_sh_notif_in),
.al_sh_notif_val_in (al_sh_notif_val_in),
.al_sh_port_in (al_sh_port_in),
.al_sh_port_val_in (al_sh_port_val_in),
// from tl
.tl_sh_lba_in (tl2cl_sh_lba),
.tl_sh_count_in (tl2cl_sh_count),
.tl_sh_command_in (tl2cl_sh_command),
.tl_sh_err_in (tl2cl_sh_err),
.tl_sh_status_in (tl2cl_sh_status),
.tl_sh_estatus_in (tl2cl_sh_estatus), // E_Status
.tl_sh_dev_in (tl2cl_sh_dev),
.tl_sh_port_in (tl2cl_sh_port),
.tl_sh_inter_in (tl2cl_sh_inter),
.tl_sh_dir_in (tl2cl_sh_dir),
.tl_sh_dma_id_in (tl2cl_sh_dma_id),
.tl_sh_dma_off_in (tl2cl_sh_dma_off),
.tl_sh_dma_cnt_in (tl2cl_sh_dma_cnt),
.tl_sh_tran_cnt_in (tl2cl_sh_tran_cnt), // Transfer Count
.tl_sh_notif_in (tl2cl_sh_notif),
.tl_sh_autoact_in (tl2cl_sh_autoact),
.tl_sh_lba_val_in (tl2cl_sh_lba_val),
.tl_sh_count_val_in (tl2cl_sh_count_val),
.tl_sh_command_val_in (tl2cl_sh_command_val),
.tl_sh_err_val_in (tl2cl_sh_err_val),
.tl_sh_status_val_in (tl2cl_sh_status_val),
.tl_sh_estatus_val_in (tl2cl_sh_estatus_val), // E_Status
.tl_sh_dev_val_in (tl2cl_sh_dev_val),
.tl_sh_port_val_in (tl2cl_sh_port_val),
.tl_sh_inter_val_in (tl2cl_sh_inter_val),
.tl_sh_dir_val_in (tl2cl_sh_dir_val),
.tl_sh_dma_id_val_in (tl2cl_sh_dma_id_val),
.tl_sh_dma_off_val_in (tl2cl_sh_dma_off_val),
.tl_sh_dma_cnt_val_in (tl2cl_sh_dma_cnt_val),
.tl_sh_tran_cnt_val_in (tl2cl_sh_tran_cnt_val), // Transfer Count
.tl_sh_notif_val_in (tl2cl_sh_notif_val),
.tl_sh_autoact_val_in (tl2cl_sh_autoact_val),
// all regs to output
.sh_data_val_out (sh_data_val),
.sh_data_out (sh_data),
.sh_control_out (sh_control),
.sh_feature_out (sh_feature),
.sh_lba_out (sh_lba),
.sh_count_out (sh_count),
.sh_command_out (sh_command),
.sh_err_out (sh_err),
.sh_status_out (sh_status),
.sh_estatus_out (sh_estatus), // E_Status
.sh_dev_out (sh_dev),
.sh_port_out (sh_port),
.sh_inter_out (sh_inter),
.sh_dir_out (sh_dir),
.sh_dma_id_out (sh_dma_id),
.sh_dma_off_out (sh_dma_off),
.sh_dma_cnt_out (sh_dma_cnt),
.sh_tran_cnt_out (sh_tran_cnt), // Transfer Count
.sh_notif_out (sh_notif),
.sh_autoact_out (sh_autoact)
);
// issue a frame
wire tl2ll_frame_req;
// frame started to be transmitted
wire tl2ll_frame_ack;
// frame issue was rejected because of incoming frame with higher priority
wire tl2ll_frame_rej;
// LL is not ready to receive a frame request. frame_req shall be low if busy is asserted
wire tl2ll_frame_busy;
// frame was transmitted w/o probles and successfully received @ a device side
wire tl2ll_frame_done_good;
// frame was transmitted, but device messages of problems with receiving
wire tl2ll_frame_done_bad;
// LL reports of an incoming frame transmission. They're always allowed and have the highest priority
wire ll2tl_incom_start;
// LL reports of a completion of an incoming frame transmission.
wire ll2tl_incom_done;
// LL reports of errors in current FIS
wire ll2tl_incom_invalidate; // TODO
// TL analyzes FIS and returnes if FIS makes sense.
wire ll2tl_incom_ack_good;
// ... and if it doesn't
wire ll2tl_incom_ack_bad;
// transmission interrupts
// TL demands to brutally cancel current transaction TODO
wire tl2ll_sync_escape_req;
// acknowlegement of a successful reception TODO
wire tl2ll_sync_escape_ack;
// TL demands to stop current recieving session TODO
wire tl2ll_incom_stop_req;
// shows if dma activate was received (a pulse)
wire got_dma_activate;
wire [3:0] got_dma_activate_port;
// if CL made a mistake in controlling data FIS length
wire data_limit_exceeded;
// LL data
// data inputs from LL
wire [DATA_BYTE_WIDTH*8 - 1:0] ll2tl_data;
wire [DATA_BYTE_WIDTH/2 - 1:0] ll2tl_data_mask;
wire ll2tl_data_val;
wire ll2tl_data_last;
// transport layer tells if its inner buffer is almost full
wire ll2tl_data_busy;
// data outputs to LL
wire [DATA_BYTE_WIDTH*8 - 1:0] tl2ll_data;
// not implemented yet TODO
wire [DATA_BYTE_WIDTH/2 - 1:0] tl2ll_data_mask;
wire tl2ll_data_last;
wire tl2ll_data_val;
wire tl2ll_data_strobe;
// watchdog timers calls. They shall be handled in TL, but for debug purposes are wired to the upper level
// when eof acknowledgement is not received after sent FIS
wire watchdog_eof;
// when too many dwords is in current FIS
wire watchdog_dwords;
transport transport(
.clk (clk),
.rst (rst),
// link layer (LL) control
// issue a frame
.frame_req (tl2ll_frame_req),
// frame started to be transmitted
.frame_ack (tl2ll_frame_ack),
// frame issue was rejected because of incoming frame with higher priority
.frame_rej (tl2ll_frame_rej),
// LL is not ready to receive a frame request. frame_req shall be low if busy is asserted
.frame_busy (tl2ll_frame_busy),
// frame was transmitted w/o probles and successfully received @ a device side
.frame_done_good (tl2ll_frame_done_good),
// frame was transmitted, but device messages of problems with receiving
.frame_done_bad (tl2ll_frame_done_bad),
// LL reports of an incoming frame transmission. They're always allowed and have the highest priority
.incom_start (ll2tl_incom_start),
// LL reports of a completion of an incoming frame transmission.
.incom_done (ll2tl_incom_done),
// LL reports of errors in current FIS
.incom_invalidate (ll2tl_incom_invalidate), // TODO
// TL analyzes FIS and returnes if FIS makes sense.
.incom_ack_good (ll2tl_incom_ack_good),
// ... and if it doesn't
.incom_ack_bad (ll2tl_incom_ack_bad),
// transmission interrupts
// TL demands to brutally cancel current transaction TODO
.sync_escape_req (tl2ll_sync_escape_req),
// acknowlegement of a successful reception TODO
.sync_escape_ack (tl2ll_sync_escape_ack),
// TL demands to stop current recieving session TODO
.incom_stop_req (tl2ll_incom_stop_req),
// controls from a command layer (CL)
// FIS type, ordered by CL
.cmd_type (cl2tl_cmd_type),
// request itself
.cmd_val (cl2tl_cmd_val),
// destination port
.cmd_port (cl2tl_cmd_port),
// if cmd got into processing, busy asserts, when TL is ready to receive a new cmd, busy deasserts
.cmd_busy (cl2tl_cmd_busy),
// indicates completion of a request
.cmd_done_good (cl2tl_cmd_done_good),
// request is completed, but device wasn't able to receive
.cmd_done_bad (cl2tl_cmd_done_bad),
// shadow registers TODO reduce outputs/inputs count. or not
// actual registers are stored in CL
.sh_data_in (sh_data),
.sh_feature_in (sh_feature),
.sh_lba_in (sh_lba),
.sh_count_in (sh_count),
.sh_command_in (sh_command),
.sh_dev_in (sh_dev),
.sh_control_in (sh_control),
.sh_autoact_in (sh_autoact),
.sh_inter_in (sh_inter),
.sh_dir_in (sh_dir),
.sh_dma_id_in (sh_dma_id),
.sh_buf_off_in (sh_dma_off),
.sh_dma_cnt_in (sh_dma_cnt),
.sh_notif_in (sh_notif),
.sh_tran_cnt_in (sh_tran_cnt),
.sh_port_in (sh_port),
// TL decodes register writes and sends corresponding issues to CL
.sh_lba_out (tl2cl_sh_lba),
.sh_count_out (tl2cl_sh_count),
.sh_command_out (tl2cl_sh_command),
.sh_err_out (tl2cl_sh_err),
.sh_status_out (tl2cl_sh_status),
.sh_estatus_out (tl2cl_sh_estatus), // E_Status
.sh_dev_out (tl2cl_sh_dev),
.sh_port_out (tl2cl_sh_port),
.sh_inter_out (tl2cl_sh_inter),
.sh_dir_out (tl2cl_sh_dir),
.sh_dma_id_out (tl2cl_sh_dma_id),
.sh_dma_off_out (tl2cl_sh_dma_off),
.sh_dma_cnt_out (tl2cl_sh_dma_cnt),
.sh_tran_cnt_out (tl2cl_sh_tran_cnt), // Transfer Count
.sh_notif_out (tl2cl_sh_notif),
.sh_autoact_out (tl2cl_sh_autoact),
.sh_lba_val_out (tl2cl_sh_lba_val),
.sh_count_val_out (tl2cl_sh_count_val),
.sh_command_val_out (tl2cl_sh_command_val),
.sh_err_val_out (tl2cl_sh_err_val),
.sh_status_val_out (tl2cl_sh_status_val),
.sh_estatus_val_out (tl2cl_sh_estatus_val), // E_Status
.sh_dev_val_out (tl2cl_sh_dev_val),
.sh_port_val_out (tl2cl_sh_port_val),
.sh_inter_val_out (tl2cl_sh_inter_val),
.sh_dir_val_out (tl2cl_sh_dir_val),
.sh_dma_id_val_out (tl2cl_sh_dma_id_val),
.sh_dma_off_val_out (tl2cl_sh_dma_off_val),
.sh_dma_cnt_val_out (tl2cl_sh_dma_cnt_val),
.sh_tran_cnt_val_out (tl2cl_sh_tran_cnt_val), // Transfer Count
.sh_notif_val_out (tl2cl_sh_notif_val),
.sh_autoact_val_out (tl2cl_sh_autoact_val),
// shows if dma activate was received (a pulse)
.got_dma_activate (got_dma_activate),
.got_dma_activate_port (got_dma_activate_port),
// if CL made a mistake in controlling data FIS length
.data_limit_exceeded (data_limit_exceeded),
// LL data
// data inputs from LL
.ll_data_in (ll2tl_data),
.ll_data_mask_in (ll2tl_data_mask),
.ll_data_val_in (ll2tl_data_val),
.ll_data_last_in (ll2tl_data_last),
// transport layer tells if its inner buffer is almost full
.ll_data_busy_out (ll2tl_data_busy),
// data outputs to LL
.ll_data_out (tl2ll_data),
// not implemented yet TODO
.ll_data_mask_out (tl2ll_data_mask),
.ll_data_last_out (tl2ll_data_last),
.ll_data_val_out (tl2ll_data_val),
.ll_data_strobe_in (tl2ll_data_strobe),
// CL data
// required content is bypassed from ll, other is trimmed
// only content of data FIS, starting from 1st dword. Max burst = 2048 dwords
// data outputs to CL
.cl_data_out (tl2cl_data),
.cl_data_mask_out (),
.cl_data_val_out (tl2cl_data_val),
.cl_data_last_out (tl2cl_data_last),
// transport layer tells if its inner buffer is almost full
.cl_data_busy_in (tl2cl_data_busy),
// data inputs from CL
.cl_data_in (cl2tl_data),
// not implemented yet TODO
.cl_data_mask_in (2'b11),//cl2tl_data_mask),
.cl_data_last_in (cl2tl_data_last),
.cl_data_val_in (cl2tl_data_val),
.cl_data_strobe_out (cl2tl_data_strobe),
// watchdog timers calls. They shall be handled in TL, but for debug purposes are wired to the upper level
// when eof acknowledgement is not received after sent FIS
.watchdog_eof (watchdog_eof),
// when too many dwords is in current FIS
.watchdog_dwords (watchdog_dwords)
);
// oob sequence is reinitiated and link now is not established or rxelecidle
wire link_reset;
// phy is ready - link is established
wire phy_ready;
// data-primitives stream from phy
wire [DATA_BYTE_WIDTH*8 - 1:0] phy2ll_data;
wire [DATA_BYTE_WIDTH - 1:0] phy2ll_isk; // charisk
wire [DATA_BYTE_WIDTH - 1:0] phy2ll_err; // disperr | notintable
// to phy
wire [DATA_BYTE_WIDTH*8 - 1:0] ll2phy_data;
wire [DATA_BYTE_WIDTH - 1:0] ll2phy_isk; // charisk
link link(
// TODO insert watchdogs
.rst (rst),
.clk (clk),
// data inputs from transport layer
// input data stream (if any data during OOB setting => ignored)
.data_in (tl2ll_data),
// in case of strange data aligments and size (1st mentioned @ doc, p.310, odd number of words case)
// Actually, only last data bundle shall be masked, others are always valid.
// Mask could be encoded into 3 bits instead of 4 for qword, but encoding+decoding aren't worth the bit
// TODO, for now not supported, all mask bits are assumed to be set
.data_mask_in (tl2ll_data_mask),
// buffer read strobe
.data_strobe_out (tl2ll_data_strobe),
// transaction's last data budle pulse
.data_last_in (tl2ll_data_last),
// read data is valid (if 0 while last pulse wasn't received => need to hold the line)
.data_val_in (tl2ll_data_val),
// data outputs to transport layer
// read data, same as related inputs
.data_out (ll2tl_data),
// same thing - all 1s for now. TODO
.data_mask_out (ll2tl_data_mask),
// count every data bundle read by transport layer, even if busy flag is set
// let the transport layer handle oveflows by himself
.data_val_out (ll2tl_data_val),
// transport layer tells if its inner buffer is almost full
.data_busy_in (ll2tl_data_busy),
.data_last_out (ll2tl_data_last),
// request for a new frame transition
.frame_req (tl2ll_frame_req),
// a little bit of overkill with the cound of response signals, think of throwing out 1 of them
// LL tells back if it cant handle the request for now
.frame_busy (tl2ll_frame_busy),
// LL tells if the request is transmitting
.frame_ack (tl2ll_frame_ack),
// or if it was cancelled because of simultanious incoming transmission
.frame_rej (tl2ll_frame_rej),
// TL tell if the outcoming transaction is done and how it was done
.frame_done_good (tl2ll_frame_done_good),
.frame_done_bad (tl2ll_frame_done_bad),
// if started an incoming transaction
.incom_start (ll2tl_incom_start),
// if incoming transition was completed
.incom_done (ll2tl_incom_done),
// if incoming transition had errors
.incom_invalidate (ll2tl_incom_invalidate),
// transport layer responds on a completion of a FIS
.incom_ack_good (ll2tl_incom_ack_good),
.incom_ack_bad (ll2tl_incom_ack_bad),
// oob sequence is reinitiated and link now is not established or rxelecidle
.link_reset (~phy_ready), //TODO mb it shall be independent
// TL demands to brutally cancel current transaction
.sync_escape_req (tl2ll_sync_escape_req),
// acknowlegement of a successful reception
.sync_escape_ack (tl2ll_sync_escape_ack),
// TL demands to stop current recieving session
.incom_stop_req (tl2ll_incom_stop_req),
// inputs from phy
// phy is ready - link is established
.phy_ready (phy_ready),
// data-primitives stream from phy
.phy_data_in (phy2ll_data),
.phy_isk_in (phy2ll_isk), // charisk
.phy_err_in (phy2ll_err), // disperr | notintable
// to phy
.phy_data_out (ll2phy_data),
.phy_isk_out (ll2phy_isk)// charis
);
sata_phy phy(
// pll reset
.extrst (extrst),
// sata clk
.rst (rst),
// sata clk, generated in pll as usrclk2
.clk (clk),
// state
.phy_ready (phy_ready),
// top-level ifaces
// ref clk from an external source, shall be connected to pads
.extclk_p (extclk_p),
.extclk_n (extclk_n),
// sata link data pins
.txp_out (txp_out),
.txn_out (txn_out),
.rxp_in (rxp_in),
.rxn_in (rxn_in),
// to link layer
.ll_data_out (phy2ll_data),
.ll_charisk_out (phy2ll_isk),
.ll_err_out (phy2ll_err),
// from link layer
.ll_data_in (ll2phy_data),
.ll_charisk_in (ll2phy_isk)
);
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/sata_phy.v 0000664 0000000 0000000 00000027644 12572445207 0023012 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: sata_phy
* Date: 2015-07-11
* Author: Alexey
* Description: phy-level, including oob, clock generation and GTXE2
*
* Copyright (c) 2015 Elphel, Inc.
* sata_phy.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sata_phy.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
`include "oob_ctrl.v"
`include "gtx_wrap.v"
module sata_phy #(
parameter DATA_BYTE_WIDTH = 4
)
(
// initial reset, resets PLL. After pll is locked, an internal sata reset is generated.
input wire extrst,
// sata clk, generated in pll as usrclk2
output wire clk,
output wire rst,
// state
output wire phy_ready,
// top-level ifaces
// ref clk from an external source, shall be connected to pads
input wire extclk_p,
input wire extclk_n,
// sata link data pins
output wire txp_out,
output wire txn_out,
input wire rxp_in,
input wire rxn_in,
// to link layer
output wire [DATA_BYTE_WIDTH * 8 - 1:0] ll_data_out,
output wire [DATA_BYTE_WIDTH - 1:0] ll_charisk_out,
output wire [DATA_BYTE_WIDTH - 1:0] ll_err_out, // TODO!!!
// from link layer
input wire [DATA_BYTE_WIDTH * 8 - 1:0] ll_data_in,
input wire [DATA_BYTE_WIDTH - 1:0] ll_charisk_in
);
wire [DATA_BYTE_WIDTH * 8 - 1:0] txdata;
wire [DATA_BYTE_WIDTH * 8 - 1:0] rxdata;
wire [DATA_BYTE_WIDTH * 8 - 1:0] rxdata_out;
wire [DATA_BYTE_WIDTH * 8 - 1:0] txdata_in;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk;
wire [DATA_BYTE_WIDTH - 1:0] rxcharisk;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_in;
wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_out;
// once gtx_ready -> 1, gtx_configured latches
// after this point it's possible to perform additional resets and reconfigurations by higher-level logic
reg gtx_configured;
// after external rst -> 0, after sata logic resets -> 1
wire sata_reset_done;
wire rxcomwakedet;
wire rxcominitdet;
wire cplllock;
wire txcominit;
wire txcomwake;
wire rxreset;
wire rxelecidle;
wire txelecidle;
wire rxbyteisaligned;
wire txpcsreset_req;
wire recal_tx_done;
wire rxreset_req;
wire rxreset_ack;
wire rxreset_oob;
// elastic buffer status signals TODO
wire rxelsfull;
wire rxelsempty;
wire gtx_ready;
oob_ctrl oob_ctrl(
// sata clk = usrclk2
.clk (clk),
// reset oob
.rst (rst),
// gtx is ready = all resets are done
.gtx_ready (gtx_ready),
// oob responces
.rxcominitdet_in (rxcominitdet),
.rxcomwakedet_in (rxcomwakedet),
.rxelecidle_in (rxelecidle),
// oob issues
.txcominit (txcominit),
.txcomwake (txcomwake),
.txelecidle (txelecidle),
.txpcsreset_req (txpcsreset_req),
.recal_tx_done (recal_tx_done),
.rxreset_req (rxreset_req),
.rxreset_ack (rxreset_ack),
// input data stream (if any data during OOB setting => ignored)
.txdata_in (txdata_in),
.txcharisk_in (txcharisk_in),
// output data stream to gtx
.txdata_out (txdata),
.txcharisk_out (txcharisk),
// input data from gtx
.rxdata_in (rxdata[31:0]),
.rxcharisk_in (rxcharisk[3:0]),
// bypassed data from gtx
.rxdata_out (rxdata_out),
.rxcharisk_out (rxcharisk_out),
// receiving data is aligned
.rxbyteisaligned (rxbyteisaligned),
// shows if channel is ready
.phy_ready (phy_ready)
);
wire cplllockdetclk; // TODO
wire drpclk; // TODO
wire cpllreset;
wire gtrefclk;
wire rxresetdone;
wire txresetdone;
wire txpcsreset;
wire txreset;
wire txuserrdy;
wire rxuserrdy;
wire txusrclk;
wire txusrclk2;
wire rxusrclk;
wire rxusrclk2;
wire txp;
wire txn;
wire rxp;
wire rxn;
wire txoutclk;
wire txpmareset_done;
wire rxeyereset_done;
// tx reset sequence; waves @ ug476 p67
localparam TXPMARESET_TIME = 5'h1;
reg [2:0] txpmareset_cnt;
assign txpmareset_done = txpmareset_cnt == TXPMARESET_TIME;
always @ (posedge gtrefclk)
txpmareset_cnt <= txreset ? 3'h0 : txpmareset_done ? txpmareset_cnt : txpmareset_cnt + 1'b1;
// rx reset sequence; waves @ ug476 p77
localparam RXPMARESET_TIME = 5'h11;
localparam RXCDRPHRESET_TIME = 5'h1;
localparam RXCDRFREQRESET_TIME = 5'h1;
localparam RXDFELPMRESET_TIME = 7'hf;
localparam RXISCANRESET_TIME = 5'h1;
localparam RXEYERESET_TIME = 7'h0 + RXPMARESET_TIME + RXCDRPHRESET_TIME + RXCDRFREQRESET_TIME + RXDFELPMRESET_TIME + RXISCANRESET_TIME;
reg [6:0] rxeyereset_cnt;
assign rxeyereset_done = rxeyereset_cnt == RXEYERESET_TIME;
always @ (posedge gtrefclk)
rxeyereset_cnt <= rxreset ? 3'h0 : rxeyereset_done ? rxeyereset_cnt : rxeyereset_cnt + 1'b1;
/*
* Resets
*/
wire usrpll_locked;
assign cpllreset = extrst;
assign rxreset = ~cplllock | cpllreset | rxreset_oob & gtx_configured;
assign txreset = ~cplllock | cpllreset;
assign rxuserrdy = usrpll_locked & cplllock & ~cpllreset & ~rxreset & rxeyereset_done & sata_reset_done;
assign txuserrdy = usrpll_locked & cplllock & ~cpllreset & ~txreset & txpmareset_done & sata_reset_done;
assign gtx_ready = rxuserrdy & txuserrdy & rxresetdone & txresetdone;
// assert gtx_configured. Once gtx_ready -> 1, gtx_configured latches
always @ (posedge clk or posedge extrst)
gtx_configured <= extrst ? 1'b0 : gtx_ready | gtx_configured;
// issue partial tx reset to restore functionality after oob sequence. Let it lasts 8 clock lycles
reg [3:0] txpcsreset_cnt;
wire txpcsreset_stop;
assign txpcsreset_stop = txpcsreset_cnt[3];
assign txpcsreset = txpcsreset_req & ~txpcsreset_stop & gtx_configured;
assign recal_tx_done = txpcsreset_stop & gtx_ready;
always @ (posedge clk or posedge extrst)
txpcsreset_cnt <= extrst | rst | ~txpcsreset_req ? 4'h0 : txpcsreset_stop ? txpcsreset_cnt : txpcsreset_cnt + 1'b1;
// issue rx reset to restore functionality after oob sequence. Let it lasts 8 clock lycles
reg [3:0] rxreset_oob_cnt;
wire rxreset_oob_stop;
assign rxreset_oob_stop = rxreset_oob_cnt[3];
assign rxreset_oob = rxreset_req & ~rxreset_oob_stop;
assign rxreset_ack = rxreset_oob_stop & gtx_ready;
always @ (posedge clk or posedge extrst)
rxreset_oob_cnt <= extrst | rst | ~rxreset_req ? 4'h0 : rxreset_oob_stop ? rxreset_oob_cnt : rxreset_oob_cnt + 1'b1;
// generate internal reset after a clock is established
// !!!ATTENTION!!!
// async rst block
reg [7:0] rst_timer;
reg rst_r;
localparam [7:0] RST_TIMER_LIMIT = 8'b1000;
always @ (posedge clk or posedge extrst)
rst_timer <= extrst | ~cplllock | ~usrpll_locked ? 8'h0 : sata_reset_done ? rst_timer : rst_timer + 1'b1;
assign rst = rst_r;
always @ (posedge clk or posedge extrst)
rst_r <= extrst | ~|rst_timer ? 1'b0 : sata_reset_done ? 1'b0 : 1'b1;
assign sata_reset_done = rst_timer == RST_TIMER_LIMIT;
/*
* USRCLKs generation. USRCLK @ 150MHz, same as TXOUTCLK; USRCLK2 @ 75Mhz -> sata_clk === sclk
* It's recommended to use MMCM instead of PLL, whatever
*/
wire usrpll_fb_clk;
wire usrclk;
wire usrclk2;
assign txusrclk = usrclk;
assign txusrclk2 = usrclk2;
assign rxusrclk = usrclk;
assign rxusrclk2 = usrclk2;
PLLE2_ADV #(
.BANDWIDTH ("OPTIMIZED"),
.CLKFBOUT_MULT (8),
.CLKFBOUT_PHASE (0.000),
.CLKIN1_PERIOD (6.666),
.CLKIN2_PERIOD (0.000),
.CLKOUT0_DIVIDE (8),
.CLKOUT0_DUTY_CYCLE (0.500),
.CLKOUT0_PHASE (0.000),
.CLKOUT1_DIVIDE (16),
.CLKOUT1_DUTY_CYCLE (0.500),
.CLKOUT1_PHASE (0.000),
/* .CLKOUT2_DIVIDE = 1,
.CLKOUT2_DUTY_CYCLE = 0.500,
.CLKOUT2_PHASE = 0.000,
.CLKOUT3_DIVIDE = 1,
.CLKOUT3_DUTY_CYCLE = 0.500,
.CLKOUT3_PHASE = 0.000,
.CLKOUT4_DIVIDE = 1,
.CLKOUT4_DUTY_CYCLE = 0.500,
.CLKOUT4_PHASE = 0.000,
.CLKOUT5_DIVIDE = 1,
.CLKOUT5_DUTY_CYCLE = 0.500,
.CLKOUT5_PHASE = 0.000,*/
.COMPENSATION ("ZHOLD"),
.DIVCLK_DIVIDE (1),
.IS_CLKINSEL_INVERTED (1'b0),
.IS_PWRDWN_INVERTED (1'b0),
.IS_RST_INVERTED (1'b0),
.REF_JITTER1 (0.010),
.REF_JITTER2 (0.010),
.STARTUP_WAIT ("FALSE")
)
usrclk_pll(
.CLKFBOUT (usrpll_fb_clk),
.CLKOUT0 (usrclk),
.CLKOUT1 (usrclk2),
.CLKOUT2 (),
.CLKOUT3 (),
.CLKOUT4 (),
.CLKOUT5 (),
.DO (),
.DRDY (),
.LOCKED (usrpll_locked),
.CLKFBIN (usrpll_fb_clk),
.CLKIN1 (txoutclk),
.CLKIN2 (1'b0),
.CLKINSEL (1'b1),
.DADDR (7'h0),
.DCLK (drpclk),
.DEN (1'b0),
.DI (16'h0),
.DWE (1'b0),
.PWRDWN (1'b0),
.RST (~cplllock)
);
/*
* Padding for an external input clock @ 150 MHz
*/
localparam [1:0] CLKSWING_CFG = 2'b11;
IBUFDS_GTE2 #(
.CLKRCV_TRST ("TRUE"),
.CLKCM_CFG ("TRUE"),
.CLKSWING_CFG (CLKSWING_CFG)
)
ext_clock_buf(
.I (extclk_p),
.IB (extclk_n),
.CEB (1'b0),
.O (gtrefclk),
.ODIV2 ()
);
gtx_wrap #(
.DATA_BYTE_WIDTH (DATA_BYTE_WIDTH),
.TXPMARESET_TIME (TXPMARESET_TIME),
.RXPMARESET_TIME (RXPMARESET_TIME),
.RXCDRPHRESET_TIME (RXCDRPHRESET_TIME),
.RXCDRFREQRESET_TIME (RXCDRFREQRESET_TIME),
.RXDFELPMRESET_TIME (RXDFELPMRESET_TIME),
.RXISCANRESET_TIME (RXISCANRESET_TIME),
.RXEYERESET_TIME (RXEYERESET_TIME)
)
gtx_wrap
(
.cplllock (cplllock),
.cplllockdetclk (cplllockdetclk),
.cpllreset (cpllreset),
.gtrefclk (gtrefclk),
.drpclk (drpclk),
.rxuserrdy (rxuserrdy),
.txuserrdy (txuserrdy),
.rxusrclk (rxusrclk),
.rxusrclk2 (rxusrclk2),
.rxp (rxp),
.rxn (rxn),
.rxbyteisaligned (rxbyteisaligned),
.rxreset (rxreset),
.rxcomwakedet (rxcomwakedet),
.rxcominitdet (rxcominitdet),
.rxelecidle (rxelecidle),
.rxresetdone (rxresetdone),
.txreset (txreset),
.txusrclk (txusrclk),
.txusrclk2 (txusrclk2),
.txelecidle (txelecidle),
.txp (txp),
.txn (txn),
.txoutclk (txoutclk),
.txpcsreset (txpcsreset),
.txresetdone (txresetdone),
.txcominit (txcominit),
.txcomwake (txcomwake),
.rxelsfull (rxelsfull),
.rxelsempty (rxelsempty),
.txdata (txdata),
.txcharisk (txcharisk),
.rxdata (rxdata),
.rxcharisk (rxcharisk)
);
/*
* Interfaces
*/
assign cplllockdetclk = gtrefclk; //TODO
assign drpclk = gtrefclk;
assign clk = usrclk2;
assign rxn = rxn_in;
assign rxp = rxp_in;
assign txn_out = txn;
assign txp_out = txp;
assign ll_data_out = rxdata_out;
assign ll_charisk_out = rxcharisk_out;
assign txdata_in = ll_data_in;
assign txcharisk_in = ll_charisk_in;
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/scrambler.v 0000664 0000000 0000000 00000010705 12572445207 0023142 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: scrambler
* Date: 2015-07-11
* Author: Alexey
* Description: a scrambler for the link layer
*
* Copyright (c) 2015 Elphel, Inc.
* scrambler.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* scrambler.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
/*
* Algorithm is taken from the doc, p.565. TODO make it parallel
*/
// TODO another widths support
module scrambler #(
parameter DATA_BYTE_WIDTH = 4
)
(
input wire clk,
input wire rst,
input wire val_in,
input wire [DATA_BYTE_WIDTH*8 - 1:0] data_in,
output wire [DATA_BYTE_WIDTH*8 - 1:0] data_out
);
reg [15:0] now;
reg [31:0] next;
always @ (posedge clk)
now <= rst ? 16'hf0f6 : val_in ? next[31:16] : now;
assign data_out = val_in ? data_in ^ next : data_in;
always @ (*)
/* if (rst)
next = 32'h0;
else*/
begin
next[31] = now[12] ^ now[10] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
next[30] = now[15] ^ now[14] ^ now[12] ^ now[11] ^ now[9] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
next[29] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[28] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[27] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[1] ^ now[0];
next[26] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[0];
next[25] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[3] ^ now[2];
next[24] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[23] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[22] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
next[21] = now[15] ^ now[13] ^ now[12] ^ now[6] ^ now[5] ^ now[4] ^ now[0];
next[20] = now[15] ^ now[11] ^ now[5] ^ now[4];
next[19] = now[14] ^ now[10] ^ now[4] ^ now[3];
next[18] = now[13] ^ now[9] ^ now[3] ^ now[2];
next[17] = now[12] ^ now[8] ^ now[2] ^ now[1];
next[16] = now[11] ^ now[7] ^ now[1] ^ now[0];
next[15] = now[15] ^ now[14] ^ now[12] ^ now[10] ^ now[6] ^ now[3] ^ now[0];
next[14] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[9] ^ now[5] ^ now[3] ^ now[2];
next[13] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[4] ^ now[2] ^ now[1];
next[12] = now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
next[11] = now[15] ^ now[14] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
next[10] = now[15] ^ now[13] ^ now[12] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[9] = now[14] ^ now[12] ^ now[11] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[8] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[7] ^ now[6] ^ now[5] ^ now[1] ^ now[0];
next[7] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[6] ^ now[5] ^ now[4] ^ now[3] ^ now[0];
next[6] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[5] ^ now[4] ^ now[2];
next[5] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[4] ^ now[3] ^ now[1];
next[4] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
next[3] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[2] = now[14] ^ now[13] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[1] = now[15] ^ now[14] ^ now[13] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
next[0] = now[15] ^ now[13] ^ now[4] ^ now[0];
end
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/host/transport.v 0000664 0000000 0000000 00000147270 12572445207 0023234 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* Module: transport
* Date: 2015-07-11
* Author: Alexey
* Description: sata transport layer implementation
*
* Copyright (c) 2015 Elphel, Inc.
* transport.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* transport.v file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*******************************************************************************/
module transport #(
parameter DATA_BYTE_WIDTH = 4
)
(
input wire clk,
input wire rst,
// link layer (LL) control
// issue a frame
output wire frame_req,
// frame started to be transmitted
input wire frame_ack,
// frame issue was rejected because of incoming frame with higher priority
input wire frame_rej,
// LL is not ready to receive a frame request. frame_req shall be low if busy is asserted
input wire frame_busy,
// frame was transmitted w/o probles and successfully received @ a device side
input wire frame_done_good,
// frame was transmitted, but device messages of problems with receiving
input wire frame_done_bad,
// LL reports of an incoming frame transmission. They're always allowed and have the highest priority
input wire incom_start,
// LL reports of a completion of an incoming frame transmission.
input wire incom_done,
// LL reports of errors in current FIS
input wire incom_invalidate, // TODO
// TL analyzes FIS and returnes if FIS makes sense.
output wire incom_ack_good,
// ... and if it doesn't
output wire incom_ack_bad,
// transmission interrupts
// TL demands to brutally cancel current transaction TODO
output wire sync_escape_req,
// acknowlegement of a successful reception TODO
input wire sync_escape_ack,
// TL demands to stop current recieving session TODO
output wire incom_stop_req,
// controls from a command layer (CL)
// FIS type, ordered by CL
input wire [2:0] cmd_type,
// request itself
input wire cmd_val,
// destination port
input wire [3:0] cmd_port,
// if cmd got into processing, busy asserts, when TL is ready to receive a new cmd, busy deasserts
output wire cmd_busy,
// indicates completion of a request
output wire cmd_done_good,
// request is completed, but device wasn't able to receive
output wire cmd_done_bad,
// shadow registers TODO reduce outputs/inputs count. or not
// actual registers are stored in CL
input wire [31:0] sh_data_in,
input wire [15:0] sh_feature_in,
input wire [47:0] sh_lba_in,
input wire [15:0] sh_count_in,
input wire [7:0] sh_command_in,
input wire [7:0] sh_dev_in,
input wire [7:0] sh_control_in,
input wire sh_autoact_in,
input wire sh_inter_in,
input wire sh_dir_in,
input wire [63:0] sh_dma_id_in,
input wire [31:0] sh_buf_off_in,
input wire [31:0] sh_dma_cnt_in,
input wire sh_notif_in,
input wire [15:0] sh_tran_cnt_in,
input wire [3:0] sh_port_in,
// TL decodes register writes and sends corresponding issues to CL
output wire [47:0] sh_lba_out,
output wire [15:0] sh_count_out,
output wire [7:0] sh_command_out,
output wire [7:0] sh_err_out,
output wire [7:0] sh_status_out,
output wire [7:0] sh_estatus_out, // E_Status
output wire [7:0] sh_dev_out,
output wire [3:0] sh_port_out,
output wire sh_inter_out,
output wire sh_dir_out,
output wire [63:0] sh_dma_id_out,
output wire [31:0] sh_dma_off_out,
output wire [31:0] sh_dma_cnt_out,
output wire [15:0] sh_tran_cnt_out, // Transfer Count
output wire sh_notif_out,
output wire sh_autoact_out,
output wire sh_lba_val_out,
output wire sh_count_val_out,
output wire sh_command_val_out,
output wire sh_err_val_out,
output wire sh_status_val_out,
output wire sh_estatus_val_out, // E_Status
output wire sh_dev_val_out,
output wire sh_port_val_out,
output wire sh_inter_val_out,
output wire sh_dir_val_out,
output wire sh_dma_id_val_out,
output wire sh_dma_off_val_out,
output wire sh_dma_cnt_val_out,
output wire sh_tran_cnt_val_out, // Transfer Count
output wire sh_notif_val_out,
output wire sh_autoact_val_out,
// shows if dma activate was received (a pulse)
output wire got_dma_activate,
output wire [3:0] got_dma_activate_port,
// if CL made a mistake in controlling data FIS length
output wire data_limit_exceeded,
// LL data
// data inputs from LL
input wire [DATA_BYTE_WIDTH*8 - 1:0] ll_data_in,
input wire [DATA_BYTE_WIDTH/2 - 1:0] ll_data_mask_in,
input wire ll_data_val_in,
input wire ll_data_last_in,
// transport layer tells if its inner buffer is almost full
output wire ll_data_busy_out,
// data outputs to LL
output wire [DATA_BYTE_WIDTH*8 - 1:0] ll_data_out,
// not implemented yet TODO
output wire [DATA_BYTE_WIDTH/2 - 1:0] ll_data_mask_out,
output wire ll_data_last_out,
output wire ll_data_val_out,
input wire ll_data_strobe_in,
// CL data
// required content is bypassed from ll, other is trimmed
// only content of data FIS, starting from 1st dword. Max burst = 2048 dwords
// data outputs to CL
output wire [DATA_BYTE_WIDTH*8 - 1:0] cl_data_out,
output wire [DATA_BYTE_WIDTH/2 - 1:0] cl_data_mask_out,
output wire cl_data_val_out,
output wire cl_data_last_out,
// transport layer tells if its inner buffer is almost full
input wire cl_data_busy_in,
// data inputs from CL
input wire [DATA_BYTE_WIDTH*8 - 1:0] cl_data_in,
// not implemented yet TODO
input wire [DATA_BYTE_WIDTH/2 - 1:0] cl_data_mask_in,
input wire cl_data_last_in,
input wire cl_data_val_in,
output wire cl_data_strobe_out,
// watchdog timers calls. They shall be handled in TL, but for debug purposes are wired to the upper level
// when eof acknowledgement is not received after sent FIS
output wire watchdog_eof,
// when too many dwords is in current FIS
output wire watchdog_dwords
);
//TODO
assign sync_escape_req = 1'b0;
assign incom_stop_req = 1'b0;
assign cl_data_strobe_out = 1'b0;
// How much time does device have to response on EOF
parameter [13:0] WATCHDOG_EOF_LIMIT = 14'd1000;
// must have a local reserve copy of shadow registers in case of
// a) received FIS with incorrect length (seems like an error, so no registers shall be written)
// b) incoming transmission overrides outcoming, so we have to latch outcoming values in real shadow registers
// while storing incoming ones in the local copy
reg [47:0] loc_lba;
reg [15:0] loc_count;
reg [7:0] loc_command;
reg [7:0] loc_err;
reg [7:0] loc_status;
reg [7:0] loc_estatus; // E_Status
reg [7:0] loc_dev;
reg [3:0] loc_port;
reg loc_inter;
reg loc_dir;
reg [63:0] loc_dma_id;
reg [31:0] loc_dma_off;
reg [31:0] loc_dma_cnt;
reg [15:0] loc_tran_cnt; // Transfer Count
reg loc_notif;
reg loc_autoact;
// latching cmd inputs
reg [3:0] cmd_port_r;
reg [2:0] cmd_type_r;
always @ (posedge clk)
cmd_type_r <= rst ? 3'h0 : cmd_val ? cmd_type : cmd_type_r;
always @ (posedge clk)
cmd_port_r <= rst ? 4'h0 : cmd_val ? cmd_port : cmd_port_r;
// incomming command type decode, shows which type of FIS shall be issued
localparam [2:0] CMD_TYPE_REG_DEV = 3'h0; // Reg H2D, bit C -> 0
localparam [2:0] CMD_TYPE_REG_CMD = 3'h1; // Reg H2D, bit C -> 1
localparam [2:0] CMD_TYPE_DMA_SETUP = 3'h2;
localparam [2:0] CMD_TYPE_DATA = 3'h3;
localparam [2:0] CMD_TYPE_BIST_ACT = 3'h4;
// asserts after FIS is sent
reg cmd_done_f;
// current header dword
wire [31:0] ll_header_dword;
// current dword shall be header's
wire ll_header_val;
// if last data dword is header's
wire ll_header_last;
// incorrect size or unmatched type of a received FIS
reg bad_fis_received;
// if a FIS has wrong size, make sure it would stop, universal dword counter
reg [13:0] dword_cnt;
// FIS dword size exceeded condition
assign watchdog_dwords = dword_cnt == 14'd2049;
// ask for a receiving termination in case of errors
reg incom_stop_req_timeout;
// dma activate is received when its type met and no errors occurs
assign got_dma_activate = state == STATE_INCOMING & cl_data_last_in & ll_data_val_in & ll_data_in[7:0] == 8'h39;
assign got_dma_activate_port = {4{got_dma_activate}} & ll_data_in[11:8];
// global TL fsm
/*
idle -----> outcoming FIS ----> outcoming ----non-data--> fill dwords -------------------------+
| |if rej | |
| | +-----data--> make header --> bypass data from CL -+
| V |
+-------> incoming FIS -------detect type---non-data--> parse dwords, write sh regs ---------+
| |
+-------------data--> get header ---> bypass data to CL -----> done
*/
localparam STATE_IDLE = 8'h0;
localparam STATE_INCOMING = 8'h1;
localparam STATE_OUTCOMING = 8'h2;
localparam STATE_IN_DATA = 8'h10; // Data FIS from device
localparam STATE_IN_REG_1 = 8'h20; // Register FIS Device to Host: 1st dword
localparam STATE_IN_REG_2 = 8'h21; // Register FIS Device to Host: 2nd dword
localparam STATE_IN_REG_3 = 8'h22; // Register FIS Device to Host: 3rd dword
localparam STATE_IN_REG_4 = 8'h23; // Register FIS Device to Host: 4th dword
localparam STATE_IN_REG_ERR = 8'h24; // Register FIS Device to Host: Error happened
localparam STATE_IN_DMAA_ERR = 8'h30; // DMA Activate: Error Happened
localparam STATE_IN_DMAS_1 = 8'h40; // DMA Setup FIS device to host: 1st dword
localparam STATE_IN_DMAS_2 = 8'h41; // DMA Setup FIS device to host: 2nd dword
localparam STATE_IN_DMAS_3 = 8'h42; // DMA Setup FIS device to host: 3rd dword
localparam STATE_IN_DMAS_4 = 8'h43; // DMA Setup FIS device to host: 4th dword
localparam STATE_IN_DMAS_5 = 8'h44; // DMA Setup FIS device to host: 5th dword
localparam STATE_IN_DMAS_6 = 8'h45; // DMA Setup FIS device to host: 6th dword
localparam STATE_IN_DMAS_ERR = 8'h46; // DMA Setup FIS device to host: Error happened
localparam STATE_IN_BIST_1 = 8'h50; // BIST Activate FIS Device to Host: 1st dword
localparam STATE_IN_BIST_2 = 8'h51; // BIST Activate FIS Device to Host: 2nd dword
localparam STATE_IN_BIST_ERR = 8'h52; // BIST Activate FIS Device to Host: Error happened
localparam STATE_IN_PIOS_1 = 8'h60; // PIO Setup FIS: 1st dword
localparam STATE_IN_PIOS_2 = 8'h61; // PIO Setup FIS: 2nd dword
localparam STATE_IN_PIOS_3 = 8'h62; // PIO Setup FIS: 3rd dword
localparam STATE_IN_PIOS_4 = 8'h63; // PIO Setup FIS: 4th dword
localparam STATE_IN_PIOS_ERR = 8'h64; // PIO Setup FIS: Error happened
localparam STATE_IN_SDB_1 = 8'h70; // Set Device Bits FIS: 1st dword
localparam STATE_IN_SDB_ERR = 8'h70; // Set Device Bits FIS: Error happened
localparam STATE_OUT_DATA_H = 8'h80; // Data FIS from host: header
localparam STATE_OUT_DATA_D = 8'h81; // Data FIS from host: payload
localparam STATE_OUT_REG = 8'h90; // Register FIS Host to Device
localparam STATE_OUT_DMAS = 8'ha0; // DMA Setup FIS Host to Device
localparam STATE_OUT_BIST = 8'hb0; // BIST Activate FIS Host to Device
localparam STATE_OUT_WAIT_RESP = 8'hc0; //
localparam STATE_IN_UNRECOG = 8'hf0; // Unrecognized FIS from Device
reg [7:0] state;
always @ (posedge clk)
if (rst)
begin
state <= STATE_IDLE;
dword_cnt <= 14'h0;
incom_stop_req_timeout <= 1'b0;
bad_fis_received <= 1'b0;
loc_lba <= 48'h0;
loc_count <= 32'h0;
loc_command <= 8'h0;
loc_err <= 8'h0;
loc_status <= 8'h0;
loc_estatus <= 8'h0;
loc_dev <= 8'h0;
loc_port <= 4'h0;
loc_inter <= 1'h0;
loc_dir <= 1'h0;
loc_dma_id <= 64'h0;
loc_dma_off <= 32'h0;
loc_dma_cnt <= 32'h0;
loc_tran_cnt <= 16'h0;
loc_notif <= 1'h0;
loc_autoact <= 1'h0;
end
else
case (state)
STATE_IDLE:
begin
dword_cnt <= 14'h0;
incom_stop_req_timeout <= 1'b0;
bad_fis_received <= 1'b0;
if (frame_req)
state <= STATE_OUTCOMING;
else
if (incom_start | frame_req)
state <= STATE_INCOMING;
else
state <= STATE_IDLE;
loc_lba <= sh_lba_in;
loc_count <= sh_count_in;
loc_command <= sh_command_in;
loc_err <= 8'h0;
loc_status <= 8'h0;
loc_estatus <= 8'h0;
loc_dev <= 8'h0;
loc_port <= sh_port_in;
loc_inter <= sh_inter_in;
loc_dir <= sh_dir_in;
loc_dma_id <= sh_dma_id_in;
loc_dma_off <= sh_buf_off_in;
loc_dma_cnt <= sh_dma_cnt_in;
loc_tran_cnt <= sh_tran_cnt_in;
loc_notif <= sh_notif_in;
loc_autoact <= sh_autoact_in;
end
STATE_INCOMING:
// enter state when we're starting to get a FIS, leave after 1st dword is received
begin
if (ll_data_val_in)
// if 0-th dword came
case (ll_data_in[7:0])
// act depending on packet type
8'h34:
// register
begin
if (~ll_data_last_in)
begin
loc_port <= ll_data_in[11:8];
loc_inter <= ll_data_in[14];
loc_status <= ll_data_in[23:16];
loc_err <= ll_data_in[31:24];
state <= STATE_IN_REG_1;
end
else
// an error state, too little dwords transfered
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
end
8'h39:
// DMA Activate
begin
if (~ll_data_last_in)
begin
state <= STATE_IN_DMAA_ERR;
dword_cnt <= 14'h1;
end
else
begin
// got_dma_activate - wire assigment
state <= STATE_IDLE;
end
end
8'h41:
// DMA Setup
begin
if (~ll_data_last_in)
begin
loc_port <= ll_data_in[11:8];
loc_dir <= ll_data_in[13];
loc_inter <= ll_data_in[14];
loc_autoact <= ll_data_in[15];
state <= STATE_IN_DMAS_1;
end
else
// an error state, too little dwords transfered
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
end
8'h46:
// Data FIS
begin
if (~ll_data_last_in)
begin
loc_port <= ll_data_in[11:8];
dword_cnt <= 14'h1;
state <= STATE_IN_DATA;
end
else
// an error state, too little dwords transfered
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
end
8'h58:
// BIST
begin
// for now skips payload, just controls length TODO
state <= STATE_IN_BIST_1;
end
8'h5f:
// PIO setup
begin
if (~ll_data_last_in)
begin
loc_port <= ll_data_in[11:8];
loc_dir <= ll_data_in[13];
loc_inter <= ll_data_in[14];
loc_status <= ll_data_in[23:16];
loc_err <= ll_data_in[31:24];
state <= STATE_IN_PIOS_1;
end
else
// an error state, too little dwords transfered
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
end
8'ha1:
// Set Device Bits
begin
if (~ll_data_last_in)
begin
loc_inter <= ll_data_in[14];
loc_notif <= ll_data_in[15];
loc_status[2:0] <= ll_data_in[19:17];
loc_status[6:4] <= ll_data_in[23:21];
loc_err <= ll_data_in[31:24];
state <= STATE_IN_SDB_1;
end
else
// an error state, too little dwords transfered
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
end
default:
// no known FIS type matched
begin
dword_cnt <= 14'h0;
state <= STATE_IN_UNRECOG;
end
endcase
end
STATE_OUTCOMING:
// enter state when we're issuing a FIS, leave when got an ack from ll (FIS started to transmit)
// or if FIS won't start because of incoming transmission. In such case outcoming request parameter shall be latched TODO or not?
begin
dword_cnt <= 14'h0;
state <= frame_rej ? STATE_INCOMING :
frame_ack & cmd_type_r == CMD_TYPE_REG_DEV ? STATE_OUT_REG :
frame_ack & cmd_type_r == CMD_TYPE_REG_CMD ? STATE_OUT_REG :
frame_ack & cmd_type_r == CMD_TYPE_DMA_SETUP ? STATE_OUT_DMAS :
frame_ack & cmd_type_r == CMD_TYPE_DATA ? STATE_OUT_DATA_H :
frame_ack & cmd_type_r == CMD_TYPE_BIST_ACT ? STATE_OUT_BIST :
STATE_OUTCOMING;
end
STATE_IN_DATA:
// receiving data from Data FIS, bypass it into buffer at upper level
begin
if (incom_done)
// EOF received, CRC good
begin
state <= STATE_IDLE;
end
else
if (ll_data_val_in)
begin
if (dword_cnt == 14'd2049)
// if too much data for a data FIS TODO handle this excpetion properly
state <= STATE_IDLE;
else
// continuing receiving data
begin
dword_cnt <= dword_cnt + 1'b1;
state <= STATE_IN_DATA;
end
end
end
STATE_IN_REG_1:
// receiving register FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: {Device, LBA High, LBA Mid, LBA Low}
begin
loc_lba[7:0] <= ll_data_in[7:0];
loc_lba[23:16] <= ll_data_in[15:8];
loc_lba[39:32] <= ll_data_in[23:16];
loc_dev[7:0] <= ll_data_in[31:24];
state <= STATE_IN_REG_2;
end
end
STATE_IN_REG_2:
// receiving register FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: {Reserved, LBA High (exp), LBA Mid (exp), LBA Low (exp)}
begin
loc_lba[15:8] <= ll_data_in[7:0];
loc_lba[31:24] <= ll_data_in[15:8];
loc_lba[47:40] <= ll_data_in[23:16];
state <= STATE_IN_REG_3;
end
end
STATE_IN_REG_3:
// receiving register FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: {Reserved, Reserved, Sector Count (exp), Sector Count}
begin
loc_count[15:0] <= ll_data_in[15:0];
state <= STATE_IN_REG_4;
end
end
STATE_IN_REG_4:
// receiving register FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// correct frame size, finishing
begin
state <= STATE_IDLE;
end
else
// incorrect frame size
begin
state <= STATE_IN_REG_ERR;
dword_cnt <= 14'h4;
end
end
STATE_IN_REG_ERR:
// FIS was started as REG, but for some reason it has a size more than needed
// just wait until it's over and assert an error
begin
if (ll_data_val_in)
if (ll_data_last_in)
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
begin
if (watchdog_dwords)
// if for some reason FIS continue transferring for too long, terminate it
begin
state <= STATE_IDLE;
incom_stop_req_timeout <= 1'b1;
end
else
dword_cnt <= dword_cnt + 1'b1;
end
end
STATE_IN_DMAA_ERR:
// FIS was started as DMA Activate, but for some reason it has a size more than needed
// just wait until it's over and assert an error
begin
if (ll_data_val_in)
if (ll_data_last_in)
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
begin
if (watchdog_dwords)
// if for some reason FIS continue transferring for too long, terminate it
begin
state <= STATE_IDLE;
incom_stop_req_timeout <= 1'b1;
end
else
dword_cnt <= dword_cnt + 1'b1;
end
end
STATE_IN_DMAS_1:
// receiving DMA Setup FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: DMA Buffer Id Low
begin
loc_dma_id[31:0] <= ll_data_in[31:0];
state <= STATE_IN_DMAS_2;
end
end
STATE_IN_DMAS_2:
// receiving DMA Setup FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: DMA Buffer Id High
begin
loc_dma_id[63:32] <= ll_data_in[31:0];
state <= STATE_IN_DMAS_3;
end
end
STATE_IN_DMAS_3:
// receiving DMA Setup FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: Reserved
begin
state <= STATE_IN_DMAS_4;
end
end
STATE_IN_DMAS_4:
// receiving DMA Setup FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: DMA Buffer Offset
begin
loc_dma_off[31:0] <= ll_data_in[31:0];
state <= STATE_IN_DMAS_5;
end
end
STATE_IN_DMAS_5:
// receiving DMA Setup FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: DMA Transfer Count
begin
loc_dma_cnt[31:0] <= ll_data_in[31:0];
state <= STATE_IN_DMAS_6;
end
end
STATE_IN_DMAS_6:
// receiving DMA Setup FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// correct frame size, finishing, current dword: Reserved
begin
state <= STATE_IDLE;
end
else
// incorrect frame size
begin
state <= STATE_IN_DMAS_ERR;
dword_cnt <= 14'h6;
end
end
STATE_IN_DMAS_ERR:
// FIS was started as DMA Setup, but for some reason it has a size more than needed
// just wait until it's over and assert an error
begin
if (ll_data_val_in)
if (ll_data_last_in)
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
begin
if (watchdog_dwords)
// if for some reason FIS continue transferring for too long, terminate it
begin
state <= STATE_IDLE;
incom_stop_req_timeout <= 1'b1;
end
else
dword_cnt <= dword_cnt + 1'b1;
end
end
STATE_IN_BIST_1:
// receiving BIST FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: TODO
begin
state <= STATE_IN_BIST_2;
end
end
STATE_IN_BIST_2:
// receiving BIST FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// correct frame size, finishing, current dword: Reserved
begin
state <= STATE_IDLE;
end
else
// incorrect frame size
begin
state <= STATE_IN_BIST_ERR;
dword_cnt <= 14'h2;
end
end
STATE_IN_BIST_ERR:
// FIS was started as BIST Activate, but for some reason it has a size more than needed
// just wait until it's over and assert an error
begin
if (ll_data_val_in)
if (ll_data_last_in)
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
begin
if (watchdog_dwords)
// if for some reason FIS continue transferring for too long, terminate it
begin
state <= STATE_IDLE;
incom_stop_req_timeout <= 1'b1;
end
else
dword_cnt <= dword_cnt + 1'b1;
end
end
STATE_IN_PIOS_1:
// receiving PIO Setup FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: {Device, LBA High, LBA Mid, LBA Low}
begin
loc_lba[7:0] <= ll_data_in[7:0];
loc_lba[23:16] <= ll_data_in[15:8];
loc_lba[39:32] <= ll_data_in[23:16];
loc_dev <= ll_data_in[31:24];
state <= STATE_IN_PIOS_2;
end
end
STATE_IN_PIOS_2:
// receiving PIO Setup FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: {Reserved, LBA High (exp), LBA Mid (exp), LBA Low (exp)}
begin
loc_lba[15:8] <= ll_data_in[7:0];
loc_lba[31:24] <= ll_data_in[15:8];
loc_lba[47:40] <= ll_data_in[23:16];
state <= STATE_IN_PIOS_3;
end
end
STATE_IN_PIOS_3:
// receiving PIOS FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// incorrect frame size
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
// going to the next dword, parse current one: {E_Status, Reserved, Sector Count (exp), Sector Count}
begin
loc_count[15:0] <= ll_data_in[15:0];
loc_estatus <= ll_data_in[31:24];
state <= STATE_IN_PIOS_4;
end
end
STATE_IN_PIOS_4:
// receiving PIO Setup FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// correct frame size, finishing, current dword: {Reserved, Transfer Count}
begin
loc_tran_cnt <= ll_data_in[15:0];
state <= STATE_IDLE;
end
else
// incorrect frame size
begin
state <= STATE_IN_BIST_ERR;
dword_cnt <= 14'h4;
end
end
STATE_IN_PIOS_ERR:
// FIS was started as PIO Setup Activate, but for some reason it has a size more than needed
// just wait until it's over and assert an error
begin
if (ll_data_val_in)
if (ll_data_last_in)
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
begin
if (watchdog_dwords)
// if for some reason FIS continue transferring for too long, terminate it
begin
state <= STATE_IDLE;
incom_stop_req_timeout <= 1'b1;
end
else
dword_cnt <= dword_cnt + 1'b1;
end
end
STATE_IN_SDB_1:
// receiving Set Device Bits FIS, dword by dword
begin
if (ll_data_val_in)
if (ll_data_last_in)
// correct frame size, finishing, current dword: Reserved
begin
state <= STATE_IDLE;
end
else
// incorrect frame size
begin
state <= STATE_IN_SDB_ERR;
dword_cnt <= 14'h1;
end
end
STATE_IN_SDB_ERR:
// FIS was started as Set Device Bits FIS, but for some reason it has a size more than needed
// just wait until it's over and assert an error
begin
if (ll_data_val_in)
if (ll_data_last_in)
begin
bad_fis_received <= 1'b1;
state <= STATE_IDLE;
end
else
begin
if (watchdog_dwords)
// if for some reason FIS continue transferring for too long, terminate it
begin
state <= STATE_IDLE;
incom_stop_req_timeout <= 1'b1;
end
else
dword_cnt <= dword_cnt + 1'b1;
end
end
STATE_OUT_DATA_H:
// Send data FIS header
begin
if (ll_data_strobe_in)
begin
state <= STATE_OUT_DATA_D;
dword_cnt <= 14'h1;
end
end
STATE_OUT_DATA_D:
// Send data FIS data payload
begin
if (ll_data_strobe_in)
begin
if (cl_data_last_in)
begin
// All data is transmitted
dword_cnt <= 14'h0;
state <= STATE_OUT_WAIT_RESP;
end
else
if (dword_cnt == 2048)
// data_limit_exceed - wire assigned
state <= STATE_IDLE;
else
begin
state <= STATE_OUT_DATA_D;
dword_cnt <= dword_cnt + 1'b1;
end
end
end
STATE_OUT_REG:
// Register Host 2 Device FIS
begin
if (ll_data_strobe_in)
// 5 header dwords, then wait for a reception on a device side
if (dword_cnt[2:0] == 3'h4)
begin
dword_cnt <= 14'h0;
state <= STATE_OUT_WAIT_RESP;
end
else
begin
state <= STATE_OUT_REG;
dword_cnt <= dword_cnt + 1'b1;
end
end
STATE_OUT_DMAS:
// DMA Setup outcoming FIS
begin
if (ll_data_strobe_in)
// 7 header dwords, then wait for a reception on a device side
if (dword_cnt[2:0] == 3'h6)
begin
dword_cnt <= 14'h0;
state <= STATE_OUT_WAIT_RESP;
end
else
begin
state <= STATE_OUT_DMAS;
dword_cnt <= dword_cnt + 1'b1;
end
end
STATE_OUT_BIST:
begin
if (ll_data_strobe_in)
// 3 header dwords, then wait for a reception on a device side
if (dword_cnt[2:0] == 3'h2)
begin
dword_cnt <= 14'h0;
state <= STATE_OUT_WAIT_RESP;
end
else
begin
state <= STATE_OUT_BIST;
dword_cnt <= dword_cnt + 1'b1;
end
end
STATE_OUT_WAIT_RESP:
begin
if (frame_done_good)
// cmd_done_good wire assigned
state <= STATE_IDLE;
else
if (frame_done_bad)
// cmd_done_bad wire assigned
state <= STATE_IDLE;
else
if (dword_cnt == WATCHDOG_EOF_LIMIT)
// in here dword_cnt works as a watchdog timer
begin
state <= STATE_IDLE;
// watchdog_eof wire assigned
// for now while debugging let it be indicated on higher level TODO Choose exception. May be send incom stop req.
// Be aware of no response for that. In such case go for rst for ll. Or better make link_reset -> 1. And dont forget for oob
end
else
begin
dword_cnt <= dword_cnt + 1'b1;
state <= STATE_OUT_WAIT_RESP;
end
end
STATE_IN_UNRECOG:
begin
if (incom_done | incom_invalidate)
// transmission complete
// incom_ack_bad wire assigned
state <= STATE_IDLE;
else
if (watchdog_dwords)
begin
state <= STATE_IDLE;
incom_stop_req_timeout <= 1'b1;
end
else
begin
dword_cnt <= dword_cnt + 1'b1;
state <= STATE_IN_UNRECOG;
end
end
default:
begin
end
endcase
// buys circuit
assign cmd_busy = |state | frame_busy;
// respond if received FIS had any meaning in terms of TL
// actual response shall come next tick after done signal to fit LL fsm
reg incom_done_r;
reg incom_done_bad_r;
always @ (posedge clk)
incom_done_bad_r <= incom_done & state == STATE_IN_UNRECOG;
always @ (posedge clk)
incom_done_r <= incom_done;
assign incom_ack_bad = incom_done_bad_r | bad_fis_received;
assign incom_ack_good = incom_done_r & ~incom_ack_bad;
// after a device says it received the FIS, reveal the error code
assign cmd_done_good = state == STATE_OUT_WAIT_RESP & frame_done_good;
assign cmd_done_bad = state == STATE_OUT_WAIT_RESP & frame_done_bad;
// Reg H2D FIS header
wire [31:0] header_regfis;
assign header_regfis = dword_cnt[2:0] == 3'h0 ? {sh_feature_in[7:0], sh_command_in, cmd_type_r == CMD_TYPE_REG_CMD, 3'h0, cmd_port_r, 8'h27} : // features command C R R R PMPort FISType
dword_cnt[2:0] == 3'h1 ? {sh_dev_in, sh_lba_in[39:32], sh_lba_in[23:16], sh_lba_in[7:0]} : // Device LBAHigh LBAMid LBALow
dword_cnt[2:0] == 3'h2 ? {sh_feature_in[15:8], sh_lba_in[47:40], sh_lba_in[31:24], sh_lba_in[15:8]} : // Features (exp) LBAHigh (exp) LBAMid (exp) LBALow (exp)
dword_cnt[2:0] == 3'h3 ? {sh_control_in[7:0], 8'h00, sh_count_in[15:0]} : // Control Reserved SectorCount (exp) SectorCount
/*dword_cnt[2:0] == 3'h4 ?*/ {32'h0000}; // Reserved
// DMA Setup FIS header
wire [31:0] header_dmas;
assign header_dmas = dword_cnt[3:0] == 3'h0 ? {8'h0, 8'h0, sh_autoact_in, sh_inter_in, sh_dir_in, 1'b0, cmd_port_r, 8'h41} : // Reserved, Reserved, A I D R PMPort, FIS Type
dword_cnt[3:0] == 3'h1 ? {sh_dma_id_in[31:0]} : // DMA Buffer Identifier Low
dword_cnt[3:0] == 3'h2 ? {sh_dma_id_in[63:32]} : // DMA Buffer Identifier High
dword_cnt[3:0] == 3'h4 ? {sh_buf_off_in[31:0]} : // DMA Buffer Offset
dword_cnt[3:0] == 3'h5 ? {sh_dma_cnt_in[31:0]} : // DMA Transfer Count
/* 3'h3 | 3'h6 */ {32'h0000}; // Reserved
// BIST Activate FIS header
wire [31:0] header_bist; // TODO
assign header_bist = dword_cnt[3:0] == 3'h0 ? {8'h00, 8'h00, 4'h0, cmd_port_r, 8'h58} : // Reserved, T A S L F P R V, R R R R PMPort, FIS Type
dword_cnt[3:0] == 3'h1 ? {32'h00000000} : // Data1
dword_cnt[3:0] == 3'h2 ? {32'h00000000} : // Data2
{32'h00000000};
// Data FIS header
wire [31:0] header_data;
assign header_data = {8'h00, 8'h00, 4'h0, cmd_port_r, 8'h46}; // Reserved, Reserved, R R R R PMPort, FIS Type
assign ll_header_val = state == STATE_OUT_REG | state == STATE_OUT_DMAS | state == STATE_OUT_BIST | state == STATE_OUT_DATA_H;
assign ll_header_last = state == STATE_OUT_REG & dword_cnt[2:0] == 3'h4 |
state == STATE_OUT_DMAS & dword_cnt[2:0] == 3'h6 |
state == STATE_OUT_BIST & dword_cnt[2:0] == 3'h2;
assign ll_header_dword = {32{state == STATE_OUT_REG}} & header_regfis |
{32{state == STATE_OUT_DMAS}} & header_dmas |
{32{state == STATE_OUT_BIST}} & header_bist |
{32{state == STATE_OUT_DATA_H}} & header_data;
// bypass data from ll to cl if it's data stage in data FIS
assign cl_data_val_out = ll_data_val_in & state == STATE_IN_DATA;
assign cl_data_last_out = ll_data_val_in & ll_data_last_in & state == STATE_IN_DATA;
assign cl_data_mask_out = ll_data_mask_in;
assign cl_data_out = ll_data_in & {32{cl_data_val_out}};
assign ll_data_busy_out = cl_data_busy_in;
// set data to ll: bypass payload from cl or headers constructed in here
assign ll_data_val_out = ll_header_val | cl_data_val_in;
assign ll_data_last_out = ll_header_last & ll_header_val | cl_data_last_in & ~ll_header_val;
assign ll_data_out = ll_header_dword & {32{ll_header_val}} | cl_data_in & {32{~ll_header_val}};
assign ll_data_mask_out = {2{ll_header_val}} | cl_data_mask_in & {2{~ll_header_val}};
// limit was 2048 words + 1 headers
assign data_limit_exceeded = dword_cnt == 14'd2048 & ~cl_data_last_in;
// check if no data was obtained from buffer by ll when we're waiting for a response
wire chk_strobe_while_waitresp;
assign chk_strobe_while_waitresp = state == STATE_OUT_WAIT_RESP & ll_data_strobe_in;
// issue a FIS
assign frame_req = cmd_val & state == STATE_IDLE & ~frame_busy;
// update shadow registers as soon as transaction finishes TODO invalidate in case of errors
// TODO update only corresponding fields, which was updated during the transmission
assign sh_lba_out = loc_lba;
assign sh_count_out = loc_count;
assign sh_command_out = loc_command;
assign sh_err_out = loc_err;
assign sh_status_out = loc_status;
assign sh_estatus_out = loc_estatus;
assign sh_dev_out = loc_dev;
assign sh_port_out = loc_port;
assign sh_inter_out = loc_inter;
assign sh_dir_out = loc_dir;
assign sh_dma_id_out = loc_dma_id;
assign sh_dma_off_out = loc_dma_off;
assign sh_dma_cnt_out = loc_dma_cnt;
assign sh_tran_cnt_out = loc_tran_cnt;
assign sh_notif_out = loc_notif;
assign sh_autoact_out = loc_autoact;
assign sh_lba_val_out = ll_data_last_in;
assign sh_count_val_out = ll_data_last_in;
assign sh_command_val_out = ll_data_last_in;
assign sh_err_val_out = ll_data_last_in;
assign sh_status_val_out = ll_data_last_in;
assign sh_estatus_val_out = ll_data_last_in;
assign sh_dev_val_out = ll_data_last_in;
assign sh_port_val_out = ll_data_last_in;
assign sh_inter_val_out = ll_data_last_in;
assign sh_dir_val_out = ll_data_last_in;
assign sh_dma_id_val_out = ll_data_last_in;
assign sh_dma_off_val_out = ll_data_last_in;
assign sh_dma_cnt_val_out = ll_data_last_in;
assign sh_tran_cnt_val_out = ll_data_last_in;
assign sh_notif_val_out = ll_data_last_in;
assign sh_autoact_val_out = ll_data_last_in;
`ifdef CHECKERS_ENABLED
always @ (posedge clk)
if (~rst)
if (chk_strobe_while_waitresp)
begin
$display("ERROR in %m: retrieving data while being in a STATE_OUT_WAIT_RESP state");
$finish;
end
`endif
// eof response watchdog
assign watchdog_eof = dword_cnt == WATCHDOG_EOF_LIMIT & state == STATE_OUT_WAIT_RESP;
`ifdef CHECKERS_ENABLED
always @ (posedge clk)
if (~rst)
if (watchdog_eof)
begin
$display("WARNING in %m: watchdog_eof asserted");
$stop;
end
`endif
`ifdef CHECKERS_ENABLED
always @ (posedge clk)
if (~rst)
if (watchdog_dwords)
begin
$display("ERROR in %m: state %h - current FIS contains more than 2048 dwords", state);
$finish;
end
`endif
wire chk_inc_dword_limit_exceeded;
assign chk_inc_dword_limit_exceeded = state == STATE_IN_DATA & dword_cnt == 14'd2049;
`ifdef CHECKERS_ENABLED
always @ (posedge clk)
if (~rst)
if (chk_inc_dword_limit_exceeded)
begin
$display("ERROR in %m: received more than 2048 words in one FIS");
$finish;
end
`endif
endmodule
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/simcoco/ 0000775 0000000 0000000 00000000000 12572445207 0021455 5 ustar 00root root 0000000 0000000 x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/simcoco/Makefile 0000664 0000000 0000000 00000001332 12572445207 0023114 0 ustar 00root root 0000000 0000000 TOPLEVEL := sata_host
TOPLEVEL_LANG ?= verilog
PWD=$(shell pwd)
COCOTB=~/sata/git/x393_sata/coco
ifeq ($(OS),Msys)
WPWD=$(shell sh -c 'pwd -W')
PYTHONPATH := $(WPWD);$(PYTHONPATH)
else
WPWD=$(shell pwd)
PYTHONPATH := $(WPWD):$(PYTHONPATH)
endif
export PYTHONPATH
VERILOG_SOURCES = $(WPWD)/../sata_host.v $(WPWD)/../x393/glbl.v $(WPWD)/../GTXE2_CHANNEL.v
COMPILE_ARGS = -I$(WPWD)/../ -I$(WPWD)/../x393/ -I$(WPWD)/../x393/axi/ -I$(WPWD)/../host/ -y$(WPWD)/../x393/unisims -y$(WPWD)/../x393/util_modules/ -y$(WPWD)/../x393/wrap -y$(WPWD)/../x393/memctrl -D CHECKERS_ENABLED -D SIMULATION
GPI_IMPL := vpi
export TOPLEVEL_LANG
MODULE ?= test_host
include $(COCOTB)/makefiles/Makefile.inc
include $(COCOTB)/makefiles/Makefile.sim
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/simcoco/driver_host.py 0000664 0000000 0000000 00000027032 12572445207 0024363 0 ustar 00root root 0000000 0000000 import cocotb
from cocotb.triggers import Timer, RisingEdge
from cocotb.drivers import BusDriver
from cocotb.result import ReturnValue
import timescale
class SataHostDriver(BusDriver):
'''
shall drive sata_host interface
'''
_signals = ['al_cmd_in', 'al_cmd_val_in', 'al_cmd_out',
# shadow regs inputs
'al_sh_data_in', 'al_sh_data_val_in', 'al_sh_data_strobe_in',
'al_sh_feature_in', 'al_sh_feature_val_in', 'al_sh_lba_lo_in',
'al_sh_lba_lo_val_in', 'al_sh_lba_hi_in', 'al_sh_lba_hi_val_in',
'al_sh_count_in', 'al_sh_count_val_in', 'al_sh_command_in',
'al_sh_command_val_in', 'al_sh_dev_in', 'al_sh_dev_val_in',
'al_sh_control_in', 'al_sh_control_val_in', 'al_sh_dma_id_lo_in',
'al_sh_dma_id_lo_val_in', 'al_sh_dma_id_hi_in', 'al_sh_dma_id_hi_val_in',
'al_sh_buf_off_in', 'al_sh_buf_off_val_in', 'al_sh_tran_cnt_in',
'al_sh_tran_cnt_val_in', 'al_sh_autoact_in', 'al_sh_autoact_val_in',
'al_sh_inter_in', 'al_sh_inter_val_in', 'al_sh_dir_in',
'al_sh_dir_val_in', 'al_sh_dma_cnt_in', 'al_sh_dma_cnt_val_in',
'al_sh_notif_in', 'al_sh_notif_val_in', 'al_sh_port_in',
'al_sh_port_val_in',
# shadow regs outputs
'sh_data_val_out', 'sh_data_out', 'sh_control_out',
'sh_feature_out', 'sh_lba_out', 'sh_count_out',
'sh_command_out', 'sh_err_out', 'sh_status_out',
'sh_estatus_out', 'sh_dev_out', 'sh_port_out',
'sh_inter_out', 'sh_dir_out', 'sh_dma_id_out',
'sh_dma_off_out', 'sh_dma_cnt_out', 'sh_tran_cnt_out',
'sh_notif_out', 'sh_autoact_out']
def __init__(self, entity, name, clk):
BusDriver.__init__(self, entity, name, clk)
# initial interface states
self.bus.al_cmd_in.setimmediatevalue(0)
self.bus.al_cmd_val_in.setimmediatevalue(0)
self.bus.al_cmd_out.setimmediatevalue(0)
self.bus.al_sh_data_in.setimmediatevalue(0)
self.bus.al_sh_data_val_in.setimmediatevalue(0)
self.bus.al_sh_data_strobe_in.setimmediatevalue(0)
self.bus.al_sh_feature_in.setimmediatevalue(0)
self.bus.al_sh_feature_val_in.setimmediatevalue(0)
self.bus.al_sh_lba_lo_in.setimmediatevalue(0)
self.bus.al_sh_lba_lo_val_in.setimmediatevalue(0)
self.bus.al_sh_lba_hi_in.setimmediatevalue(0)
self.bus.al_sh_lba_hi_val_in.setimmediatevalue(0)
self.bus.al_sh_count_in.setimmediatevalue(0)
self.bus.al_sh_count_val_in.setimmediatevalue(0)
self.bus.al_sh_command_in.setimmediatevalue(0)
self.bus.al_sh_command_val_in.setimmediatevalue(0)
self.bus.al_sh_dev_in.setimmediatevalue(0)
self.bus.al_sh_dev_val_in.setimmediatevalue(0)
self.bus.al_sh_control_in.setimmediatevalue(0)
self.bus.al_sh_control_val_in.setimmediatevalue(0)
self.bus.al_sh_dma_id_lo_in.setimmediatevalue(0)
self.bus.al_sh_dma_id_lo_val_in.setimmediatevalue(0)
self.bus.al_sh_dma_id_hi_in.setimmediatevalue(0)
self.bus.al_sh_dma_id_hi_val_in.setimmediatevalue(0)
self.bus.al_sh_buf_off_in.setimmediatevalue(0)
self.bus.al_sh_buf_off_val_in.setimmediatevalue(0)
self.bus.al_sh_tran_cnt_in.setimmediatevalue(0)
self.bus.al_sh_tran_cnt_val_in.setimmediatevalue(0)
self.bus.al_sh_autoact_in.setimmediatevalue(0)
self.bus.al_sh_autoact_val_in.setimmediatevalue(0)
self.bus.al_sh_inter_in.setimmediatevalue(0)
self.bus.al_sh_inter_val_in.setimmediatevalue(0)
self.bus.al_sh_dir_in.setimmediatevalue(0)
self.bus.al_sh_dir_val_in.setimmediatevalue(0)
self.bus.al_sh_dma_cnt_in.setimmediatevalue(0)
self.bus.al_sh_dma_cnt_val_in.setimmediatevalue(0)
self.bus.al_sh_notif_in.setimmediatevalue(0)
self.bus.al_sh_notif_val_in.setimmediatevalue(0)
self.bus.al_sh_port_in.setimmediatevalue(0)
self.bus.al_sh_port_val_in.setimmediatevalue(0)
@cocotb.coroutine
def getCmd(self):
''' get the value of al_cmd register '''
raise ReturnValue(self.bus.al_cmd_out & 7 ) # get the last 3 bits
@cocotb.coroutine
def setCmd(self, cmd_type, cmd_port, cmd_val):
self.bus.al_cmd_in <= ((cmd_type << 5) + (cmd_port << 1) + (cmd_val)) << 3
self.bus.al_cmd_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_cmd_val_in <= 0
@cocotb.coroutine
def getReg(self, addr):
if addr == 0:
raise ReturnValue(self.bus.sh_data_out)
elif addr == 1:
raise ReturnValue(self.bus.sh_feature_out)
elif addr == 2:
raise ReturnValue(self.bus.sh_lba_out)
elif addr == 3:
raise ReturnValue(self.bus.sh_lba_out << 24)
elif addr == 4:
raise ReturnValue(self.bus.sh_count_out)
elif addr == 5:
raise ReturnValue(self.bus.sh_command_out)
elif addr == 6:
raise ReturnValue(self.bus.sh_dev_out)
elif addr == 7:
raise ReturnValue(self.bus.sh_control_out)
elif addr == 8:
raise ReturnValue(self.bus.sh_dma_id_out)
elif addr == 9:
raise ReturnValue(self.bus.sh_dma_id_out << 32)
elif addr == 10:
raise ReturnValue(self.bus.sh_dma_off_out)
elif addr == 11:
raise ReturnValue(self.bus.sh_tran_cnt_out)
elif addr == 12:
raise ReturnValue(self.bus.sh_autoact_out)
elif addr == 13:
raise ReturnValue(self.bus.sh_inter_out)
elif addr == 14:
raise ReturnValue(self.bus.sh_dir_out)
elif addr == 15:
raise ReturnValue(self.bus.al_cmd_out)
elif addr == 16:
raise ReturnValue(self.bus.sh_err_out)
elif addr == 17:
raise ReturnValue(self.bus.sh_status_out)
elif addr == 18:
raise ReturnValue(self.bus.sh_estatus_out)
elif addr == 19:
raise ReturnValue(self.bus.sh_port_out)
elif addr == 20:
raise ReturnValue(self.bus.sh_dma_cnt_out)
elif addr == 21:
raise ReturnValue(self.bus.sh_notif_out)
else:
raise ReturnValue(0)
@cocotb.coroutine
def setReg(self, addr, data):
if addr == 0:
self.bus.al_sh_data_in <= data
self.bus.al_sh_data_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_data_in <= 0
self.bus.al_sh_data_val_in <= 0
elif addr == 1:
self.bus.al_sh_feature_in <= data
self.bus.al_sh_feature_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_feature_in <= 0
self.bus.al_sh_feature_val_in <= 0
elif addr == 2:
self.bus.al_sh_lba_lo_in <= data
self.bus.al_sh_lba_lo_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_lba_lo_in <= 0
self.bus.al_sh_lba_lo_val_in <= 0
elif addr == 3:
self.bus.al_sh_lba_hi_in <= data
self.bus.al_sh_lba_hi_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_lba_hi_in <= 0
self.bus.al_sh_lba_hi_val_in <= 0
elif addr == 4:
self.bus.al_sh_count_in <= data
self.bus.al_sh_count_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_count_in <= 0
self.bus.al_sh_count_val_in <= 0
elif addr == 5:
self.bus.al_sh_command_in <= data
self.bus.al_sh_command_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_command_in <= 0
self.bus.al_sh_command_val_in <= 0
elif addr == 6:
self.bus.al_sh_dev_in <= data
self.bus.al_sh_dev_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_dev_in <= 0
self.bus.al_sh_dev_val_in <= 0
elif addr == 7:
self.bus.al_sh_control_in <= data
self.bus.al_sh_control_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_control_in <= 0
self.bus.al_sh_control_val_in <= 0
elif addr == 8:
self.bus.al_sh_dma_id_lo_in <= data
self.bus.al_sh_dma_id_lo_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_dma_id_lo_in <= 0
self.bus.al_sh_dma_id_lo_val_in <= 0
elif addr == 9:
self.bus.al_sh_dma_id_hi_in <= data
self.bus.al_sh_dma_id_hi_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_dma_id_hi_in <= 0
self.bus.al_sh_dma_id_hi_val_in <= 0
elif addr == 10:
self.bus.al_sh_dma_off_in <= data
self.bus.al_sh_dma_off_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_dma_off_in <= 0
self.bus.al_sh_dma_off_val_in <= 0
elif addr == 11:
self.bus.al_sh_tran_cnt_in <= data
self.bus.al_sh_tran_cnt_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_tran_cnt_in <= 0
self.bus.al_sh_tran_cnt_val_in <= 0
elif addr == 12:
self.bus.al_sh_autoact_in <= data
self.bus.al_sh_autoact_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_autoact_in <= 0
self.bus.al_sh_autoact_val_in <= 0
elif addr == 13:
self.bus.al_sh_inter_in <= data
self.bus.al_sh_inter_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_inter_in <= 0
self.bus.al_sh_inter_val_in <= 0
elif addr == 14:
self.bus.al_sh_dir_in <= data
self.bus.al_sh_dir_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_dir_in <= 0
self.bus.al_sh_dir_val_in <= 0
elif addr == 19:
self.bus.al_sh_port_in <= data
self.bus.al_sh_port_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_port_in <= 0
self.bus.al_sh_port_val_in <= 0
elif addr == 20:
self.bus.al_sh_dma_cnt_in <= data
self.bus.al_sh_dma_cnt_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_dma_cnt_in <= 0
self.bus.al_sh_dma_cnt_val_in <= 0
elif addr == 21:
self.bus.al_sh_notif_in <= data
self.bus.al_sh_notif_val_in <= 1
yield RisingEdge(self.clock)
self.bus.al_sh_notif_in <= 0
self.bus.al_sh_notif_val_in <= 0
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/simcoco/sata_driver.py 0000664 0000000 0000000 00000006061 12572445207 0024335 0 ustar 00root root 0000000 0000000 import cocotb
from cocotb.triggers import Timer, RisingEdge
from cocotb.drivers import BusDriver
from cocotb.result import ReturnValue
class SataHalfWord(BusDriver):
''' Every 8 bits -> 10 on phy line '''
def __init__(self, data, control):
self.data = [].append(data)
self.control = [].append(control)
class SataPhyDriver(BusDriver):
_signals = ['txp_out', 'txn_out', 'rxp_in', 'rxp_out']
def __init__(self, entity, name, clock, gen):
''' The clock shall be serial '''
BusDriver.__init__(self, entity, name, clock)
# outcoming elecidle flag
self.txelecidle = 1
# queue of *parallel* values to send
self.sq = []
# stream trace of received parallel values
self.rq = []
# sata generation (~ clock frequency)
self.gen = gen
self.driveBit(0)
# Queues management section
def addHalfWord(self, hword):
self.sq = self.sq.append(hword)
# elecidle management section
def setElecIdle(self):
self.txelecidle = 1
def unsetElecIdle(self):
self.txelecidle = 0
# Data send section
def driveBit(self, value):
if txelecidle:
self.bus.txp_out.setimmediatevalue('z')
self.bus.txn_out.setimmediatevalue('z')
elif value == 1:
self.bus.txp_out.setimmediatevalue(1)
self.bus.txn_out.setimmediatevalue(0)
elif value == 0:
self.bus.txp_out.setimmediatevalue(0)
self.bus.txn_out.setimmediatevalue(1)
else:
self.bus.txp_out.setimmediatevalue(value)
self.bus.txn_out.setimmediatevalue(value)
yield RisingEdge(self.clock)
def serial(self, parallel):
for i in range(9, -1, -1):
value = '{0:b}'.format(parallel)[i]
driveBit(value)
def sendQueue(self):
for hword in self.sq:
serial(self, hword)
class SataPhyMonitor(BusMonitor):
_signals = ['txp_out', 'txn_out', 'rxp_in', 'rxp_out']
def __init__(self, *args, **kwargs):
BusMOnitor.__init__(self, *arggs, **kwargs)
# Data receive section
def getBit(self)
yield RisingEdge(self.clock)
return self.bus.txp_out.getValue()
def getHalfWord(self):
hword = ''
for i in range(9, -1, -1):
hword.append(getBit)
return hword
def alignReciever(self):
''' look for a comma character in a bitstream
returns running disparity value, when comma occurs '''
# get an initial hword
hword = ''
for i in range(9, -1, -1):
hword.append(getBit)
# shift until we meet a comma
while True:
if hword == '0011111010':
disparity = 1
break
elif hword == '1100000101':
disparity = 0
break
else
hword.pop(1)
hword.append(getBit)
return disparity
def decodeHalfWord(self):
pass
# oob
def monitorElecidle(self):
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/simcoco/test_host.py 0000664 0000000 0000000 00000002511 12572445207 0024042 0 ustar 00root root 0000000 0000000 import timescale
import cocotb
from cocotb.triggers import Timer, RisingEdge, FallingEdge
from driver_host import SataHostDriver
TIMESCALE = 1000 # in ps
@cocotb.coroutine
def issueReset(rst, length):
rst <= 1
yield Timer(length * TIMESCALE)
rst <= 0
@cocotb.coroutine
def setClk(clk, halfperiod):
while True:
clk <= 0
yield Timer(halfperiod * TIMESCALE)
clk <= 1
yield Timer(halfperiod * TIMESCALE)
@cocotb.coroutine
def setDiffClk(clkp, clkn, halfperiod):
while True:
clkp <= 0
clkn <= 1
yield Timer(halfperiod * TIMESCALE)
clkp <= 1
clkn <= 0
yield Timer(halfperiod * TIMESCALE)
@cocotb.test()
def basic_test(dut):
cocotb.fork(setDiffClk(dut.extclk_p, dut.extclk_n, 3.333))
dut.rst = 0
yield Timer(30 * TIMESCALE)
yield issueReset(dut.extrst, 1050)
shadow = SataHostDriver(dut, "", dut.clk)
yield FallingEdge(dut.rst)
# set random data to shadow registers
yield RisingEdge(dut.clk)
cocotb.fork(shadow.setReg(1,0xe))
cocotb.fork(shadow.setReg(4,0xdead))
cocotb.fork(shadow.setReg(5,0xbee1))
yield Timer(100 * TIMESCALE)
# write registers to a device
yield RisingEdge(dut.clk)
# cocotb.fork(shadow.setCmd(cmd_type = 1, cmd_port = 0, cmd_val = 1))
yield Timer(40000 * TIMESCALE)
x393_sata-d99f18e06730a7640247d0e20f6cb1eaf5631348/simcoco/test_host.pyc 0000664 0000000 0000000 00000003473 12572445207 0024215 0 ustar 00root root 0000000 0000000 ó
ÆÓUc @ s™ d d l Z d d l Z d d l m Z m Z m Z d d l m Z d Z e j d „ ƒ Z
e j d „ ƒ Z e j d „ ƒ Z e j
ƒ d „ ƒ Z d S( iÿÿÿÿN( t Timert
RisingEdget FallingEdge( t SataHostDriveriè c c s' | d k t | t ƒ V| d k d S( Ni i ( R t TIMESCALE( t rstt length( ( s2 /home/alexey/sata/git/x393_sata/simul/test_host.pyt
issueReset s
c c sC x<