pax_global_header 0000666 0000000 0000000 00000000064 12555570767 0014535 g ustar 00root root 0000000 0000000 52 comment=bc46d5537b0dfc03e4bf726fe279dba239910775
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/ 0000775 0000000 0000000 00000000000 12555570767 0017250 5 ustar 00root root 0000000 0000000 x353-bc46d5537b0dfc03e4bf726fe279dba239910775/.project 0000664 0000000 0000000 00000004232 12555570767 0020720 0 ustar 00root root 0000000 0000000
x353ise_logs/ISEBitgen.log1/home/andrey/git/x353/ise_logs/ISEBitgen-20150727202331879.logise_logs/ISEMap.log1/home/andrey/git/x353/ise_logs/ISEMap-20150727201724222.logise_logs/ISENGDBuild.log1/home/andrey/git/x353/ise_logs/ISENGDBuild-20150727201724222.logise_logs/ISEPAR.log1/home/andrey/git/x353/ise_logs/ISEPAR-20150727202331879.logise_logs/ISEPartgen.log1/home/andrey/git/x353/ise_logs/ISEPartgen-20150726172041010.logise_logs/ISETraceMap.log1/home/andrey/git/x353/ise_logs/ISETraceMap-20150727201724222.logise_logs/ISETracePAR.log1/home/andrey/git/x353/ise_logs/ISETracePAR-20150727202331879.logise_logs/ISExst.log1/home/andrey/git/x353/ise_logs/ISExst-20150727201317048.logise_state/x353-map.tgz1/home/andrey/git/x353/ise_state/x353-map-20150727201724222.tgzise_state/x353-ngdbuild.tgz1/home/andrey/git/x353/ise_state/x353-ngdbuild-20150727201724222.tgzise_state/x353-par.tgz1/home/andrey/git/x353/ise_state/x353-par-20150727202331879.tgzise_state/x353-synth.tgz1/home/andrey/git/x353/ise_state/x353-synth-20150727201317048.tgz
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/LICENSE 0000664 0000000 0000000 00000104506 12555570767 0020263 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
.
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/README.md 0000664 0000000 0000000 00000007021 12555570767 0020527 0 ustar 00root root 0000000 0000000 x353
=====
FPGA code for the current Elphel NC353 camera (and other products such as Eyesis4pi based on the same
10353E system board ), updated to work with [VDT plugin](https://github.com/Elphel/vdt-plugin)
This repository is created as a reference for simulation of image acquisition, processing and compression
in the new NC393 camera that includes functionality of the previous one, so the same input image (on one of
the 4 channels) should generate the same intermediate and final compressed files on both cameras.
We will also try to make it possible to generate functional bitstream files compatible with the existing
NC353 camera (so others will be able to modify their camera code with the current version of Xilinx tools),
but we are not there yet - ***this project is valid for simulation only!***
Here is what makes it difficult:
1. Xilinx abandoned support for the older devices in the current software called "Vivado".
2. Last verion of the ISE (it is ISE 14.7) can not use the older code "as is"
3. We were able to modify the Verilog code to be parsed by the current XST, but it does not
recognize some statements in the *.xcf constraints file (I had to rename original *.ucf to *.xcf).
4. Attempt to try old parser (suggested by XST itself as the new parser is not the default for
the Spartan 3e):
```
WARNING:Xst:3152 - You have chosen to run a version of XST which is not the default
solution for the specified device family. You are free to use it in order to take
advantage of its enhanced HDL parsing/elaboration capabilities. However,
please be aware that you may be impacted by language support differences.
This version may also result in circuit performance and device utilization
differences for your particular design. You can always revert back to the
default XST solution by setting the "use_new_parser" option to value "no"
on the XST command line or in the XST process properties panel.
```
also failed. After I added recommended options:
```
run -use_new_parser no -ifn x353.prj -ofn x353.ngc -top x353 -p xc3s1200eft256 -uc x353.xcf -opt_mode speed -opt_level 1
```
and ISE noticed that:
```
WARNING:Xst:1583 - You are using an internal switch '-use_new_parser'.
```
It still repeated the same WARNING:Xst:3152 (see above) disregarding its own suggestion.
So we will need to find a way how to replace lines in the *xst file that cause errors in XST:
```
204 TIMEGRP "CPU_ADDR" = pads("A<*>");
205 TIMEGRP "CPU_ADDRCE" = "CPU_ADDR" pads("CE*");
206 TIMEGRP "CPU_DATA" = pads("D<*>");
207 TIMEGRP "WE" = pads("WE");
208 TIMEGRP "OE" = pads("OE");
209 TIMEGRP "DACK_PAD"= pads("DACK*");
209 TIMEGRP "DREQ_PAD"= pads("DREQ*");
210 TIMEGRP "ALLPADS"= pads("*");
```
```
ERROR:Xst:1888 - Processing TIMEGRP CPU_ADDR: User group 'pads("A<*>")' defined from
other user group pattern not supported.
```
Even Google does not know what to do about this Xilinx XST feature:
> No results found for "ERROR:Xst:1888".
>
> Results for ERROR:Xst:1888 (without quotes):
>
> ...
So we'try to find other ways to re-formulate old timing constraints preserving the same meaning and try
again to run tools. Until then I'll have to mention again ***this project is valid for simulation only!***
Update: Not yet tested with the real hardware, but the project was modified to work with ISE 14.7 (physical
constraints were changed to parameters from the old style synthesis attributes, and the tools genereted a
bitfile and even original timing constraints (after changing to uppercase) were met.
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/ 0000775 0000000 0000000 00000000000 12555570767 0021444 5 ustar 00root root 0000000 0000000 x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/color_proc353.v 0000664 0000000 0000000 00000105333 12555570767 0024234 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** color_proc353.v
**
** Color space converter (bayer-> YCbCr 4:2:1) for JPEG compressor
**
** Copyright (C) 2002-2010 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X333 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
`define debug_compressor
module color_proc (clk, // pixel clock (1/2 system clock - 80MHz)
en, // Enable (0 will reset states)
en_sdc, // enable subtracting of DC component
go, // pulse to star/restart (needed for each frame, repeat generated by the caller)
nblocks, // [17:0] number of 16x16 blocks to read (valid @ "go" pulse)
eot, // single-cycle end of transfer pulse
m_cb, // [9:0] scale for CB - default 0.564 (10'h90)
m_cr, // [9:0] scale for CB - default 0.713 (10'hb6)
memWasInit, // memory channel2 was just initialized - reset page address (at posedge clk)
di, // [7:0]
sdram_a, // [10:0] (MSB - SDRAM buffer page number)
sdram_rdy, // SDRAM buffer ready
sdram_next, // request to read a page to SDRAM buffer
inc_sdrama, // enable read sdram buffer
noMoreData, // used as alternative to end frame input (possibly broken frame)
dv_raw, // data valid for di (for testing to bypass color conversion - use di[7:0])
ignore_color, //zero Cb/Cr components
four_blocks, // use only 6 blocks fro the output, not 6
jp4_dc_improved, // in JP4 mode, compare DC coefficients to the same color ones
tile_margin, // margins around 16x16 tiles (0/1/2)
tile_shift, // tile shift from top left corner
converter_type, // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff, // divide differences by 2 (to fit in 8-bit range)
hdr, // second green absolute, not difference
do, // [9:0] data out (4:2:0) (signed, average=0)
avr, // [8:0] DC (average value) - RAM output, no register. For Y components 9'h080..9'h07f, for C - 9'h100..9'h0ff!
dv, // out data valid (will go high for at least 64 cycles)
ds, // single-cycle mark of the first pixel in a 64 (8x8) - pixel block
tn, // [2:0] tile number 0..3 - Y, 4 - Cb, 5 - Cr (valid with start)
first, // sending first MCU (valid @ ds)
last, // sending last MCU (valid @ ds)
n000, // [7:0] number of zero pixels (255 if 256)
n255, // [7:0] number of 0xff pixels (255 if 256)
bayer_phase, //[1:0]) bayer color filter phase 0:(GR/BG), 1:(RG/GB), 2: (BG/GR), 3: (GB/RG)
// below signals valid at ds ( 1 later than tn, first, last)
component_num, //[2:0] - component number (YCbCr: 0 - Y, 1 - Cb, 2 - Cr, JP4: 0-1-2-3 in sequence (depends on shift) 4 - don't use
component_color, // use color quantization table (YCbCR, jp4diff)
component_first, // first this component in a frame (DC absolute, otherwise - difference to previous)
component_lastinmb // last component in a macroblock;
`ifdef debug_compressor
,bcntrIsZero
,bcntr
`endif
);
input ignore_color;
input four_blocks; // use only 6 blocks fro the output, not 6
input jp4_dc_improved; // in JP4 mode, compare DC coefficients to the same color ones
input [1:0] tile_margin; // margins around 16x16 tiles (0/1/2)
input [2:0] tile_shift; // tile shift from top left corner
input [2:0] converter_type; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
input scale_diff; // divide differences by 2 (to fit in 8-bit range)
input hdr; // second green absolute, not difference
input clk, en, go, en_sdc;
input [17:0] nblocks;
output eot;
input [ 9:0] m_cb; // [9:0] scale for CB - default 0.564 (10'h90)
input [ 9:0] m_cr; // [9:0] scale for CB - default 0.713 (10'hb6)
input memWasInit; // memory channel2 was just initialized - reset page address (at posedge clk)
input [ 7:0] di;
output [ 10:0] sdram_a;
input sdram_rdy;
output sdram_next;
output inc_sdrama;
input noMoreData; // (@posedge clk) used as alternative to end frame input (possibly broken frame)
output dv_raw;
// output [ 8:0] do;
output [ 9:0] do;
// output [ 7:0] avr;
output [ 8:0] avr;
output dv;
output ds;
output [ 2:0] tn;
output first;
output last;
output [7:0] n000;
output [7:0] n255;
input [1:0] bayer_phase;
output [2:0] component_num; //[1:0] - component number (YCbCr: 0 - Y, 1 - Cb, 2 - Cr, JP4: 0-1-2-3 in sequence (depends on shift), >=4 - don't use
output component_color; // use color quantization table (YCbCR, jp4diff)
output component_first; // first this component in a frame (DC absolute, otherwise - difference to previous)
output component_lastinmb; // last component in a macroblock;
//debug
`ifdef debug_compressor
output bcntrIsZero;
output [17:0] bcntr;
`endif
wire [ 9:0] m_cb; // [9:0] scale for CB - default 0.564 (10'h90)
wire [ 9:0] m_cr; // [9:0] scale for CB - default 0.713 (10'hb6)
wire [7:0] di;
wire [8:0] y_out; // data from buffer
wire [8:0] c_out; // data from buffer
reg [1:0] wpage; // page (0/1) where data is being written to (both Y and CbCr)
reg [1:0] rpage; // page (0/1) from where data is sent out ( both Y and CbCr)
wire [10:0] sdram_a;
reg sdram_next;
reg [17:0] bcntr; // down counter of blocks left
reg bcntrIsZero; // one cycle of bcntr[]==0
reg eot;
reg ccv_start_en; //
reg ccv_out_start,ccv_out_start_d; // start output of YCbCr from buffers
reg [8:0] raddr; // output address of buffer memories (MSB selects Y(0)/CbCr(1))
reg dv0; // "dv0" - one cycle ahead of "dv" to compensate for "do" register latency
reg ds0; // "ds0" - one cycle ahead of "ds" to compensate for "do" register latency
// reg [8:0] do;
// reg [8:0] pre_do;
reg [9:0] do;
reg [9:0] pre_do;
reg [1:0] pre_dv, pre_ds;
wire dv=pre_dv[1];
wire ds=pre_ds[1];
wire [2:0] tn;
reg dv_raw;
// reg [13:0] accYA,accYB,accCb, accCr;
// reg [13:0] accY0,accY1,accY2,accY3,accC2b, accCr; //will use 6 individual accumulators for larger flexibility (different input sequence)
// 16x8 dual port RAM
reg buf_sel;
reg willbe_first;
reg first,first0;
reg last,last0;
reg [4:0] preline; // number of line in a tile, down counter (0x13->0, 0x11->0, 0x0f->0), 1 cycles ahead of data from SDRAM
reg [4:0] prepix; // number of pixel in a line in a tile, down counter (0x13->0, 0x11->0, 0x0f->0)
// reg [1:0] sdram_page;
reg [1:0] sdram_a9_page;
reg [8:0] sdram_a9;
reg [8:0] seq_cntr; // master
// reg [2:0] pre_inc_sdrama;
wire [4:0] tile_size;
wire [8:0] macroblock_period_minus1;
wire all_ready;
reg preline_was_0;
reg pre_start_of_line;
reg pre_first_pixel;
reg [8:0] sdrama_top_left; // address of top left corner to be processed
reg [2:0] sdrama_line_inc; // increment amount when proceeding to next tile line
reg inc_sdrama;
reg last_from_sdram; // reading last byte from SDRAM
reg first_pixel; // reading first pixel to color converter (di will be evailable next cycle)
reg tim2next;
reg [8:0] y_in, c_in;
reg [7:0] yaddrw, caddrw;
reg ywe, cwe;
reg color_enable, pre_color_enable;// prevent random colors in monochrome/JP46 modes (pre_* - sync input)
reg cs_pre_first_out; // clear color accumulators
wire [7:0] conv18_y_in, conv20_y_in, mono_y_in, jp4_y_in;
// wire [8:0] jp4diff_y_in, conv18_c_in, conv20_c_in;
wire [8:0] jp4diff_y_in, conv18_c_in, conv20_c_in;
wire [7:0] conv18_yaddrw, conv20_yaddrw, mono_yaddrw, jp4_yaddrw, jp4diff_yaddrw;
wire [6:0] conv18_caddrw, conv20_caddrw;
wire conv18_ywe, conv18_cwe, conv20_ywe, conv20_cwe, mono_ywe, jp4_ywe, jp4diff_ywe;
wire conv18_pre_first_out, conv20_pre_first_out, mono_pre_first_out, jp4_pre_first_out, jp4diff_pre_first_out;
reg [4:0] en_converters;
reg [2:0] converter_type_r;
reg ignore_color_r;
reg jp4_dc_improved_r;
// reg jp4_diff_r;
reg four_blocks_r;
reg scale_diff_r;
reg hdr_r;
reg [1:0] tile_margin_r; // SuppressThisWarning Veditor UNUSED
// reg [2:0] tile_shift_r;
reg [1:0] bayer_phase_r;
reg [3:0] bayer_phase_onehot;
reg raddr_lastInBlock;
reg raddr_updateBlock; // first in block, after last also. Should be when *_r match the currently selected converter for the macroblock
wire [2:0] component_num; //[1:0] - component number (YCbCr: 0 - Y, 1 - Cb, 2 - Cr, JP4: 0-1-2-3 in sequence (depends on shift) >=4 - don't use
wire component_color; // use color quantization table (YCbCR, jp4diff)
wire component_first; // first this component in a frame (DC absolute, otherwise - difference to previous)
// component_num,component_color,component_first for different converters vs tn (1 bit per tn (0..5)
reg component_lastinmb; // last component in a macroblock;
reg [5:0] component_numsL, component_numsLS; // component_num[0] vs tn
reg [5:0] component_numsM, component_numsMS; // component_num[1] vs tn
reg [5:0] component_numsH, component_numsHS; // component_num[2] vs tn
reg [5:0] component_colors, component_colorsS; // use color quantization table (YCbCR, jp4diff)
reg [5:0] component_firsts, component_firstsS; // first this component in a frame (DC absolute, otherwise - difference to previous)
reg eof_rq; // request to end frame if there will be no more data
assign sdram_a={sdram_a9_page[1:0],sdram_a9[8:0]};
assign tn[2:0]=raddr[8:6];
assign component_num[2:0]= {component_numsH[0],component_numsM[0],component_numsL[0]};
assign component_color = component_colors[0];
assign component_first = component_firsts[0];
assign all_ready = sdram_rdy && ccv_start_en;
assign macroblock_period_minus1[8:0] = four_blocks?(tile_margin[1]?9'h18f:(tile_margin[0]?9'h143:9'h0ff)):(tile_margin[1]?9'h18f:9'h17f);
assign tile_size[4:0] = tile_margin[1]?5'h13:(tile_margin[0]?5'h11:5'h0f);
always @ (posedge clk) begin
if (!en) seq_cntr[8:0] <=9'h0;
else if (seq_cntr[8:0]!=0) seq_cntr[8:0] <= seq_cntr[8:0] -1;
else if (all_ready) seq_cntr[8:0] <= macroblock_period_minus1;
preline_was_0 <= (preline[4:0]==5'h0);
if ((seq_cntr[8:0]==0) || ((prepix[4:0]==0) && !preline_was_0) ) prepix[4:0] <= tile_size[4:0];
else if (prepix[4:0]!=0) prepix[4:0] <= prepix[4:0] - 1;
if (seq_cntr[8:0]==0) preline[4:0] <= tile_size[4:0];
else if ((prepix[4:0]==0) && !preline_was_0) preline[4:0] <= preline[4:0] - 1;
pre_start_of_line <= ((seq_cntr[8:0]==0) || ((prepix[4:0]==0) && !preline_was_0) );
pre_first_pixel <= en && (seq_cntr[8:0]==9'h0) && all_ready;
case (tile_shift[2:0])
3'h0: sdrama_top_left[8:0] <= 9'h0;
3'h1: sdrama_top_left[8:0] <= 9'h15;
3'h2: sdrama_top_left[8:0] <= 9'h2a;
3'h3: sdrama_top_left[8:0] <= 9'h3f;
3'h4: sdrama_top_left[8:0] <= 9'h54;
endcase
case (tile_margin[1:0])
2'h0: sdrama_line_inc[2:0] <= 3'h5;
2'h1: sdrama_line_inc[2:0] <= 3'h3;
2'h2: sdrama_line_inc[2:0] <= 3'h1;
endcase
first_pixel <= pre_first_pixel;
last_from_sdram <= en & preline_was_0 && (prepix[4:0]==0);
inc_sdrama <= en & (pre_first_pixel || (inc_sdrama && !last_from_sdram ));
if (pre_first_pixel) sdram_a9[8:0] <= sdrama_top_left[8:0];
else if (inc_sdrama) sdram_a9[8:0] <= sdram_a9[8:0] + (pre_start_of_line ? sdrama_line_inc[2:0] : 3'b1);
if (!en || memWasInit) sdram_a9_page[1:0] <= 2'h0;
else if (last_from_sdram && inc_sdrama) sdram_a9_page[1:0] <= sdram_a9_page[1:0]+1;
// wpage[1:0] valid with ywe
if (cs_pre_first_out) wpage[1:0] <= sdram_a9_page[1:0]; // copy page from SDRAM buffer
// register control modes to be valid while overlapping
if (pre_first_pixel) begin
converter_type_r [2:0] <= converter_type[2:0];
ignore_color_r <= ignore_color;
jp4_dc_improved_r <= jp4_dc_improved;
// jp4_diff_r <= (converter_type[2:0]==3'h4);
four_blocks_r <= four_blocks;
scale_diff_r <= scale_diff;
hdr_r <= hdr;
// scale_diff <= (converter_type[2:0]==3'h5);
tile_margin_r[1:0] <= tile_margin[1:0];
// tile_shift_r[2:0] <= tile_shift[2:0];
bayer_phase_r[1:0] <= bayer_phase[1:0];
bayer_phase_onehot[3:0]<={(bayer_phase[1:0]==2'h3)?1'b1:1'b0,
(bayer_phase[1:0]==2'h2)?1'b1:1'b0,
(bayer_phase[1:0]==2'h1)?1'b1:1'b0,
(bayer_phase[1:0]==2'h0)?1'b1:1'b0};
end
if (!en) en_converters[4:0] <= 0;
else if (pre_first_pixel)
en_converters[4:0]<= {(converter_type[2:0]==3'h4)?1'b1:1'b0,
(converter_type[2:0]==3'h3)?1'b1:1'b0,
(converter_type[2:0]==3'h2)?1'b1:1'b0,
(converter_type[2:0]==3'h1)?1'b1:1'b0,
(converter_type[2:0]==3'h0)?1'b1:1'b0};
end
// new
//cs_pre_first_out
reg [3:0] accYen;
reg [1:0] accCen; // individual accumulator enable (includes clearing)
reg [3:0] accYfirst;
reg [1:0] accCfirst; // add to zero, instead of to acc @ acc*en
// reg [7:0] preAccY, preAccC; // registered data from color converters, matching acc selection latency
reg [8:0] preAccY, preAccC; // registered data from color converters, matching acc selection latency
// reg [13:0] accY0,accY1,accY2,accY3,accC0,accC1;
reg [14:0] accY0,accY1,accY2,accY3,accC0,accC1;
reg cs_first_out;
reg [5:0] accCntrY0,accCntrY1,accCntrY2,accCntrY3,accCntrC0,accCntrC1;
wire [3:0] pre_accYdone;
wire [1:0] pre_accCdone; // need to make sure that pre_accCdone do not happen with pre_accYdone
reg [3:0] accYrun;
reg [1:0] accCrun;
reg [3:0] accYdone;
// reg [1:0] accCdone;
reg accYdoneAny;
reg [1:0] avrY_wa, pre_avrY_wa;
reg avrC_wa, pre_avrC_wa;
reg avrPage_wa, pre_avrPage_wa;
reg avr_we;
// reg [7:0] avermem[0:15];
reg [8:0] avermem[0:15];
wire [3:0] avr_wa= {avrPage_wa,accYdoneAny?{1'b0,avrY_wa[1:0]}:{2'b10,avrC_wa}};
reg [3:0] avr_ra; // read address
// wire [7:0] avrY_di= avrY_wa[1] ? (avrY_wa[0]?accY3[13:6]:accY2[13:6]):(avrY_wa[0]?accY1[13:6]:accY0[13:6]);
wire [8:0] avrY_di= avrY_wa[1] ? (avrY_wa[0]?accY3[14:6]:accY2[14:6]):(avrY_wa[0]?accY1[14:6]:accY0[14:6]);
// wire [7:0] avrC_di= avrC_wa ?accC1[13:6]:accC0[13:6];
wire [8:0] avrC_di= avrC_wa ?accC1[14:6]:accC0[14:6];
// wire [7:0] avr = avermem[avr_ra[3:0]];
wire [8:0] avr = avermem[avr_ra[3:0]];
assign pre_accYdone[3:0] = {(accCntrY3[5:0]==6'h3e)?1'b1:1'b0,(accCntrY2[5:0]==6'h3e)?1'b1:1'b0,(accCntrY1[5:0]==6'h3e)?1'b1:1'b0,(accCntrY0[5:0]==6'h3e)?1'b1:1'b0} & accYen[3:0];
assign pre_accCdone[1:0] = { (accCntrC1[5:0]==6'h3e)?1'b1:1'b0,(accCntrC0[5:0]==6'h3e)?1'b1:1'b0} & accCen[1:0];
always @ (posedge clk) begin
cs_first_out<=cs_pre_first_out;
// if (ywe) preAccY[7:0] <= y_in[7:0];
if (ywe) preAccY[8:0] <= y_in[8:0];
// if (cwe) preAccC[7:0] <= c_in[7:0];
if (cwe) preAccC[8:0] <= c_in[8:0];
accYen[3:0] <= {4{en & ywe}} & {yaddrw[7] & yaddrw[6], yaddrw[7] & ~yaddrw[6],~ yaddrw[7] & yaddrw[6], ~yaddrw[7] & ~yaddrw[6]};
accCen[1:0] <= {2{en & cwe}} & {caddrw[6], ~caddrw[6]};
accYfirst[3:0] <= {4{cs_first_out}} | (accYfirst[3:0] & ~accYen[3:0]);
accCfirst[1:0] <= {2{cs_first_out}} | (accCfirst[1:0] & ~accCen[1:0]);
// accAllFirst <= cs_first_out || ( accAllFirst && !(|accYen[3:0] || |accCen[1:0])); // until the first starts
if (accYen[0]) accY0[14:0]<= (accYfirst[0]?15'h0:accY0[14:0]) + {{6{preAccY[8]}},preAccY[8:0]};
if (accYen[1]) accY1[14:0]<= (accYfirst[1]?15'h0:accY1[14:0]) + {{6{preAccY[8]}},preAccY[8:0]};
if (accYen[2]) accY2[14:0]<= (accYfirst[2]?15'h0:accY2[14:0]) + {{6{preAccY[8]}},preAccY[8:0]};
if (accYen[3]) accY3[14:0]<= (accYfirst[3]?15'h0:accY3[14:0]) + {{6{preAccY[8]}},preAccY[8:0]};
if (accCen[0]) accC0[14:0]<= (accCfirst[0]?15'h0:accC0[14:0]) + {{6{preAccC[8]}},preAccC[8:0]};
if (accCen[1]) accC1[14:0]<= (accCfirst[1]?15'h0:accC1[14:0]) + {{6{preAccC[8]}},preAccC[8:0]};
/*
if (accYen[0]) accCntrY0[5:0]<= (accYfirst[0]?6'h0:(accCntrY0[5:0]+1));
if (accYen[1]) accCntrY1[5:0]<= (accYfirst[1]?6'h0:(accCntrY1[5:0]+1));
if (accYen[2]) accCntrY2[5:0]<= (accYfirst[2]?6'h0:(accCntrY2[5:0]+1));
if (accYen[3]) accCntrY3[5:0]<= (accYfirst[3]?6'h0:(accCntrY3[5:0]+1));
if (accCen[0]) accCntrC0[5:0]<= (accCfirst[0]?6'h0:(accCntrC0[5:0]+1));
if (accCen[1]) accCntrC1[5:0]<= (accCfirst[1]?6'h0:(accCntrC1[5:0]+1));
*/
if (!en) accCntrY0[5:0]<= 6'h0; else if (accYen[0]) accCntrY0[5:0]<= (accYfirst[0]?6'h0:(accCntrY0[5:0]+1));
if (!en) accCntrY1[5:0]<= 6'h0; else if (accYen[1]) accCntrY1[5:0]<= (accYfirst[1]?6'h0:(accCntrY1[5:0]+1));
if (!en) accCntrY2[5:0]<= 6'h0; else if (accYen[2]) accCntrY2[5:0]<= (accYfirst[2]?6'h0:(accCntrY2[5:0]+1));
if (!en) accCntrY3[5:0]<= 6'h0; else if (accYen[3]) accCntrY3[5:0]<= (accYfirst[3]?6'h0:(accCntrY3[5:0]+1));
if (!en) accCntrC0[5:0]<= 6'h0; else if (accCen[0]) accCntrC0[5:0]<= (accCfirst[0]?6'h0:(accCntrC0[5:0]+1));
if (!en) accCntrC1[5:0]<= 6'h0; else if (accCen[1]) accCntrC1[5:0]<= (accCfirst[1]?6'h0:(accCntrC1[5:0]+1));
accYrun[3:0] <= {4{en}} & ((accYfirst[3:0] & accYen[3:0]) | (accYrun[3:0] & ~pre_accYdone[3:0]));
accCrun[1:0] <= {2{en}} & ((accCfirst[1:0] & accCen[1:0]) | (accCrun[1:0] & ~pre_accCdone[1:0]));
accYdone[3:0] <= pre_accYdone[3:0] & accYrun[3:0];
// accCdone[1:0] <= pre_accCdone[1:0] & accCrun[1:0];
accYdoneAny <= |(pre_accYdone[3:0] & accYrun[3:0]);
avr_we <= |(pre_accYdone[3:0] & accYrun[3:0]) || |(pre_accCdone[1:0] & accCrun[1:0]);
pre_avrY_wa[1:0] <= yaddrw[7:6];
avrY_wa[1:0] <= pre_avrY_wa[1:0];
pre_avrC_wa <= caddrw[ 6];
avrC_wa <= pre_avrC_wa;
pre_avrPage_wa <= wpage[0];
avrPage_wa <= pre_avrPage_wa;
// if (avr_we) avermem[avr_wa[3:0]] <= accYdoneAny?avrY_di[7:0]:avrC_di[7:0];
if (avr_we) avermem[avr_wa[3:0]] <= en_sdc?(accYdoneAny?avrY_di[8:0]:avrC_di[8:0]):9'h0;
avr_ra[3:0] <= {rpage[0],raddr[8:6]};
end
reg transfer_ended=0; /// there was already EOT pulse for the current frame
always @ (posedge clk) begin
transfer_ended <= bcntrIsZero && (transfer_ended || eot);
/*+*/ tim2next <= (seq_cntr[8:0]=='h10); // rather arbitrary number - sdram buffer should in no case be actually overwritten before data read out
// it may depend on relation between SDRAM clk frequency (75MHz) and this clk (variable? 30MHz)
// eof_rq <= (tim2next && !bcntrIsZero) || (eof_rq && !(inc_sdrama || noMoreData ||transfer_ended));
eof_rq <= (tim2next && !bcntrIsZero) || (eof_rq && !(inc_sdrama || transfer_ended));
// ccv_start_en <= en && (ccv_start_en || go); //NOTE: Just for simulation
ccv_start_en <= en && !eot && (ccv_start_en || go); //FIXME: Still uncaught problem: SDRAM ready occurs before go_single!
// bcntrIsZero <= (bcntr[17:0]==18'b0) || noMoreData;
bcntrIsZero <= (bcntr[17:0]==18'b0);
sdram_next <= tim2next && ~sdram_next;
// eot <= (tim2next && bcntrIsZero) || (eof_rq && noMoreData);
eot <= !transfer_ended && !eot && bcntrIsZero && (tim2next || (eof_rq && noMoreData));
if (go) bcntr[17:0] <= nblocks[17:0];
else if (noMoreData) bcntr[17:0] <= 18'b0;
else if (sdram_next && !bcntrIsZero) bcntr[17:0] <= bcntr[17:0]-1;
if (ccv_out_start) rpage[1:0] <=wpage[1:0];
if (ccv_out_start) color_enable <= pre_color_enable;
ccv_out_start_d <= ccv_out_start;
raddr_lastInBlock <= en && (raddr[5:0]==6'h3e);
raddr_updateBlock <= raddr_lastInBlock || ccv_out_start;
if (ccv_out_start || !en) raddr[8:0] <= {!en,!en,7'h0}; // 9'h180/9'h000;
else if (!raddr[8] || (!four_blocks_r && !raddr[7])) raddr[8:0] <= raddr[8:0]+1; // for 4 blocks - count for 0,1; 6 blocks - 0,1,2
dv0 <= en && raddr_updateBlock?(!raddr[8] || (!four_blocks_r && !raddr[7])):dv0;
ds0 <= raddr_updateBlock && (!raddr[8] || (!four_blocks_r && !raddr[7]));
buf_sel <= raddr[8];
// pre_do[8:0] <= (buf_sel?c_out[7:0]:y_out[7:0])-avr[7:0];
// pre_do[9:0] <= (buf_sel?{c_out[8],c_out[8:0]}:{y_out[8],y_out[8:0]})-{avr[8],avr[8:0]};
pre_do[9:0] <= buf_sel?(color_enable?({c_out[8],c_out[8:0]}-{avr[8],avr[8:0]}):10'b0):({y_out[8],y_out[8:0]}-{avr[8],avr[8:0]});
//color_enable
// do[8:0] <= pre_do[8:0];
do[9:0] <= pre_do[9:0];
dv_raw <= inc_sdrama && en;
if (go) willbe_first <= 1'b1;
else if (first_pixel) willbe_first <= 1'b0;
if (first_pixel) begin
first0 <= willbe_first;
last0 <= (bcntr[17:0] == 18'b0);
end
if (ccv_out_start) begin
first <= first0;
last <= last0;
end
// 8x8 memory to hold average values
// if (avm_we) avermem[avm_a[3:0]] <= avm_d[7:0];
pre_dv[1:0] <= {pre_dv[0],dv0};
pre_ds[1:0] <= {pre_ds[0],ds0};
// Shift registers - generating block attributes to be used later in compressor
if (raddr_updateBlock) begin
if (ccv_out_start_d) begin
component_numsL[5:0] <= component_numsLS[5:0];
component_numsM[5:0] <= component_numsMS[5:0];
component_numsH[5:0] <= component_numsHS[5:0];
component_colors[5:0] <= component_colorsS[5:0];
component_firsts[5:0] <= first0? component_firstsS[5:0]:6'h0; // here we may use first0 that is one cycle earlier and ends much earlier
end else begin
component_numsL[5:0] <= {1'b0,component_numsL[5:1]};
component_numsM[5:0] <= {1'b0,component_numsM[5:1]};
component_numsH[5:0] <= {1'b0,component_numsH[5:1]};
component_colors[5:0] <= {1'b0,component_colors[5:1]};
component_firsts[5:0] <= {1'b0,component_firsts[5:1]};
end
end
component_lastinmb <= tn[0] && (four_blocks_r? tn[1] : tn[2]); // last component in a macroblock;
end
// average for each block should be calculated before the data goes to output output
always @ (posedge clk) case (converter_type_r[2:0])
3'h0:begin //color 18
cs_pre_first_out <= conv18_pre_first_out;
y_in[8:0] <= {conv18_y_in[7],conv18_y_in[7:0]};
ywe <= conv18_ywe;
yaddrw[7:0] <= {conv18_yaddrw[7],conv18_yaddrw[3],conv18_yaddrw[6:4],conv18_yaddrw[2:0]};
c_in[8:0] <= {conv18_c_in[8:0]};
cwe <= conv18_cwe;
pre_color_enable <= 1'b1;
caddrw[7:0] <= {1'b0,conv18_caddrw[6:0]};
ccv_out_start <= (conv18_yaddrw[7:0]==8'hc5); //TODO: adjust to minimal latency?
component_numsLS <= 6'h10; // component_num [0]
component_numsMS <= 6'h20; // component_num [1]
component_numsHS <= 6'h00; // component_num [2]
component_colorsS <= 6'h30; // use color quantization table (YCbCR, jp4diff)
component_firstsS <= 6'h31; // first this component in a frame (DC absolute, otherwise - difference to previous)
end
3'h1:begin //color 20
cs_pre_first_out <= conv20_pre_first_out;
y_in[8:0] <= {conv20_y_in[7],conv20_y_in[7:0]};
ywe <= conv20_ywe;
yaddrw[7:0] <= {conv20_yaddrw[7],conv20_yaddrw[3],conv20_yaddrw[6:4],conv20_yaddrw[2:0]};
c_in[8:0] <= {conv20_c_in[8:0]};
cwe <= conv20_cwe;
pre_color_enable <= 1'b1;
caddrw[7:0] <= {1'b0,conv20_caddrw[6:0]};
ccv_out_start <= (conv20_yaddrw[7:0]==8'hc5); //TODO: adjust to minimal latency?
component_numsLS <= 6'h10; // component_num [0]
component_numsMS <= 6'h20; // component_num [1]
component_numsHS <= 6'h3f; // component_num [2]
component_colorsS <= 6'h30; // use color quantization table (YCbCR, jp4diff)
component_firstsS <= 6'h31; // first this component in a frame (DC absolute, otherwise - difference to previous)
end
3'h2:begin //mono
cs_pre_first_out <= mono_pre_first_out;
y_in[8:0] <= {mono_y_in[7],mono_y_in[7:0]};
ywe <= mono_ywe;
yaddrw[7:0] <= {mono_yaddrw[7],mono_yaddrw[3],mono_yaddrw[6:4],mono_yaddrw[2:0]};
c_in[8:0] <= 9'h0;
cwe <= 1'b0;
pre_color_enable <= 1'b0;
caddrw[7:0] <= 8'h0;
ccv_out_start <= accYdone[0];
component_numsLS <= 6'h10; // component_num [0]
component_numsMS <= 6'h20; // component_num [1]
component_numsHS <= 6'h30; // component_num [2]
component_colorsS <= 6'h30; // use color quantization table (YCbCR, jp4diff)
component_firstsS <= 6'h31; // first this component in a frame (DC absolute, otherwise - difference to previous)
end
3'h3:begin // jp4
cs_pre_first_out <= jp4_pre_first_out;
y_in[8:0] <= {jp4_y_in[7],jp4_y_in[7:0]};
ywe <= jp4_ywe;
yaddrw[7:0] <= {jp4_yaddrw[7],jp4_yaddrw[3],jp4_yaddrw[6:4],jp4_yaddrw[2:0]};
c_in[8:0] <= 9'h0;
cwe <= 1'b0;
pre_color_enable <= 1'b0;
caddrw[7:0] <= 8'h0;
ccv_out_start <= accYdone[0];
component_numsLS <= jp4_dc_improved_r?6'h0a:6'h10; // LSb of component_num
component_numsMS <= jp4_dc_improved_r?6'h0c:6'h20; // MSb of component_num
component_numsHS <= 6'h30; // component_num [2]
component_colorsS <= 6'h30; // use color quantization table (YCbCR, jp4diff)
component_firstsS <= jp4_dc_improved_r?6'h3f:6'h31; // first this component in a frame (DC absolute, otherwise - difference to previous)
end
3'h4:begin //jp4diff
cs_pre_first_out <= jp4diff_pre_first_out;
y_in[8:0] <= {jp4diff_y_in[8:0]};
ywe <= jp4diff_ywe;
yaddrw[7:0] <= {jp4diff_yaddrw[7],jp4diff_yaddrw[3],jp4diff_yaddrw[6:4],jp4diff_yaddrw[2:0]};
c_in[8:0] <= 9'h0;
cwe <= 1'b0;
pre_color_enable <= 1'b0;
caddrw[7:0] <= 8'h0;
ccv_out_start <= accYdone[0];
component_numsLS <= 6'h0a; // LSb of component_num
component_numsMS <= 6'h0c; // MSb of component_num
component_numsHS <= 6'h30; // component_num [2]
component_colorsS <= {2'h3,~bayer_phase_onehot[3:0] | (hdr_r? {~bayer_phase_onehot[1:0],~bayer_phase_onehot[3:2]} : 4'h0)}; // use color quantization table (YCbCR, jp4diff)
component_firstsS <= 6'h3f; // first this component in a frame (DC absolute, otherwise - difference to previous)
end
endcase
wire limit_diff=1'b1;
csconvert18 i_csconvert18 (.RST(!en_converters[0]),
.CLK(clk),
.mono(ignore_color_r),
.limit_diff(limit_diff), // 1 - limit color outputs to -128/+127 range, 0 - let them be limited downstream
.m_cb(m_cb[9:0]), // [9:0] scale for CB - default 0.564 (10'h90)
.m_cr(m_cr[9:0]), // [9:0] scale for CB - default 0.713 (10'hb6)
.din(di[7:0]),
.pre_first_in(first_pixel),
.signed_y(conv18_y_in[7:0]),
.q(conv18_c_in[8:0]),
.yaddr(conv18_yaddrw[7:0]), //
.ywe(conv18_ywe),
.caddr(conv18_caddrw[6:0]),
.cwe(conv18_cwe),
.pre_first_out(conv18_pre_first_out),
.bayer_phase(bayer_phase_r[1:0]),
.n000(n000[7:0]), // TODO:remove ?
.n255(n255[7:0]));
csconvert_mono i_csconvert_mono (
.en(en_converters[2]),
.clk(clk),
.din(di[7:0]),
.pre_first_in(first_pixel),
.y_out (mono_y_in[7:0]),
.yaddr (mono_yaddrw[7:0]),
.ywe (mono_ywe),
.pre_first_out(mono_pre_first_out));
csconvert_jp4 i_csconvert_jp4 (
.en(en_converters[3]),
.clk(clk),
.din(di[7:0]),
.pre_first_in(first_pixel),
.y_out (jp4_y_in[7:0]),
.yaddr (jp4_yaddrw[7:0]),
.ywe (jp4_ywe),
.pre_first_out(jp4_pre_first_out));
csconvert_jp4diff i_csconvert_jp4diff (
.en(en_converters[4]),
.clk(clk),
.scale_diff(scale_diff_r),
.hdr(hdr_r),
.din(di[7:0]),
.pre_first_in(first_pixel),
.y_out (jp4diff_y_in[8:0]),
.yaddr (jp4diff_yaddrw[7:0]),
.ywe (jp4diff_ywe),
.pre_first_out(jp4diff_pre_first_out),
.bayer_phase(bayer_phase_r[1:0]));
//TODO: temporary plugs, until module is cretaed
// will be wrong, of course
assign conv20_y_in[7:0]= conv18_y_in[7:0];
assign conv20_yaddrw[7:0]= conv18_yaddrw[7:0];
assign conv20_ywe= conv18_ywe;
assign conv20_c_in[8:0]= conv18_c_in[8:0];
assign conv20_caddrw[6:0]= conv18_caddrw[6:0];
assign conv20_cwe= conv18_cwe;
assign conv20_pre_first_out= conv18_pre_first_out;
// currently only 8 bits are used in the memories
RAMB16_S9_S9 i_y_buff (
.DOA(), // Port A 8-bit Data Output
.DOPA(), // Port A 8-bit Parity Output
.ADDRA({1'b0,wpage[1:0],yaddrw[7:0]}), // Port A 11-bit Address Input
.CLKA(clk), // Port A Clock
.DIA(y_in[7:0]), // Port A 8-bit Data Input
.DIPA(y_in[8]), // Port A 1-bit parity Input
.ENA(ywe), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(1'b1), // Port A Write Enable Input
.DOB(y_out[7:0]), // Port B 8-bit Data Output
.DOPB(y_out[8]), // Port B 1-bit Parity Output
.ADDRB({1'b0,rpage[1:0],raddr[7:0]}), // Port B 11-bit Address Input
.CLKB(clk), // Port B Clock
.DIB(8'h0), // Port B 8-bit Data Input
.DIPB(1'h0), // Port-B 1-bit parity Input
.ENB(!raddr[8]), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(1'b0) // Port B Write Enable Input
);
RAMB16_S9_S9 i_CrCb_buff (
.DOA(), // Port A 8-bit Data Output
.DOPA(), // Port A 8-bit Parity Output
.ADDRA({1'b0,wpage[1:0],caddrw[7:0]}), // Port A 11-bit Address Input
.CLKA(clk), // Port A Clock
.DIA(c_in[7:0]), // Port A 8-bit Data Input
.DIPA(c_in[8]), // Port A 1-bit parity Input
.ENA(cwe), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(1'b1), // Port A Write Enable Input
.DOB(c_out[7:0]), // Port B 8-bit Data Output
.DOPB(c_out[8]), // Port B 1-bit Parity Output
.ADDRB({1'b0,rpage[1:0],raddr[7:0]}), // Port B 11-bit Address Input
.CLKB(clk), // Port B Clock
.DIB(8'h0), // Port B 8-bit Data Input
.DIPB(1'h0), // Port-B 1-bit parity Input
.ENB(raddr[8]), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(1'b0) // Port B Write Enable Input
);
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/compressor333.v 0000664 0000000 0000000 00000205434 12555570767 0024270 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** compressor333.v
**
** Top level module for JPEG compressor part of FPGA
**
** Copyright (C) 2002-2010 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X333
** X333 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
`timescale 1ns/1ps
`define debug_compressor
module compressor(// cwr, // CPU write - global clock
clk, // compressor pixel clock.(80MHz)
clk2x, // twice clk, used for huffman/stuffer stages. leading front should be before clk leading front (160MHz)
cwe, // we to compressor from CPU (now @ negedge clk) - only command register and number of MCUs
wr_saturation, // write color saturation vaues
// (currently 10 bits - cb from idi[9:0],
// cr - from idi[21:12]
wr_quantizer_mode, // Quantizer tuning - Coring table pair number (0..7)
rs, // 0 - bit modes,
// 1 - number of MCUs
twqe, // quantization table write enable
twce, // coring functions tables (@negedge clk - addr and data valid this cycle and one before)
twhe, // huffamn table write enable
twfe, // table to be multiplied by DCT coefficients (then squared and accumulated)
// to determine focus sharpness
ta, // [8:0] addresses words in tables (quantization and huffman)
di, // [31:0] data from CPU
vacts_long, // long vacts pulse (15 scan lines) to delay comprssor start (@pixel clock, need re-sync)
eot, // ( to interrupts?) pulse while processing the last MCU in a frame - predictable time to end of DMA transfer
// SDRAM interface
done_input, // will go high after EOT and persist until DCT is enabled
done_compress, // will go high after all data is sent out
done_compress_pulse, // Does not need to be reset
compressor_started, // single sclk compressor started
is_compressing, // @posedge clk, from go_single to eot (actual or simulated)
chInitOnehot2, // decoded channel init pulses, 2 cycles behind chInit (to reset page address)
nextBlocksEn, // When combined with SDRAM data ready, may be used to end frame compression input (instead of block counter)
pxd, // [7:0] data from SDRAM organized as 18x18x8bit MCUs+overlapping margins
pxa, // [10:0] - address to SDRAM buffer (2 MSBs - page. Starts with 0)
pxrdy, // SDRAM buffer (channel 2) has a page ready
nxtpage,// read next page to SDRAM buffer (from SDRAM)
inc_sdrama, //enable read from SDRAM buffer
confirmFrame2Compressor, // (re) enable reading SDRAM to channel 2 FIFO (it stops after each frame over and after channel init)
restart_memory, // restart memory channel (to align after broken frames) - masked by enable bit in memory controller
bonded, // channel bonded with the other (just for channel 2), make it TIG
bayer_phase,// [1:0] bayer color filter phase 0:(GR/BG), 1:(RG/GB), 2: (BG/GR), 3: (GB/RG)
// Reusing channel 3 for DC components output (****** currently disconnected ******)
dccout, //enable output of DC and HF components for brightness/color/focus adjustments
hfc_sel, // [2:0] (for autofocus) only components with both spacial frequencies higher than specified will be added
statistics_dv, //sclk
statistics_do,//[15:0] sclk
// start of frame time (set at first HACT after first VACT)
sec, // [31:0] number of seconds
usec, // [19:0] number of microseconds
q,
qv,
imgptr, // [23:0]image pointer in 32-byte chunks
hifreq //[31:0]) // accumulated high frequency components in a frame sub-window
,dma_is_reset // DMA module is reset, enable resetting data counters
,test_state // {is_compressing, cmprs_repeat,cmprs_en}
`ifdef debug_compressor
,test_cntr0 // [31:0] just for testing
`endif
`ifdef debug_stuffer
,tst_stuf_negedge, // [3:0] just for testing
tst_stuf_posedge, // [3:0] just for testing
tst_stuf_etrax, // [3:0] just for testing
test_cntr, // [3:0] just for testing
test_cntr1 // [3:0] just for testing
`endif
);
input clk;
input clk2x;
input cwe;
input wr_saturation;
input wr_quantizer_mode;
input rs;
input twqe;
input twce;
input twhe;
input twfe;
// input [11:0] ta;
input [ 9:0] ta;
input [15:0] di;
input vacts_long; // long vacts pulse (15 scan lines) to delay comprssor start (@pixel clock, need re-sync)
output eot;
output done_input; // will go high after EOT and persist until DCT is enabled
output done_compress; // will go high after all data is sent out
output done_compress_pulse; // Does not need to be reset
output compressor_started;
output is_compressing;
input chInitOnehot2; // @negedge clk2x
input nextBlocksEn; // (@negedge clk2x) When combined with SDRAM data ready, may be used to end frame compression input (instead of block counter)
input [ 7:0] pxd;
output [10:0] pxa;
input pxrdy;
output nxtpage;
output inc_sdrama;
output confirmFrame2Compressor;
output restart_memory; // restart memory channel (to align after broken frames) - masked by enable bit in memory controller
input bonded; // channel bonded with the other (just for channel 2), make it TIG
input [ 1:0] bayer_phase;
input dccout;
input [2:0] hfc_sel;
output statistics_dv;
output [15:0] statistics_do;
input [31:0] sec;
input [19:0] usec;
output [15:0] q;
output qv;
output [23:0] imgptr;
output [31:0] hifreq;
input dma_is_reset; // DMA module is reset, enable resetting data counters
output [ 2:0] test_state; // {is_compressing, cmprs_repeat,cmprs_en}
// wire is_compressing; // from go_single to eot (@posedge clk)
`ifdef debug_compressor
output [31:0] test_cntr0;
`endif
`ifdef debug_stuffer
output [3:0] tst_stuf_negedge;
output [3:0] tst_stuf_posedge;
output [3:0] tst_stuf_etrax;
output [3:0] test_cntr;
output [7:0] test_cntr1;
`endif
wire [ 9:0] m_cb; // variable Cb coefficient (was 'h90 constant)
wire [ 9:0] m_cr; // variable Cr coefficient (was 'hb6 constant)
reg [15:0] stuffer_do_p;
reg stuffer_dv_p;
wire [15:0] q;
wire qv;
wire [ 1:0] bayer_phase;
wire [7:0] n000; // number of zero pixels (255 if 256) in a 16x16 tile (overlap ignored,before color conversion)
wire [7:0] n255; // number of 0xff pixels (255 if 256) in a 16x16 tile (overlap ignored,before color conversion)
wire [15:0] dccdata;
reg finish_dcc;
wire dccvld;
wire dccout;
reg dcc_en;
wire eot;
wire eot_real;
wire nxtpage;
//TODO: move focus control outside,
// add second bit to scaling differences (not just 0.5 and 1.0, but also 0.75 - probably most reasonable)
//================NOTE: After memory controller is reprogrammed, compressor should be reset (reset+restarted) - else buffer pages would mismatch (seen that) =============================
// wire [ 8:0] ta; // now inputs
// wire twqe;
// wire twhe;
// new control bits:
// [23] ==1 - set focus mode
// [22:21] 0 - none
// 1 - replace
// 2 - combine for all image
// 3 - combine in window only
// [20] ==1 - set bayer shift (from the gammas)
// [19:18] - bayer shift value (from the gammas)
// [17] == 1 - set processed tile position in the 20x20 tile got from memory
// [16:14] 0 - top left alignment
// 1 - 1 pixel right and 1 - down from the top left alignment
// 2 - 2 pixels right and 2 - down from the top left alignment
// 3 - 3 pixels right and 3 - down from the top left alignment
// 4 - 4 pixels right and 4 - down from the top left alignment
// [13]==1 - enable color modes
// [12:9]== 0 - monochrome, (4:2:0),
// 1 - color, 4:2:0, 18x18(old)
// 2 - jp4, original (4:2:0),
// 3 - jp4, dc -improved (4:2:0),
// 4 - color, 4:2:0, 20x20, middle of the tile (not yet implemented)
// 5 - jp4, 4 blocks, (legacy)
// 6 - jp4, 4 blocks, dc -improved
// 7 - jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
// 8 - jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
// 9 - jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
// 10 - jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2),
// 11-13 - reserved
// 14 - mono, 4 blocks
// 15 - reserved
// [8:7] == 0,1 - NOP, 2 - disable, 3 - enable subtracting of average value (DC component), bypassing DCT
// [6] == 1 - enable quantization bank select, 0 - disregard bits [5:3]
// [5:3] = quantization page number (0..7)
// [2]== 1 - enable on/off control:
// [1:0]== 0 - reset compressor, stop immediately
// 1 - enable compressor, disable repetitive mode
// 2 - enable compressor, compress single frame
// 3 - enable compressor, enable repetitive mode
//
// control registetr bits
wire cr_w; // data written to cr (1 cycle) - now just to reset legacy IRQ
wire raw_dv; // input pixel data valid (pxd[7:0]may be sent to DMA buffer through multiplexor) // SuppressThisWarning Veditor UNUSED
wire color_dv; // unused // color data valid (color_d[7:0] may be sent to DMA buffer through multiplexor)// SuppressThisWarning Veditor UNUSED
wire [ 9:0] color_d; // data out stream from color space converter (6X64 blocks for each MCU - 4Y, Cb,Cr)
wire [ 2:0] color_tn; // tile number in an MCU from color space converter (valid @ color_dv)
wire [ 8:0] color_avr; // [8:0] DC (average value) 9 bit signed for Y: 9'h000..9'h0ff, for C - 9h100..9'h000..9'h0ff
wire color_first; // sending first MCU (valid @ ds)
wire color_last; // sending last MCU (valid @ ds)
// wire dct_en;
wire dct_start;
wire dct_dv; // SuppressThisWarning Veditor UNUSED
wire [12:0] dct_out;
wire dct_last_in; // output high during input of the last of 64 pixels in a 8x8 block
wire dct_pre_first_out; // 1 cycle ahead of the first output in a 64 block
wire [17:0] ntiles; //number of 16x16 MCU tiles in a frame to process
reg quant_start;
wire [12:0] quant_do;
// wire quant_dv;
wire quant_ds;
//usefocus
wire [12:0] focus_do;
wire focus_ds;
// wire enc_first;
wire enc_last; // SuppressThisWarning Veditor UNUSED
wire [15:0] enc_do;
wire enc_dv;
wire [15:0] huff_do;
wire [ 3:0] huff_dl;
wire huff_dv;
wire flush; // flush stuffer
wire stuffer_rdy;
//assign stuffer_rdy=1'b1;
wire [15:0] stuffer_do;
wire stuffer_dv;
wire stuffer_done;
reg stuffer_done_persist;
reg done_input; // will go high after EOT and persist until DCT is enabled
reg done_compress; // will go high after all data is sent out
reg [1:0] stuffer_done_sync;
reg done_compress_pulse;
reg [1:0] compressor_starting;
reg compressor_started; // sync @(negedge clk2x)
// interclock sync
reg cmprs_en_2x_n; // enable DCT (0- resets buffer pages) - negedge, earlier than
// reg cmprs_en_2x_p; // enable DCT (0- resets buffer pages) - posedge
reg cr_w_2x_n; // 2 cycles long
// reg cr_w_2x_p; // 2 cycles long
reg wr_saturation_d; //wr_saturation next
// reg wr_quantizer_mode_d;
reg pre_finish_dcc;
// reg [1:0] vlong;
reg vlong;
reg vlong1_or_not_bonded;
reg not_vlong1_or_not_bonded;
// reg go_dly;
reg go_rq; // request for "go" pulse (will wait for the end of vlong[1] if started during that time
reg go_single; // single pulse to start/restart compressor (not in the vacts_long interval)
wire confirmFrame2Compressor;
wire is_compressing; // from go_single to eot (@posedge clk)
wire is_compressing_d; // delayed by several cycles (8) to overlap possible abort_compress_clk;
wire force_flush; // force flush - abort compressing (when writing tiles during is_compressing)
// single cycle @ negedge clk2x
reg abort_compress; //from force_flush till stuffer_done @negedge clk2x
reg [1:0] abort_compress_clk; // sync to posedge clk - at the end will be simulated
reg force_eot;
wire [2:0] memWasInit; // syncronizing chInitOnehot2 to clk so buffer page may be reset
wire cmprs_en;
wire cmprs_start;
wire cmprs_repeat;
wire [ 2:0] cmprs_qpage;
wire cmprs_dcsub;
wire [ 3:0] cmprs_mode;
wire [ 1:0] cmprs_fmode;
wire [ 2:0] tile_shift;
// signals synchronized to start of frame compress
reg [ 2:0] cmprs_qpage_this;
reg cmprs_dcsub_this;
// reg [ 3:0] cmprs_mode_this;
reg [ 1:0] cmprs_fmode_this;
reg [ 2:0] tile_shift_this;
reg [ 1:0] cmprs_bayer_this;
wire pre_go_single;
reg ignore_color; // ignore color information
reg four_blocks;
reg jp4_dc_improved;
reg [ 1:0] tile_margin;
reg [ 2:0] converter_type; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff , 5 jp4-diff, divide diffs by 2
wire [1:0] bayer_shift;
wire [2:0] component_num; //[1:0] - component number (YCbCr: 0 - Y, 1 - Cb, 2 - Cr, JP4: 0-1-2-3 in sequence (depends on shift)
wire component_color; // use color quantization table (YCbCR, jp4diff)
wire component_first; // first this component in a frame (DC absolute, otherwise - difference to previous)
wire component_lastinmb; // last component in a macroblock;
reg scale_diff;
reg hdr;
reg confirm_en;
reg confirm;
wire restart_memory;
reg noMoreData_en=0; // enable noMoreData (to delay noMoreData, preventing it from the previous frame)
reg noMoreData; // used as alternative to end frame input (possibly broken frame)
reg [ 1:0] nextBlocksEnS; // re-sync to clock
assign test_state={is_compressing,cmprs_repeat,cmprs_en};
// input dma_is_reset; // DMA module is reset, enable resetting data counters
reg [1:0] reset_data_counters;
always @ (negedge clk2x) begin
reset_data_counters[1:0] <={reset_data_counters[0], dma_is_reset && !cmprs_en_2x_n};
end
assign eot=eot_real || force_eot; // force_eot during abort compress
// input dma_is_reset; // DMA module is reset, enable resetting data counters
// assign finish_dcc=stuffer_done;
assign q[15:0]= stuffer_do_p[15:0];
assign qv= stuffer_dv_p;
// assign pre_go_single= cmprs_en && go_rq && !vlong[1] && !is_compressing && !go_single;
assign pre_go_single= cmprs_en &&
go_rq &&
// !vlong[1] &&
not_vlong1_or_not_bonded &&
!is_compressing &&
!is_compressing_d &&
!abort_compress_clk[1] &&
!go_single;
always @ (posedge clk) begin
confirm_en <= cmprs_en;
// confirm <= confirm_en && (go_single || (confirm && !inc_sdrama));
confirm <= confirm_en && (go_single || // confirm memory so it can start reading new frame
// memWasInit[2] || // re-confirm memory if it was reset
// (confirm && !inc_sdrama));
(confirm && !nxtpage)); // until the next block is requestedfrom SDRAM
nextBlocksEnS[1:0] <= {nextBlocksEnS[0], nextBlocksEn};
noMoreData_en <= cmprs_en && (nxtpage || (noMoreData_en && !go_single));
/// noMoreData <= noMoreData_en && confirm_en && !confirm && !nextBlocksEnS[1] && !nextBlocksEnS[0] && !pxrdy;
// noMoreData <= confirm_en && !confirm && !nextBlocksEnS[1] && !nextBlocksEnS[0] && !pxrdy;
// noMoreData <= confirm_en && !confirm && !nextBlocksEnS[1] && !nextBlocksEnS[0] && !pxrdy && !go_rq;
noMoreData <= confirm_en &&
!confirm &&
!nextBlocksEnS[1] && !nextBlocksEnS[0] &&
!pxrdy &&
(!go_rq || is_compressing); // prevent noMoreData when just starting, but not when could not finish (too high fps)
end
reg bonded_sync;
always @ (posedge clk) bonded_sync <= bonded; // TIG
/// assign confirmFrame2Compressor= go_rq;
assign confirmFrame2Compressor= confirm;
assign restart_memory=go_single;
//restart_memory
/// synchronizing chInitOnehot2 from negedge clk2x to posedge clk
FDCE_1 i_memWasInit0 (.C(clk2x),.CE(chInitOnehot2),.CLR(memWasInit[2]), .D(1'b1), .Q(memWasInit[0]));
FD i_memWasInit1 (.C(clk), .D(memWasInit[0]), .Q(memWasInit[1]));
FD i_memWasInit2 (.C(clk), .D(memWasInit[1] & !memWasInit[2]),.Q(memWasInit[2]));
//TODO: add longer delay between frames to make sure they will not get corruped because of the trailer?
FD i_is_compressing (.Q(is_compressing),.C(clk), .D(cmprs_en && (go_single || (is_compressing && !eot)) ));
// SRL16 i_is_compressing_d(.Q(is_compressing_d),.D(is_compressing_d), .CLK(clk), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b0)); // dly=7+1
SRL16 i_is_compressing_d(.Q(is_compressing_d),.D(is_compressing), .CLK(clk), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b0)); // dly=7+1
always @ (negedge clk2x) begin
abort_compress <= cmprs_en_2x_n && (force_flush || (abort_compress && !stuffer_done));
end
always @ (posedge clk) begin
abort_compress_clk[1:0] <= {abort_compress_clk[0],abort_compress};
force_eot <= abort_compress_clk[0] && !abort_compress_clk[1];
end
always @ (posedge clk) begin // any write to cr will reset done
// vlong[1:0] <= {vlong[0],vacts_long}; // dual sync
vlong <= vacts_long; // dual sync
vlong1_or_not_bonded <= vlong || !bonded_sync;
not_vlong1_or_not_bonded <= !vlong || !bonded_sync;
// go_rq <= cmprs_en && (cmprs_start || (cmprs_repeat && vlong[1]) || (go_rq && !go_single));
go_rq <= cmprs_en && (cmprs_start || (cmprs_repeat && vlong1_or_not_bonded) || (go_rq && !go_single));
go_single <= pre_go_single;
if (pre_go_single) begin
cmprs_qpage_this[2:0]<=cmprs_qpage[2:0];
cmprs_dcsub_this <=cmprs_dcsub;
// cmprs_mode_this[3:0] <=cmprs_mode[3:0];
cmprs_fmode_this[1:0]<=cmprs_fmode[1:0];
tile_shift_this[2:0]<= tile_shift[2:0];
// will inctanciate ROM
case (cmprs_mode[3:0])
4'h0: begin //monochrome, (4:2:0),
ignore_color <= 1;
four_blocks <= 0;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 2; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=0;
hdr <=0;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{tile_shift[0]}};
end
4'h1: begin //color, 4:2:0, 18x18(old)
ignore_color <= 0;
four_blocks <= 0;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 1;
converter_type[2:0] <= 0; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=0;
hdr <=0;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{tile_shift[0]}};
end
4'h2: begin // jp4, original (4:2:0),
ignore_color <= 1;
four_blocks <= 0;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 3; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=0;
hdr <=0;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{tile_shift[0]}};
end
4'h3: begin // jp4, dc -improved (4:2:0),
ignore_color <= 1;
four_blocks <= 0;
jp4_dc_improved <= 1;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 3; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=0;
hdr <=0;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{tile_shift[0]}};
end
4'h4: begin // color, 4:2:0, 20x20, middle of the tile (not yet implemented)
ignore_color <= 0;
four_blocks <= 0;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 2;
converter_type[2:0] <= 1; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=0;
hdr <=0;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{~tile_shift[0]}};
end
4'h5: begin // jp4, 4 blocks, (legacy)
ignore_color <= 1;
four_blocks <= 1;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 3; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=0;
hdr <=0;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{~tile_shift[0]}};
end
4'h6: begin // jp4, 4 blocks, dc -improved
ignore_color <= 1;
four_blocks <= 1;
jp4_dc_improved <= 1;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 3; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=0;
hdr <=0;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{~tile_shift[0]}};
end
4'h7: begin // jp4, 4 blocks, differential
ignore_color <= 1;
four_blocks <= 1;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 4; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=0;
hdr <=0;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{~tile_shift[0]}};
end
4'h8: begin // jp4, 4 blocks, differential, hdr
ignore_color <= 1;
four_blocks <= 1;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 4; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=0;
hdr <=1;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{~tile_shift[0]}};
end
4'h9: begin // jp4, 4 blocks, differential, divide diff by 2
ignore_color <= 1;
four_blocks <= 1;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 4; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=1;
hdr <=0;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{~tile_shift[0]}};
end
4'ha: begin // jp4, 4 blocks, differential, hdr, divide diff by 2
ignore_color <= 1;
four_blocks <= 1;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 4; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
scale_diff <=1;
hdr <=1;
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{~tile_shift[0]}};
end
4'he: begin // mono, 4 blocks
ignore_color <= 1;
four_blocks <= 1;
jp4_dc_improved <= 0;
tile_margin[1:0] <= 0;
converter_type[2:0] <= 2; // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
cmprs_bayer_this[1:0] <= (bayer_phase[1:0]+bayer_shift[1:0]) ^ {2{~tile_shift[0]}};
end
endcase
end
end
// [12:9]== 0 - color, 4:2:0
// 1 - monochrome, (4:2:0),
// 2 - jp4, original (4:2:0),
// 3 - jp4, dc -improved (4:2:0),
// 4 - color, 4:2:0, 20x20, middle of the tile (not yet implemented)
// 5 - jp4, 4 blocks, (legacy)
// 6 - jp4, 4 blocks, dc -improved
// 7 - jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
// 8 - jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
// 9 - jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
// 10 - jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2),
// 11-13 - reserved
// 14 - mono, 4 blocks
// 15 - reserved
always @ (negedge clk2x) begin
cmprs_en_2x_n <= cmprs_en;
cr_w_2x_n <= cr_w;
end
always @ (posedge clk2x) begin
// cmprs_en_2x_p <= cmprs_en_2x_n;
// cr_w_2x_p <= cr_w_2x_n;
end
always @ (negedge clk2x) begin // any write to cr will reset done
stuffer_done_persist <= !cr_w_2x_n && cmprs_en_2x_n && (stuffer_done_persist || stuffer_done );
done_compress <= !cr_w_2x_n && cmprs_en_2x_n && (done_compress || stuffer_done_persist);
stuffer_done_sync[1:0] <= {stuffer_done_sync[0],stuffer_done};
done_compress_pulse <= stuffer_done_sync[0] && !stuffer_done_sync[1];
compressor_starting[1:0] <= {compressor_starting[0],color_first & dct_start};
compressor_started <= (color_tn[2:0]==3'h0) &&compressor_starting[0] && !compressor_starting[1]; // sync @(negedge clk2x)
end
always @ (posedge clk) begin // any write to cr will reset done
done_input <= !cr_w && cmprs_en && (done_input || eot);
end
always @ (posedge clk2x) begin
stuffer_do_p[15:0] <= stuffer_do[15:0];
stuffer_dv_p <= stuffer_dv;
end
wire stuffer_flushing;
`ifdef debug_stuffer
//testing
reg [3:0] tst_stuf_negedge, tst_stuf_posedge;
reg tst_enc_dv_r;
// always @ (negedge clk2x) begin // any write to cr will reset done
// cmprs_en_2x_n
/*if (!cmprs_en_2x_n) tst_stuf_negedge <=0;
else*/ //if (stuffer_dv) tst_stuf_negedge <= tst_stuf_negedge+1;
// end
// always @ (posedge clk2x) begin // any write to cr will reset done
/*if (!cmprs_en) tst_stuf_posedge <=0;
else*/ //if (stuffer_dv_p) tst_stuf_posedge <= tst_stuf_posedge+1;
// end
always @ (negedge clk2x) begin
tst_enc_dv_r <= enc_dv;
if (stuffer_done) tst_stuf_negedge <=0;
else if (tst_enc_dv_r) tst_stuf_negedge <= tst_stuf_negedge+1; // twice per
end
always @ (posedge clk) begin // any write to cr will reset done
// if (stuffer_done) tst_stuf_negedge <=0;
// else if (enc_dv) tst_stuf_negedge <= tst_stuf_negedge+1;
if (go_single) tst_stuf_posedge <= 0;
else if (enc_dv) tst_stuf_posedge <= tst_stuf_posedge+1;
end
`endif
always @ (negedge clk2x) pre_finish_dcc <= stuffer_done;
always @ (posedge clk2x) finish_dcc <= pre_finish_dcc; //stuffer+done - @negedge clk2x
//propagation of first block through compressor pipeline
wire first_block_color=(color_tn[2:0]==3'h0) && color_first; // while color conversion,
reg first_block_color_after; // after color conversion,
reg first_block_dct; // after DCT
wire first_block_quant; // after quantizer
always @ (posedge clk) begin
if (dct_start) first_block_color_after <= first_block_color;
if (dct_last_in) first_block_dct <= first_block_color_after;
end
compr_ifc i_compr_ifc (.clk(clk), // pixel clock (80MHz)
.sclk(clk2x), // system clock (160MHz)
.cwe(cwe), // we to compressor from CPU (sync to negedge sclk)
.rs(rs), // register select:
// 0 - bit modes,
// 1 - write ntiles;
.di(di[15:0]), // [15:0] data from CPU
.cr_w(cr_w), // data written to cr (1 cycle long)
.ntiles(ntiles[17:0]),// - number of 16x16 MCU tiles in a frame to process
.cmprs_en(cmprs_en), // enable compressor
.cmprs_start(cmprs_start), // single cycle when single or constant compression is turned on
.cmprs_repeat(cmprs_repeat),// high in repetitive mode
.cmprs_qpage(cmprs_qpage), // [2:0] - quantizator page number (0..7)
.cmprs_dcsub(cmprs_dcsub), // subtract dc level before DCT, restore later
.cmprs_mode(cmprs_mode), // [3:0] - compressor mode
.cmprs_shift(tile_shift[2:0]), // tile shift from top left corner
.cmprs_fmode(cmprs_fmode), //[1:0] - focus mode
.bayer_shift(bayer_shift), // additional shift to bayer mosaic
.is_compressing(is_compressing), // high from start of compressing till EOT (sync to posedge clk)
.abort_compress(abort_compress),
.force_flush(force_flush)); // abort compress - generate flush pulse, force end of image over DMA, update counter
// single-cycle @ negedge sclk
`ifdef debug_compressor
wire debug_bcntrIsZero;
wire [17:0] debug_bcntr; //SuppressThisWarning Veditor UNUSED
`endif
color_proc i_color_proc(.clk(clk), // pixel clock 37.5MHz
.en(cmprs_en), // Enable (0 will reset states)
.en_sdc(cmprs_dcsub_this), // enable subtracting of DC component
.go(go_single), // now - always single-cycle pulse (TODO: simplify color_proc)
.nblocks(ntiles[17:0]),// [15:0] number of 16x16 blocks to read (valid @ "go" pulse only)
.eot(eot_real), // single-cycle end of transfer pulse
.m_cb(m_cb[9:0]), // [9:0] scale for CB - default 0.564 (10'h90)
.m_cr(m_cr[9:0]), // [9:0] scale for CB - default 0.713 (10'hb6)
.ignore_color(ignore_color), //zero Cb/Cr components
.four_blocks(four_blocks), // use only 6 blocks for the output, not 6
.jp4_dc_improved(jp4_dc_improved), // in JP4 mode, compare DC coefficients to the same color ones
.tile_margin(tile_margin[1:0]), // margins around 16x16 tiles (0/1/2)
.tile_shift(tile_shift_this[2:0]), // tile shift from top left corner
.converter_type(converter_type[2:0]), // 0 - color18, 1 - color20, 2 - mono, 3 - jp4, 4 - jp4-diff
.scale_diff(scale_diff), // divide differences by 2 (to fit in 8-bit range)
.hdr(hdr), // second green absolute, not difference
.memWasInit(memWasInit[2]), // memory channel2 was just initialized - reset page address
.di(pxd[7:0]), // [7:0]
.sdram_a(pxa[10:0]), // [10:0] (2 MSBs - SDRAM buffer page number)
.sdram_rdy(pxrdy), // SDRAM buffer ready
.sdram_next(nxtpage), // request to read a page to SDRAM buffer
.inc_sdrama(inc_sdrama), // enable read sdram buffer
.noMoreData(noMoreData), // used as alternative to end frame input (possibly broken frame)
.dv_raw(raw_dv), // data valid for di (for testing to bypass color conversion - use di[7:0])
// .do(color_d[8:0]), // [9:0] data out (4:2:0) (signed, average=0)
.do(color_d[9:0]), // [9:0] data out (4:2:0)
.avr(color_avr[8:0]), // [8:0] DC (average value) - RAM output, no register. For Y components 9'h000..9'h0ff, for C - 9'h100..9'h0ff
.dv(color_dv), // out data valid (will go high for at least 64 cycles)
.ds(dct_start), // single-cycle mark of the first pixel in a 64 (8x8) - pixel block
.tn(color_tn[2:0]), // [2:0] tile number 0..3 - Y, 4 - Cb, 5 - Cr (valid with start)
.first(color_first), // sending first MCU (valid @ ds)
.last(color_last), // sending last MCU (valid @ ds)
.n000(n000[7:0]), // [7:0] number of zero pixels (255 if 256)
.n255(n255[7:0]), // [7:0] number of 0xff pixels (255 if 256)
.bayer_phase(cmprs_bayer_this[1:0]), // bayer color filter phase 0:(GR/BG), 1:(RG/GB), 2: (BG/GR), 3: (GB/RG)
// below signals valid at ds ( 1 later than tn, first, last)
.component_num(component_num[2:0]), //[1:0] - component number (YCbCr: 0 - Y, 1 - Cb, 2 - Cr, JP4: 0-1-2-3 in sequence (depends on shift) >=4 - don't use
.component_color(component_color), // use color quantization table (YCbCR, jp4diff)
.component_first(component_first), // first this component in a frame (DC absolute, otherwise - difference to previous)
.component_lastinmb(component_lastinmb) // last component in a macroblock;
`ifdef debug_compressor
,.bcntrIsZero(debug_bcntrIsZero)
,.bcntr(debug_bcntr[17:0])
`endif
);
//assign color_d[9]=color_d[8]; // temporary
xdct i_xdct ( .clk(clk), // top level module
.en(cmprs_en), // if zero will reset transpose memory page numbers
.start(dct_start), // single-cycle start pulse that goes with the first pixel data. Other 63 should follow
.xin(color_d[9:0]), // [7:0] - input data
.last_in(dct_last_in), // output high during input of the last of 64 pixels in a 8x8 block //
.pre_first_out(dct_pre_first_out),// 1 cycle ahead of the first output in a 64 block
.dv(dct_dv), // data output valid. Will go high on the 94-th cycle after the start
.d_out(dct_out[12:0]));// [12:0]output data
// probably dcc things are not needed anymore
always @ (posedge clk) quant_start <= dct_pre_first_out;
always @ (posedge clk) begin
if (!dccout) dcc_en <=1'b0;
else if (dct_start && color_first && (color_tn[2:0]==3'b001)) dcc_en <=1'b1; // 3'b001 - closer to the first "start" in quantizator
end
wire [15:0] quant_dc_tdo;// MSB aligned coefficient for the DC component (used in focus module)
//wire [3:0] coring_num;
wire [2:0] coring_num;
quantizator i_quantizator(.clk(clk), // pixel clock
.en(cmprs_en), // enable (0 resets counter)
.sclk(clk2x), // system clock, twe, ta,tdi - valid @negedge (ra, tdi - 2 cycles ahead
.twqe(twqe), // enable write to a table
.twce(twce), // coring functions tables (@negedge clk - addr and data valid this cycle and one before)
.ta(ta[8:0]), // [6:0] table address
.tdi(di[15:0]), //
.ctypei(component_color), // component type input (Y/C)
.dci(color_avr[8:0]), // [8:0] - average value in a block - subtracted before DCT (now 9 bits signed)
.first_stb(first_block_color), //this is first stb pulse in a frame
.stb(dct_start), // strobe that writes ctypei, dci
.tsi(cmprs_qpage_this[2:0]), // table (quality) select
.pre_start(dct_pre_first_out),
.first_in(first_block_dct), // first block in (valid @ start)
.first_out(first_block_quant), // valid @ ds
.di(dct_out[12:0]), // [8:0] pixel data in (signed)
.do(quant_do[12:0]), // [11:0] pixel data out signed
// .dv(quant_dv), // data out valid
.dv(), // data out valid
.ds(quant_ds), // data out strobe (one ahead of the start of dv)
.dc_tdo(quant_dc_tdo[15:0]), //[15:0], MSB aligned coefficient for the DC component (used in focus module)
// .dc_tdo_stb(quant_dc_tdo_stb),
.dcc_en(dcc_en), // enable dcc (sync to beginning of a new frame)
.hfc_sel(hfc_sel), // hight frequency components select [2:0] (includes components with both numbers >=hfc_sel
.color_first(color_first), // first MCU in a frame NOTE: ONLY NEEDED for DCC
.coring_num(coring_num), ///coring table par number
.dcc_vld(dccvld),
.dcc_data(dccdata[15:0]),
.n000(n000[7:0]), // input [7:0] number of zero pixels (255 if 256) - to be multiplexed with dcc
.n255(n255[7:0])); // input [7:0] number of 0xff pixels (255 if 256) - to be multiplexed with dcc
//TODO: compact table
focus_sharp i_focus_sharp(.clk(clk), // pixel clock
.en(cmprs_en), // enable (0 resets counter)
.sclk(clk2x), // system clock, twe, ta,tdi - valid @negedge (ra, tdi - 2 cycles ahead
.twe(twfe), // enable write to a table
.ta(ta[9:0]), // [9:0] table address
.tdi(di[15:0]), // [15:0] table data in (8 LSBs - quantization data)
.mode(cmprs_fmode_this[1:0]), // focus mode (combine image with focus info) - 0 - none, 1 - replace, 2 - combine all, 3 - combine woi
// .stren(focus_strength),
.firsti(color_first), // first macroblock
.lasti(color_last), // last macroblock
.tni(color_tn[2:0]), // block number in a macronblock - 0..3 - Y, >=4 - color (sync to stb)
.stb(dct_start), // strobe that writes ctypei, dci
.start(quant_start),// marks first input pixel (needs 1 cycle delay from previous DCT stage)
.di(dct_out[12:0]), // [11:0] pixel data in (signed)
.quant_ds(quant_ds), // quantizator data strobe (1 before DC)
.quant_d(quant_do[12:0]), // quantizator data output
.quant_dc_tdo(quant_dc_tdo[15:0]), //[15:0], MSB aligned coefficient for the DC component (used in focus module)
// .quant_dc_tdo_stb(quant_dc_tdo_stb),
.do(focus_do[12:0]), // [11:0] pixel data out (AC is only 9 bits long?) - changed to 10
.ds(focus_ds), // data out strobe (one ahead of the start of dv)
.hifreq(hifreq[31:0]) //[31:0]) // accumulated high frequency components in a frame sub-window
);
dcc_sync i_dcc_sync(//.clk(clk),
.sclk(clk2x),
.dcc_en(dcc_en), // clk rising, sync with start of the frame
.finish_dcc(finish_dcc), // sclk rising
.dcc_vld(dccvld), // clk rising
.dcc_data(dccdata[15:0]), //[15:0] clk risimg
.statistics_dv(statistics_dv), //sclk
.statistics_do(statistics_do[15:0])//[15:0] sclk
);
// generate DC data/strobe for the direct output (re) using sdram channel3 buffering
// encoderDCAC is updated to handle 13-bit signed data instead of the 12-bit. It will limit the values on ot's own
encoderDCAC i_encoderDCAC(.clk(clk),
.en(cmprs_en),
// .firsti(color_first), // was "first MCU in a frame" (@ stb)
.lasti(color_last), // was "last MCU in a frame" (@ stb)
// .tni(color_tn[2:0]), // [2:0] tile number in MCU (0..5) - was valid @ stb
.first_blocki(first_block_color), // first block in frame - save fifo write address (@ stb)
.comp_numberi(component_num[2:0]), // [2:0] component number 0..2 in color, 0..3 - in jp4diff, >= 4 - don't use (@ stb)
.comp_firsti(component_first), // fitst this component in a frame (reset DC) (@ stb)
.comp_colori(component_color), // use color - huffman? (@ stb)
.comp_lastinmbi(component_lastinmb), // last component in a macroblock (@ stb)
.stb(dct_start), // strobe that writes firsti, lasti, tni,average
.zdi(focus_do[12:0]), // [12:0]
.first_blockz(first_block_quant), // first block input (@zds)
.zds(focus_ds), // strobe - one ahead of the DC component output
.last(enc_last), // - not used
.do(enc_do[15:0]),
.dv(enc_dv)
);
wire last_block, test_lbw;
huffman i_huffman (.pclk(clk), // pixel clock
.clk(clk2x), // twice frequency - uses negedge inside
.en(cmprs_en), // enable (0 resets counter) sync to .pclk(clk)
// .cwr(cwr), // CPU WR global clock
.twe(twhe), // enable write to a table
.ta(ta[8:0]), // [8:0] table address
.tdi(di[15:0]), // [23:0] table data in (8 LSBs - quantization data, [13:9] zigzag address
.di(enc_do[15:0]), // [15:0] specially RLL prepared 16-bit data (to FIFO)
.ds(enc_dv), // di valid strobe
.rdy(stuffer_rdy), // receiver (bit stuffer) is ready to accept data
.do(huff_do), // [15:0] output data
.dl(huff_dl), // [3:0] output width (0==16)
.dv(huff_dv), // output data bvalid
.flush(flush),
.last_block(last_block),
.test_lbw(),
.gotLastBlock(test_lbw)); // last block done - flush the rest bits
`ifdef debug_compressor
reg eot_2x_n,stuffer_flush_enable;
// wire stuffer_flushing;
always @ (negedge clk2x) begin
eot_2x_n <=eot;
stuffer_flush_enable <= cmprs_en_2x_n && (stuffer_flush_enable?(!stuffer_flushing):eot_2x_n);
end
reg [31:0] test_cntr0;
reg [1:0] was_flush;
reg [1:0] was_eot;
reg [1:0] was_last_block;
reg [1:0] was_test_lbw;
reg [1:0] was_go_single;
reg [1:0] was_is_compressing;
// reg [1:0] was_go_single;
reg [1:0] was_bcntrIsZero;
reg [1:0] was_go_rq;
always @ ( negedge clk2x) begin
// was_flush[1:0] <= {was_flush[0],flush};
was_flush [1:0] <= {was_flush[0], flush && stuffer_flush_enable};
// was_eot [1:0] <= {was_eot[0], eot_2x_n};
was_last_block[1:0] <= {was_last_block[0],last_block};
was_test_lbw [1:0] <= {was_test_lbw[0], test_lbw};
was_go_single[1:0] <= {was_go_single[0],go_single};
was_is_compressing [1:0] <= {was_is_compressing[0], is_compressing};
// if (!cmprs_en_2x_n) test_cntr0[7:0] <= 0;
// else if (was_flush[1:0]==2'h1) test_cntr0[7:0] <=test_cntr0[7:0] + 1; // 1->7a (was 7b without mask?)
//// if (!cmprs_en_2x_n) test_cntr0[15:8] <= 0;
//// else if (was_eot[1:0]==2'h1) test_cntr0[15:8] <=test_cntr0[15:8] + 1; // 1->7a !!!
////// if (!cmprs_en_2x_n) test_cntr0[23:16] <= 0;
////// else if (was_last_block[1:0]==2'h1) test_cntr0[23:16] <=test_cntr0[23:16] + 1; // 1->7b
////// if (!cmprs_en_2x_n) test_cntr0[31:24] <= 0;
////// else if (was_test_lbw[1:0]==2'h1) test_cntr0[31:24] <=test_cntr0[31:24] + 1; // 1->7b
//// if (!cmprs_en_2x_n) test_cntr0[23:16] <= 0;
//// else if (was_go_single[1:0]==2'h1) test_cntr0[23:16] <=test_cntr0[23:16] + 1; // 1->2
//// if (!cmprs_en_2x_n) test_cntr0[31:24] <= 0;
//// else if (was_is_compressing[1:0]==2'h1) test_cntr0[31:24] <=test_cntr0[31:24] + 1; // 1->2
end
// debug_bcntrIsZero
// reg [1:0] was_go_single;
// reg [1:0] was_bcntrIsZero;
// debug_bcntrIsZero
reg debug1;
always @ ( posedge clk) begin
was_eot [1:0] <= {was_eot[0], eot};
was_go_rq [1:0] <= {was_go_rq[0], go_rq};
was_bcntrIsZero [1:0] <= {was_bcntrIsZero[0], debug_bcntrIsZero};
//// test_cntr0[7:0] <= debug_bcntr[7:0]; // 0 -> 0 -> 78 -> 78 -> 78
/// test_cntr0[15:0] <= debug_bcntr[15:0]; // 0 -> 0 -> 78 -> 78 -> 78
// if (was_go_rq[1:0]==2'h1) test_cntr0[15:8] <= 0;
// else if (was_eot[1:0]==2'h1) test_cntr0[15:8] <=test_cntr0[15:8] + 1;
// if (!cmprs_en) test_cntr0[23:16] <= 0;
// else if (go_single) test_cntr0[23:16] <=test_cntr0[23:16] + 1; // 0 -> 1 -> 2 -> 3 -> 4
// if (!cmprs_en) test_cntr0[31:24] <= 0;
// else if (was_bcntrIsZero[1:0]==2'h1) test_cntr0[31:24] <=test_cntr0[31:24] + 1; // 0 -> 1 -> 1 -> 2 -> 3
// should end up 1 more than number of blocks?
// if (go_single) test_cntr0[31:16] <= 0;
// else if (nxtpage) test_cntr0[31:16] <=test_cntr0[31:16] + 1; //
if (go_single) test_cntr0[15:0] <= 0;
else if (nxtpage) test_cntr0[14:0] <= test_cntr0[14:0] + 1; //
if (go_single) test_cntr0[30:16] <= test_cntr0[14:0];
if (was_go_rq[1:0]==2'h1) debug1 <= 1'b0;
else if (pxrdy) debug1 <= 1'b1;
if (go_single) test_cntr0[31] <= debug1;
test_cntr0[15] <= pxrdy;
end
`endif
stuffer i_stuffer (.clk(clk2x), //clock - uses negedge inside
.en(cmprs_en_2x_n), // enable, 0- reset
.reset_data_counters(reset_data_counters[1]), // reset data transfer counters (only when DMA and compressor are disabled)
// .flush(flush), // flush output data (fill byte with 0, long word with FFs
.flush(flush || force_flush), // flush output data (fill byte with 0, long word with FFs
.stb(huff_dv), // input data strobe
.dl(huff_dl), // [3:0] number of bits to send (0 - 16)
.d(huff_do), // [15:0] input data to shift (only lower bits are valid)
// time stamping - will copy time at the end of color_first (later than the first hact after vact in the current froma, but before the next one
// and before the data is needed for output
.color_first(color_first), //
.sec(sec[31:0]),
.usec(usec[19:0]),
.rdy(stuffer_rdy), // enable huffman encoder to proceed. Used as CE for many huffman encoder registers
.q(stuffer_do), // [15:0] output data
.qv(stuffer_dv), // output data valid
.done(stuffer_done),
.imgptr (imgptr[23:0]), // [23:0]image pointer in 32-byte chunks
.flushing(stuffer_flushing)
`ifdef debug_stuffer
,.etrax_dma_r(tst_stuf_etrax[3:0]) // [3:0] just for testing
,.test_cntr(test_cntr[3:0])
,.test_cntr1(test_cntr1[7:0])
`endif
);
always @ (negedge clk2x) wr_saturation_d <= wr_saturation;
FDE_1 #(.INIT(1'b0)) i_m_cb0 (.C(clk2x),.CE(wr_saturation),.D(di[ 0]),.Q(m_cb[0]));
FDE_1 #(.INIT(1'b0)) i_m_cb1 (.C(clk2x),.CE(wr_saturation),.D(di[ 1]),.Q(m_cb[1]));
FDE_1 #(.INIT(1'b0)) i_m_cb2 (.C(clk2x),.CE(wr_saturation),.D(di[ 2]),.Q(m_cb[2]));
FDE_1 #(.INIT(1'b0)) i_m_cb3 (.C(clk2x),.CE(wr_saturation),.D(di[ 3]),.Q(m_cb[3]));
FDE_1 #(.INIT(1'b1)) i_m_cb4 (.C(clk2x),.CE(wr_saturation),.D(di[ 4]),.Q(m_cb[4]));
FDE_1 #(.INIT(1'b0)) i_m_cb5 (.C(clk2x),.CE(wr_saturation),.D(di[ 5]),.Q(m_cb[5]));
FDE_1 #(.INIT(1'b0)) i_m_cb6 (.C(clk2x),.CE(wr_saturation),.D(di[ 6]),.Q(m_cb[6]));
FDE_1 #(.INIT(1'b1)) i_m_cb7 (.C(clk2x),.CE(wr_saturation),.D(di[ 7]),.Q(m_cb[7]));
FDE_1 #(.INIT(1'b0)) i_m_cb8 (.C(clk2x),.CE(wr_saturation),.D(di[ 8]),.Q(m_cb[8]));
FDE_1 #(.INIT(1'b0)) i_m_cb9 (.C(clk2x),.CE(wr_saturation),.D(di[ 9]),.Q(m_cb[9]));
FDE_1 #(.INIT(1'b0)) i_m_cr0 (.C(clk2x),.CE(wr_saturation), .D(di[12]),.Q(m_cr[0]));
FDE_1 #(.INIT(1'b1)) i_m_cr1 (.C(clk2x),.CE(wr_saturation), .D(di[13]),.Q(m_cr[1]));
FDE_1 #(.INIT(1'b1)) i_m_cr2 (.C(clk2x),.CE(wr_saturation), .D(di[14]),.Q(m_cr[2]));
FDE_1 #(.INIT(1'b0)) i_m_cr3 (.C(clk2x),.CE(wr_saturation), .D(di[15]),.Q(m_cr[3]));
FDE_1 #(.INIT(1'b1)) i_m_cr4 (.C(clk2x),.CE(wr_saturation_d),.D(di[ 0]),.Q(m_cr[4]));
FDE_1 #(.INIT(1'b1)) i_m_cr5 (.C(clk2x),.CE(wr_saturation_d),.D(di[ 1]),.Q(m_cr[5]));
FDE_1 #(.INIT(1'b0)) i_m_cr6 (.C(clk2x),.CE(wr_saturation_d),.D(di[ 2]),.Q(m_cr[6]));
FDE_1 #(.INIT(1'b1)) i_m_cr7 (.C(clk2x),.CE(wr_saturation_d),.D(di[ 3]),.Q(m_cr[7]));
FDE_1 #(.INIT(1'b0)) i_m_cr8 (.C(clk2x),.CE(wr_saturation_d),.D(di[ 4]),.Q(m_cr[8]));
FDE_1 #(.INIT(1'b0)) i_m_cr9 (.C(clk2x),.CE(wr_saturation_d),.D(di[ 5]),.Q(m_cr[9]));
//always @ (negedge clk2x) wr_quantizer_mode_d <= wr_quantizer_mode;
FDE_1 i_coring_num0 (.C(clk2x),.CE(wr_quantizer_mode),.D(di[ 0]),.Q(coring_num[0]));
FDE_1 i_coring_num1 (.C(clk2x),.CE(wr_quantizer_mode),.D(di[ 1]),.Q(coring_num[1]));
FDE_1 i_coring_num2 (.C(clk2x),.CE(wr_quantizer_mode),.D(di[ 2]),.Q(coring_num[2]));
endmodule
// ----------------- submodules ---------------------
// [16] ==1 - set focus mode
// [15:14] 0 - none
// 1 - replace
// 2 - combine for all image
// 3 - combine in window only
// [13]==1 - enable color modes
// [12:9]== 0 - color, 4:2:0
// 1 - monochrome, 6/4 blocks (as 4:2:0)
// 2 - jp4, 6 blocks, original
// 3 - jp4, 6 blocks, dc -improved
// 4 - mono, 4 blocks (but still not actual monochrome JPEG as the blocks are scanned in 2x2 macroblocks)
// 5 - jp4, 4 blocks, dc-improved
// 6 - jp4, differential
// 7 - 15 - reserved
// [8:7] == 0,1 - NOP, 2 - disable, 3 - enable subtracting of average value (DC component), bypassing DCT
// [6] == 1 - enable quantization bank select, 0 - disregard bits [5:3]
// [5:3] = quantization page number (0..7)
// [2]== 1 - enable on/off control:
// [1:0]== 0 - reset compressor, stop immediately
// 1 - enable compressor, disable repetitive mode
// 2 - enable compressor, compress single frame
// 3 - enable compressor, enable repetitive mode
module compr_ifc (clk, // compressor input clock (1/2 of sclk)
// cwr, // CPU write - global clock
sclk, // system clock (120MHz)
cwe, // we to compressor from CPU (sync to negedge sclk)
rs, // 0 - bit modes,
// 1 - write ntiles;
di, // [15:0] data from CPU (sync to negedge sclk)
cr_w, // data written to cr (1 cycle long) - just to reset legacy IRQ
ntiles,//[17:0] - number of tiles in a frame to process
cmprs_en, // enable compressor
cmprs_start, // single cycle when single or constant compression is turned on
cmprs_repeat,// high in repetitive mode
cmprs_qpage, // [2:0] - quantizator page number (0..7)
cmprs_dcsub, // subtract dc level before DCT, restore later
cmprs_mode, // [3:0] - compressor mode
cmprs_shift, // tile shift from top left corner
cmprs_fmode, //[1:0] - focus mode
bayer_shift, // additional shift to bayer mosaic
is_compressing, // high from start of compressing till EOT (sync to posedge clk)
abort_compress,
force_flush); // abort compress - generate flush pulse, force end of image over DMA, update counter
// single-cycle @ negedge sclk
// force_eot); // sync to posedge clk - simulates eot to abort compression
input clk,
sclk,
cwe;
input rs;
input [15:0] di;
output cr_w;
output [17:0] ntiles;
output cmprs_en; // enable compressor
output cmprs_start; // single cycle when single or constant compression is turned on
output cmprs_repeat;// high in repetitive mode
output [ 2:0] cmprs_qpage; // [2:0] - quantizator page number (0..7)
output cmprs_dcsub; // subtract dc level before DCT, restore later
output [ 3:0] cmprs_mode; // [3:0] - compressor mode
output [ 2:0] cmprs_shift; // tile shift from top left corner
output [ 1:0] cmprs_fmode; // [1:0] - focus mode
output [ 1:0] bayer_shift; // additional shift to bayer mosaic
input is_compressing; // high from start of compressing till EOT (sync to posedge clk)
input abort_compress;
output force_flush; // abort compress - generate flush pulse, force end of image over DMA, update counter
// output force_eot; // sync to posedge clk - simulates eot to abort compression
reg cmprs_en; // enable compressor
wire cmprs_start; // single cycle when single or constant compression is turned on
reg cmprs_repeat;// high in repetitive mode
reg [ 2:0] cmprs_qpage; // [2:0] - quantizator page number (0..7)
reg cmprs_dcsub; // subtract dc level before DCT, restore later
reg [ 3:0] cmprs_mode; // [3:0] - compressor mode
reg [ 2:0] cmprs_shift; // tile shift from top left corner
reg [ 1:0] cmprs_fmode; // [1:0] - focus mode
reg [ 1:0] bayer_shift; // additional shift to bayer mosaic
wire [ 1:0] cmprs_start_c;
wire cmprs_en_s; // enable compressor
wire cmprs_start_s; // single cycle when single or constant compression is turned on
wire cmprs_repeat_s;// high in repetitive mode
wire [ 2:0] cmprs_qpage_s; // [2:0] - quantizator page number (0..7)
wire cmprs_dcsub_s; // subtract dc level before DCT, restore later
wire [ 3:0] cmprs_mode_s; // [3:0] - compressor mode
wire [ 2:0] cmprs_shift_s; // tile shift from top left corner
wire [ 1:0] cmprs_fmode_s; // [1:0] - focus mode
wire [ 1:0] bayer_shift_s; // additional shift to bayer mosaic
///AF: reg [23:0] cr;
reg [17:0] ntiles;
reg [15:0] ntiles0;
reg [17:0] ntiles1;
reg [17:0] ntiles1_prev;
wire [23:0] cri;
wire [1:0] rcs;
wire cr_w;
wire [1:0] cr_wi;
assign rcs[1:0]={cwe && rs, cwe && ~rs};
reg rcs0_d, rcs0_dd;
///AF: reg rcs1_d;
reg [2:0] rcs1d;
reg [1:0] is_compressing_sclk; // sync to negedge sclk
reg [1:0] is_compressing_or_flushing_sclk=2'h0; // includes flushing
reg force_flush; // abort compress - generate flush pulse, force end of image over DMA, update counter
// wire [1:0] f_eot;
// wire force_eot;
reg cmprs_en_long; /// waits for compressor to finish gracefully with timeout enforced
reg cmprs_en_finish; /// finishing compressor flushing
reg [6:0] cmprs_en_timeout;
reg cmprs_en_s_d;
reg force_flush1; ///force flush caused by turning compressor off
always @ (negedge sclk) begin
cmprs_en_s_d <= cmprs_en_s;
cmprs_en_finish <= is_compressing_or_flushing_sclk[1] && /// when compressor is still running
((!cmprs_en_s && cmprs_en_s_d) || /// and compressor is disabled by command
(cmprs_en_finish && (cmprs_en_timeout[6:0]!= 7'h0))); /// timeout (maybe not needed?)
if (!cmprs_en_finish) cmprs_en_timeout[6:0] <= 7'h50; //80
else cmprs_en_timeout[6:0] <=cmprs_en_timeout[6:0]-1;
cmprs_en_long <= cmprs_en_s || cmprs_en_s_d || cmprs_en_finish;
force_flush1<= is_compressing_sclk[1] && /// is still compressing
!cmprs_en_s && /// first cycle when compressor enable is turned off
cmprs_en_s_d;
end
always @ (negedge sclk) begin
rcs0_d <= rcs[0];
// rcs1_d <= rcs[1];
rcs1d[2:0]<={rcs1d[1:0],rcs[1]};
rcs0_dd <= rcs0_d;
is_compressing_or_flushing_sclk[1:0] <= {is_compressing_or_flushing_sclk[0],
is_compressing | (abort_compress & is_compressing_or_flushing_sclk[1])};
is_compressing_sclk[1:0] <= {is_compressing_sclk[0], is_compressing};
// force_flush <= is_compressing_sclk[1] && rcs[1];
///add double cycle if needed
force_flush <= force_flush1 ||(rcs1d[2] && is_compressing_sclk[1] && (ntiles1_prev[17:0] != ntiles1[17:0]));
end
FDE_1 i_cri00 (.C(sclk),.CE(rcs[0]),.D(di[ 0]),.Q(cri[ 0]));
FDE_1 i_cri01 (.C(sclk),.CE(rcs[0]),.D(di[ 1]),.Q(cri[ 1]));
FDE_1 i_cri02 (.C(sclk),.CE(rcs[0]),.D(di[ 2]),.Q(cri[ 2]));
FDE_1 i_cri03 (.C(sclk),.CE(rcs[0]),.D(di[ 3]),.Q(cri[ 3]));
FDE_1 i_cri04 (.C(sclk),.CE(rcs[0]),.D(di[ 4]),.Q(cri[ 4]));
FDE_1 i_cri05 (.C(sclk),.CE(rcs[0]),.D(di[ 5]),.Q(cri[ 5]));
FDE_1 i_cri06 (.C(sclk),.CE(rcs[0]),.D(di[ 6]),.Q(cri[ 6]));
FDE_1 i_cri07 (.C(sclk),.CE(rcs[0]),.D(di[ 7]),.Q(cri[ 7]));
FDE_1 i_cri08 (.C(sclk),.CE(rcs[0]),.D(di[ 8]),.Q(cri[ 8]));
FDE_1 i_cri09 (.C(sclk),.CE(rcs[0]),.D(di[ 9]),.Q(cri[ 9]));
FDE_1 i_cri10 (.C(sclk),.CE(rcs[0]),.D(di[10]),.Q(cri[10]));
FDE_1 i_cri11 (.C(sclk),.CE(rcs[0]),.D(di[11]),.Q(cri[11]));
FDE_1 i_cri12 (.C(sclk),.CE(rcs[0]),.D(di[12]),.Q(cri[12]));
FDE_1 i_cri13 (.C(sclk),.CE(rcs[0]),.D(di[13]),.Q(cri[13]));
FDE_1 i_cri14 (.C(sclk),.CE(rcs[0]),.D(di[14]),.Q(cri[14]));
FDE_1 i_cri15 (.C(sclk),.CE(rcs[0]),.D(di[15]),.Q(cri[15]));
FDE_1 i_cri16 (.C(sclk),.CE(rcs0_d),.D(di[ 0]),.Q(cri[16]));
FDE_1 i_cri17 (.C(sclk),.CE(rcs0_d),.D(di[ 1]),.Q(cri[17]));
FDE_1 i_cri18 (.C(sclk),.CE(rcs0_d),.D(di[ 2]),.Q(cri[18]));
FDE_1 i_cri19 (.C(sclk),.CE(rcs0_d),.D(di[ 3]),.Q(cri[19]));
FDE_1 i_cri20 (.C(sclk),.CE(rcs0_d),.D(di[ 4]),.Q(cri[20]));
FDE_1 i_cri21 (.C(sclk),.CE(rcs0_d),.D(di[ 5]),.Q(cri[21]));
FDE_1 i_cri22 (.C(sclk),.CE(rcs0_d),.D(di[ 6]),.Q(cri[22]));
FDE_1 i_cri23 (.C(sclk),.CE(rcs0_d),.D(di[ 7]),.Q(cri[23]));
// just for legacy cr_w
FDCE_1 i_cr_wi0 (.C(sclk),.CE(rcs0_d),.CLR(cr_w),.D(1'b1), .Q(cr_wi[0]));
FD i_cr_wi1 (.C(clk), .D(cr_wi[0] ),.Q(cr_wi[1]));
FD i_cr_w (.C(clk), .D(cr_wi[1] & !cr_w),.Q(cr_w ));
// always @ (posedge clk) cr[23:0] <=cri[23:0]; // make it sync
always @ (negedge sclk) if (rcs[1]) ntiles0[15:0] <= di[15:0];
// always @ (negedge sclk) if (rcs1_d) ntiles1[17:0] <= {di[15:0],ntiles0[15:0]};
always @ (negedge sclk) if (rcs1d[0]) ntiles1[17:0] <= {di[ 1:0],ntiles0[15:0]};
always @ (negedge sclk) if (rcs1d[2]) ntiles1_prev[17:0] <= ntiles1[17:0];
// rcs1d[2:0]<={rcs1d[1:0],rcs[1]};
// command decode
FDE_1 i_cmprs_en_s (.C(sclk),.CE(rcs0_dd && cri[2]), .D(cri[1:0]!=2'h0),.Q(cmprs_en_s));
FDE_1 i_cmprs_repeat_s (.C(sclk),.CE(rcs0_dd && cri[2]), .D(cri[1:0]==2'h3),.Q(cmprs_repeat_s));
FD_1 i_cmprs_start_s (.C(sclk),.D (rcs0_dd && cri[2] && ((cri[1:0]==2'h2) || ((cri[1:0]==2'h3) && ! cmprs_repeat_s ))),.Q(cmprs_start_s));
FDE_1 i_cmprs_qpage_s0 (.C(sclk),.CE(rcs0_dd && cri[6]), .D(cri[ 3]), .Q(cmprs_qpage_s[0]));
FDE_1 i_cmprs_qpage_s1 (.C(sclk),.CE(rcs0_dd && cri[6]), .D(cri[ 4]), .Q(cmprs_qpage_s[1]));
FDE_1 i_cmprs_qpage_s2 (.C(sclk),.CE(rcs0_dd && cri[6]), .D(cri[ 5]), .Q(cmprs_qpage_s[2]));
FDE_1 i_cmprs_dcsub_s (.C(sclk),.CE(rcs0_dd && cri[8]), .D(cri[ 7]), .Q(cmprs_dcsub_s));
FDE_1 i_cmprs_mode_s0 (.C(sclk),.CE(rcs0_dd && cri[13]),.D(cri[ 9]), .Q(cmprs_mode_s[0]));
FDE_1 i_cmprs_mode_s1 (.C(sclk),.CE(rcs0_dd && cri[13]),.D(cri[10]), .Q(cmprs_mode_s[1]));
FDE_1 i_cmprs_mode_s2 (.C(sclk),.CE(rcs0_dd && cri[13]),.D(cri[11]), .Q(cmprs_mode_s[2]));
FDE_1 i_cmprs_mode_s3 (.C(sclk),.CE(rcs0_dd && cri[13]),.D(cri[12]), .Q(cmprs_mode_s[3]));
FDE_1 i_cmprs_shift_s0 (.C(sclk),.CE(rcs0_dd && cri[17]),.D(cri[14]), .Q(cmprs_shift_s[0]));
FDE_1 i_cmprs_shift_s1 (.C(sclk),.CE(rcs0_dd && cri[17]),.D(cri[15]), .Q(cmprs_shift_s[1]));
FDE_1 i_cmprs_shift_s2 (.C(sclk),.CE(rcs0_dd && cri[17]),.D(cri[16]), .Q(cmprs_shift_s[2]));
FDE_1 i_bayer_shift_s0 (.C(sclk),.CE(rcs0_dd && cri[20]),.D(cri[18]), .Q(bayer_shift_s[0]));
FDE_1 i_bayer_shift_s1 (.C(sclk),.CE(rcs0_dd && cri[20]),.D(cri[19]), .Q(bayer_shift_s[1]));
FDE_1 i_cmprs_fmode_s0 (.C(sclk),.CE(rcs0_dd && cri[23]),.D(cri[21]), .Q(cmprs_fmode_s[0]));
FDE_1 i_cmprs_fmode_s1 (.C(sclk),.CE(rcs0_dd && cri[23]),.D(cri[22]), .Q(cmprs_fmode_s[1]));
always @ (posedge clk) begin
ntiles[17:0] <=ntiles1[17:0]; // make it sync
/// cmprs_en <= cmprs_en_s;
cmprs_en <= cmprs_en_long; // extended enable, waiting for the compressor to output data length
cmprs_repeat <= cmprs_repeat_s;
cmprs_qpage[2:0] <= cmprs_qpage_s[2:0];
cmprs_dcsub <=cmprs_dcsub_s;
cmprs_mode[3:0] <=cmprs_mode_s[3:0];
cmprs_shift[2:0] <=cmprs_shift_s[2:0];
bayer_shift[1:0] <=bayer_shift_s[1:0];
cmprs_fmode[1:0] <=cmprs_fmode_s[1:0];
end
FDCE_1 i_cmprs_start_c0 (.C(sclk),.CE(cmprs_start_s), .CLR(cmprs_start),.D(1'b1), .Q(cmprs_start_c[0]));
FD i_cmprs_start_c1 (.C(clk), .D(cmprs_start_c[0] ),.Q(cmprs_start_c[1]));
FD i_cmprs_start (.C(clk), .D(cmprs_start_c[1] & !cmprs_start),.Q(cmprs_start ));
endmodule
// syncronizes dcc data with dma1 output, adds 16..31 16-bit zero words for Axis DMA
module dcc_sync (//clk,
sclk,
dcc_en, // clk rising, sync with start of the frame
finish_dcc, // sclk rising
dcc_vld, // clk rising
dcc_data, //[15:0] clk risimg
statistics_dv, //sclk
statistics_do //[15:0] sclk
);
//input clk;
input sclk, dcc_en, finish_dcc,dcc_vld;
input [15:0] dcc_data;
output statistics_dv;
output [15:0] statistics_do;
reg [15:0] statistics_do;
reg statistics_we;
reg statistics_dv;
reg dcc_run;
reg dcc_finishing;
reg skip16; // output just 16 zero words (data was multiple of 16 words)
reg [ 4:0] dcc_cntr;
always @ (posedge sclk) begin
dcc_run <= dcc_en;
statistics_we <= dcc_run && dcc_vld && !statistics_we;
statistics_do[15:0] <= statistics_we?dcc_data[15:0]:16'h0;
statistics_dv <= statistics_we || dcc_finishing;
skip16 <= finish_dcc && (statistics_dv?(dcc_cntr[3:0]==4'hf):(dcc_cntr[3:0]==4'h0) );
if (!dcc_run) dcc_cntr[3:0] <= 4'h0;
else if (statistics_dv) dcc_cntr[3:0] <= dcc_cntr[3:0]+1;
dcc_cntr[4] <= dcc_run && ((dcc_finishing && ((dcc_cntr[3:0]==4'hf)^dcc_cntr[4]) || skip16));
dcc_finishing <= dcc_run && (finish_dcc || (dcc_finishing && (dcc_cntr[4:1]!=4'hf)));
end
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/csconvert18.v 0000664 0000000 0000000 00000072566 12555570767 0024032 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** csconvert18.v
**
** Color space converter (bayer-> YCbCr 4:2:1) for JPEG compressor
**
** Copyright (C) 2002-2008 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X333 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
/*
09/07/2002 Andrey Filippov
Compared to spreadsheet simulation. Y - matches, CbCr in ~25% give result one less than spreadsheet simulation.
It is always odd and s.s. gives next even
TODO: optimize sequencing counters and possibly add some extra bits - as to calculate int((a+b+c+d)/4)
instead of int((int((a+b)/2)+int((c+d)/2))/2)
Color space converter processes one MCU at a time. It receives 16x16 8-bit bayer pixels (now it is always in (GR/BG)
sequence). With some latency it will produce 16x16x8 bit Y data (could be some artifacts on the borders) in scan-line
sequence and clock rate and Cb and Cr at the same time at half rate, so 4:2:0 will be generated at the same
time.
update: now it processes overlapping tiles (18x18) to avoid problems on the MCU boarders
Y= 0.299*R+0.587*G+0.114*B
Cb=-0.168*R-0.3313*G+0.5*B = 0.564*(B-Y)+128
Cr=0.5*R-0.4187*G-0.0813*B = 0.713*(R-Y)+128
For Bayer array (GR/BG)(bayer_phase[1:0]==0), and pixels P[Y,X]:
R[0,0]=0.5* (P[0,-1]+P[0,1])
R[0,1]= P[0,1]
R[1,0]=0.25*(P[0,-1]+P[0,1]+P[2,-1]+P[2,1])
R[1,1]=0.5 *(P[0,1] +P[2,1])
G[0,0]= P[0,0]
G[0,1]=0.25*(P[-1,1]+P[0,0]+P[0,2]+P[1,1])
G[1,0]=0.25*(P[0,0]+P[1,-1]+P[1,1]+P[2,0])
G[1,1]= P[1,1]
B[0,0]=0.5* (P[-1,0]+P[1,0])
B[0,1]=0.25*(P[-1,0]+P[-1,2]+P[1,0]+P[1,2])
B[1,0]= P[1,0]
B[1,1]=0.5* (P[1,0]+P[1,2])
Y[0,0]=0.299*0.5*(P[0,-1]+P[0,1]) + 0.587*P[0,0] + 0.114*0.5* (P[-1,0]+P[1,0])
Y[0,1]=0.299*P[0,1]+0.587*0.25*(P[-1,1]+P[0,0]+P[0,2]+P[1,1])+0.114*0.25*(P[-1,0]+P[-1,2]+P[1,0]+P[1,2])
Y[1,0]=0.299*0.25*(P[0,-1]+P[0,1]+P[2,-1]+P[2,1])+0.587*0.25*(P[0,0]+P[1,-1]+P[1,1]+P[2,0])+0.114*P[1,0]
Y[1,1]=0.299*0.5 *(P[0,1] +P[2,1])+0.587*P[1,1]+0.114*0.5* (P[1,0]+P[1,2])
Y[0,0]=(0x96*P[0,0]+ 0x4d*((P[0,-1]+P[0,1])/2) + 0x1d*((P[-1,0]+P[1,0])/2))>>8
Y[0,1]=(0x4d*P[0,1]+ 0x96*((P[-1,1]+P[0,0]+P[0,2]+P[1,1])/4)+ 0x1d*((P[-1,0]+P[-1,2]+P[1,0]+P[1,2])/4))>>8
Y[1,0]=(0x1d*P[1,0]+ 0x96*((P[0,0]+P[1,-1]+P[1,1]+P[2,0])/4)+ 0x4d*((P[0,-1]+P[0,1]+P[2,-1]+P[2,1])/4))>>8
Y[1,1]=(0x96*P[1,1]+ 0x1d*((P[1,0]+P[1,2])/2) + 0x4d*((P[0,1] +P[2,1])/2)))>>8
Cb and Cy are needed 1 for each 4 pixels (4:2:0)
(YC= 0.299*P[0,1]+0.587*(0.5*P[0,0]+P[1,1])+0.114*P[1,0] )
Cb=0.564*(P[1,0]-(0.299*P[0,1]+0.587*0.5*(P[0,0]+P[1,1])+0.114*P[1,0]))+128
Cr=0.713*(P[0,1]-(0.299*P[0,1]+0.587*0.5*(P[0,0]+P[1,1])+0.114*P[1,0]))+128
Cb=0.564*(P[1,0]-(0.299*P[0,1]+0.587*0.5*(P[0,0]+P[1,1])+0.114*P[1,0]))+128=
0.564*P[1,0]-0.299*0.564*P[0,1]-0.587*0.564*0.5*(P[0,0]+P[1,1])-0.114*0.564*P[1,0]))+128=
0.564*P[1,0]-0.168636*P[0,1]-0.165534*P[0,0]-0.165534*P[1,1]-0.064638*P[1,0]+128=
0.499362*P[1,0]-0.168636*P[0,1]-0.165534*P[0,0]-0.165534*P[1,1]+128=
-0.165534*P[0,0] -0.168636*P[0,1] +0.499362*P[1,0] -0.165534*P[1,1]+ 128=
(-256*0.165534*P[0,0] -256*0.168636*P[0,1] +256*0.499362*P[1,0] -256*0.165534*P[1,1])>>8+ 128=
(-42.5*P[0,0] -43*P[0,1] +128*P[1,0] -42.5*P[1,1])>>8+ 128=
(-85*((P[0,0]+P[1,1])/2) -43*P[0,1] +128*P[1,0])>>8+ 128=
(-0x55*((P[0,0]+P[1,1])/2) -2b*P[0,1] +P[1,0]<<7)>>8+ 0x80=
(-0x55*((P[0,0]+P[1,1])/2) -2b*P[0,1])>>8 +P[1,0]>>1 +0x80=
Cr=0.713*(P[0,1]-(0.299*P[0,1]+0.587*0.5*(P[0,0]+P[1,1])+0.114*P[1,0]))+128=
0.713* P[0,1]- 0.713*0.299*P[0,1] - 0.713*0.587*0.5*P[0,0]- 0.713*0.587*0.5*P[1,1] -0.713*0.114*P[1,0]+128=
0.713* P[0,1]- 0.213187*P[0,1] - 0.2092655*P[0,0]- 0.2092655*P[1,1] -0.081282*P[1,0]+128=
0.499813* P[0,1] -0.2092655*P[0,0] -0.2092655*P[1,1] -0.081282*P[1,0]+128=
-0.2092655*P[0,0] +0.499813* P[0,1] -0.081282*P[1,0] -0.2092655*P[1,1] +128=
(-256*0.2092655*P[0,0] +256*0.499813* P[0,1] -256*0.081282*P[1,0] -256*0.2092655*P[1,1])>>8 +128=
(-54*P[0,0] +128* P[0,1] -21*P[1,0] -54*P[1,1])>>8 +128= // rounded up, sum=129 -> decreasing
(-53.5*P[0,0] +128* P[0,1] -21*P[1,0] -53.5*P[1,1])>>8 +128=
(-107*((P[0,0]+P[1,1])/2) +P[0,1]<<7 -21*P[1,0])>>8 +128=
(-0x6b*((P[0,0]+P[1,1])/2) +P[0,1]<<7 -0x15*P[1,0])>>8 +0x80=
(-0x6b*((P[0,0]+P[1,1])/2) -0x15*P[1,0])>>8 +P[0,1]>>1 +0x80=
*/ /*
For Bayer array (RG/GB)(bayer_phase[1:0]==1), and pixels P[Y,X]:
R[0,0]= P[0,0]
R[0,1]=0.5 *(P[0,0]+P[0,2])
R[1,0]=0.5 *(P[0,0]+P[2,0])
R[1,1]=0.25*(P[0,0]+P[0,2]+P[2,0]+P[2,2])
G[0,0]=0.25*(P[-1,0]+P[0,-1]+P[0,1]+P[1,0])
G[0,1]= P[0,1]
G[1,0]= P[1,0]
G[1,1]=0.25*(P[0,1]+P[1,0]+P[1,2]+P[2,1])
B[0,0]=0.25*(P[-1,-1]+P[-1,1]+P[1,-1]+P[1,1])
B[0,1]=0.5* (P[-1,1]+P[1,1])
B[1,0]=0.5* (P[1,-1]+P[1,1])
B[1,1]= P[1,1]
Y[0,0]=0.299*P[0,0] + 0.587*0.25*(P[-1,0]+P[0,-1]+P[0,1]+P[1,0]) + 0.114*0.25*(P[-1,-1]+P[-1,1]+P[1,-1]+P[1,1])
Y[0,1]=0.299*0.5 *(P[0,0]+P[0,2])+0.587*P[0,1]+0.114*0.5* (P[-1,1]+P[1,1])
Y[1,0]=0.299*0.5 *(P[0,0]+P[2,0])+0.587*P[1,0]+0.114*0.5* (P[1,-1]+P[1,1])
Y[1,1]=0.299*0.25*(P[0,0]+P[0,2]+P[2,0]+P[2,2])+0.587*0.25*(P[0,1]+P[1,0]+P[1,2]+P[2,1])+0.114*P[1,1]
Y[0,0]=(0x4d*P[0,0]+ 0x96*((P[-1,0]+P[0,-1]+P[0,1]+P[1,0])/4) + 0x1d*((P[-1,-1]+P[-1,1]+P[1,-1]+P[1,1])/4))>>8
Y[0,1]=(0x96*P[0,1]+ 0x4d*((P[0,0]+P[0,2])/2)+ 0x1d*((P[-1,1]+P[1,1])/2))>>8
Y[1,0]=(0x96*P[1,0]+ 0x4d*((P[0,0]+P[2,0])/2)+ 0x1d*((P[1,-1]+P[1,1])/2))>>8
Y[1,1]=(0x1d*P[1,1]+ 0x96*((P[0,1]+P[1,0]+P[1,2]+P[2,1])/4) + 0x4d*((P[0,0]+P[0,2]+P[2,0]+P[2,2])/4)))>>8
Cb and Cy are needed 1 for each 4 pixels (4:2:0)
(YC= 0.299*P[0,0]+0.587*(0.5*P[0,1]+P[1,0])+0.114*P[1,1] )
Cb=0.564*(P[1,1]-(0.299*P[0,0]+0.587*0.5*(P[0,1]+P[1,0])+0.114*P[1,1]))+128
Cr=0.713*(P[0,0]-(0.299*P[0,0]+0.587*0.5*(P[0,1]+P[1,0])+0.114*P[1,1]))+128
Cb=0.564*(P[1,1]-(0.299*P[0,0]+0.587*0.5*(P[0,1]+P[1,0])+0.114*P[1,1]))+128=
(-0x55*((P[0,1]+P[1,0])/2) -2b*P[0,0] +P[1,1]<<7)>>8+ 0x80=
(-0x55*((P[0,1]+P[1,0])/2) -2b*P[0,0])>>8 +P[1,1]>>1 +0x80=
Cr=0.713*(P[0,0]-(0.299*P[0,0]+0.587*0.5*(P[0,1]+P[1,0])+0.114*P[1,1]))+128=
(-0x6b*((P[0,1]+P[1,0])/2) +P[0,0]<<7 -0x15*P[1,1])>>8 +0x80=
(-0x6b*((P[0,1]+P[1,0])/2) -0x15*P[1,1])>>8 +P[0,0]>>1 +0x80=
----
*/ /*
For Bayer array (BG/GR)(bayer_phase[1:0]==2), and pixels P[Y,X]:
R[0,0]=0.25*(P[-1,-1]+P[-1,1]+P[1,-1]+P[1,1])
R[0,1]=0.5 *(P[-1,1] +P[1,1])
R[1,0]=0.5* (P[1,-1]+P[1,1])
R[1,1]= P[1,1]
G[0,0]=0.25*(P[-1,0]+P[0,-1]+P[0,1]+P[1,0])
G[0,1]= P[0,1]
G[1,0]= P[1,0]
G[1,1]=0.25*(P[0,1]+P[1,0]+P[1,2]+P[2,1])
B[0,0]= P[0,0]
B[0,1]=0.5* (P[0,0]+P[0,2])
B[1,0]=0.5* (P[0,0]+P[2,0])
B[1,1]=0.25*(P[0,0]+P[0,2]+P[2,0]+P[2,2])
Y[0,0]=0.299*0.25*(P[-1,-1]+P[-1,1]+P[1,-1]+P[1,1]) + 0.587*0.25*(P[-1,0]+P[0,-1]+P[0,1]+P[1,0]) + 0.114* P[0,0]
Y[0,1]=0.299*0.5 *(P[-1,1] +P[1,1])+0.587*P[0,1]+0.114*0.5* (P[0,0]+P[0,2])
Y[1,0]=0.299*0.5* (P[1,-1]+P[1,1])+0.587*P[1,0]+0.114*0.5* (P[0,0]+P[2,0])
Y[1,1]=0.299*P[1,1]+0.587*0.25*(P[0,1]+P[1,0]+P[1,2]+P[2,1])+0.114*0.25*(P[0,0]+P[0,2]+P[2,0]+P[2,2])
Y[0,0]=(0x1d*P[0,0]+ 0x96*((P[-1,0]+P[0,-1]+P[0,1]+P[1,0])/4)+ 0x4d*((P[-1,-1]+P[-1,1]+P[1,-1]+P[1,1])/4))>>8
Y[0,1]=(0x96*P[0,1]+ 0x4d*((P[-1,1] +P[1,1])/2)+ 0x1d*((P[0,0]+P[0,2])/2))>>8
Y[1,0]=(0x96*P[1,0]+ 0x4d*((P[1,-1]+P[1,1])/2)+ 0x1d*((P[0,0]+P[2,0])/2))>>8
Y[1,1]=(0x4d*P[1,1]+ 0x96*((P[0,1]+P[1,0]+P[1,2]+P[2,1])/4) + 0x1d*((P[0,0]+P[0,2]+P[2,0]+P[2,2])/4)))>>8
Cb and Cy are needed 1 for each 4 pixels (4:2:0)
(YC= 0.299*P[1,1]+0.587*(0.5*P[1,0]+P[0,1])+0.114*P[0,0] )
Cb=0.564*(P[0,0]-(0.299*P[1,1]+0.587*0.5*(P[1,0]+P[0,1])+0.114*P[0,0]))+128
Cr=0.713*(P[1,1]-(0.299*P[1,1]+0.587*0.5*(P[1,0]+P[0,1])+0.114*P[0,0]))+128
Cb=0.564*(P[0,0]-(0.299*P[1,1]+0.587*0.5*(P[1,0]+P[0,1])+0.114*P[0,0]))+128=
(-0x55*((P[1,0]+P[0,1])/2) -2b*P[1,1] +P[0,0]<<7)>>8+ 0x80=
(-0x55*((P[1,0]+P[0,1])/2) -2b*P[1,1])>>8 +P[0,0]>>1 +0x80=
Cr=0.713*(P[1,1]-(0.299*P[1,1]+0.587*0.5*(P[1,0]+P[0,1])+0.114*P[0,0]))+128=
(-0x6b*((P[1,0]+P[0,1])/2) +P[1,1]<<7 -0x15*P[0,0])>>8 +0x80=
(-0x6b*((P[1,0]+P[0,1])/2) -0x15*P[0,0])>>8 +P[1,1]>>1 +0x80=
----
*/ /*
For Bayer array (GB/RG)(bayer_phase[1:0]==3), and pixels P[Y,X]:
R[0,0]=0.5 *(P[-1,0]+P[1,0])
R[0,1]=0.25*(P[-1,0]+P[-1,2]+P[1,0]+P[1,2])
R[1,0]= P[1,0]
R[1,1]=0.5 *(P[1,0]+P[1,2])
G[0,0]= P[0,0]
G[0,1]=0.25*(P[-1,1]+P[0,0]+P[0,2]+P[1,1])
G[1,0]=0.25*(P[0,0]+P[1,-1]+P[1,1]+P[2,0])
G[1,1]= P[1,1]
B[0,0]=0.5* (P[0,-1]+P[0,1])
B[0,1]= P[0,1]
B[1,0]=0.25*(P[0,-1]+P[0,1]+P[2,-1]+P[2,1])
B[1,1]=0.5* (P[0,1]+P[2,1])
Y[0,0]=0.299*0.5 *(P[-1,0]+P[1,0]) + 0.587*P[0,0] + 0.114*0.5* (P[0,-1]+P[0,1])
Y[0,1]=0.299*0.25*(P[-1,0]+P[-1,2]+P[1,0]+P[1,2])+0.587*0.25*(P[-1,1]+P[0,0]+P[0,2]+P[1,1])+0.114*P[0,1]
Y[1,0]=0.299*P[1,0]+0.587*0.25*(P[0,-1]+P[0,1]+P[2,-1]+P[2,1])+0.114*0.25*(P[0,-1]+P[0,1]+P[2,-1]+P[2,1])
Y[1,1]=0.299*0.5 *(P[1,0]+P[1,2])+0.587*P[1,1]+0.114*0.5* (P[0,1]+P[2,1])
Y[0,0]=(0x96*P[0,0]+ 0x4d*((P[-1,0]+P[1,0])/2) + 0x1d*((P[0,-1]+P[0,1])/2))>>8
Y[0,1]=(0x1d*P[0,1]+ 0x96*((P[-1,1]+P[0,0]+P[0,2]+P[1,1])/4)+ 0x4d*((P[-1,0]+P[-1,2]+P[1,0]+P[1,2])/4))>>8
Y[1,0]=(0x4d*P[1,0]+ 0x96*((P[0,0]+P[1,-1]+P[1,1]+P[2,0])/4)+ 0x1d*((P[0,-1]+P[0,1]+P[2,-1]+P[2,1])/4))>>8
Y[1,1]=(0x96*P[1,1]+ 0x4d*((P[1,0]+P[1,2])/2 + 0x1d*((P[0,1] +P[2,1])/2)))>>8
Cb and Cy are needed 1 for each 4 pixels (4:2:0)
(YC= 0.299*P[1,0]+0.587*(0.5*P[1,1]+P[0,0])+0.114*P[0,1] )
Cb=0.564*(P[0,1]-(0.299*P[1,0]+0.587*0.5*(P[1,1]+P[0,0])+0.114*P[0,1]))+128
Cr=0.713*(P[1,0]-(0.299*P[1,0]+0.587*0.5*(P[1,1]+P[0,0])+0.114*P[0,1]))+128
Cb=0.564*(P[0,1]-(0.299*P[1,0]+0.587*0.5*(P[1,1]+P[0,0])+0.114*P[0,1]))+128=
(-0x55*((P[1,1]+P[0,0])/2) -2b*P[1,0] +P[0,1]<<7)>>8+ 0x80=
(-0x55*((P[1,1]+P[0,0])/2) -2b*P[1,0])>>8 +P[0,1]>>1 +0x80=
Cr=0.713*(P[1,0]-(0.299*P[1,0]+0.587*0.5*(P[1,1]+P[0,0])+0.114*P[0,1]))+128=
(-0x6b*((P[1,1]+P[0,0])/2) +P[1,0]<<7 -0x15*P[0,1])>>8 +0x80=
(-0x6b*((P[1,1]+P[0,0])/2) -0x15*P[0,1])>>8 +P[1,0]>>1 +0x80=
----
*/
/* 02/24/2003 - modified to include bypass for monochrome mode*/
/* 06/29/2004 - added counting of pixels with value of 0 and 255 (limited to 255 to use just 8 bits) */
//05.07.2008 - latency included here
module csconvert18(RST,
CLK,
mono,
limit_diff, // 1 - limit color outputs to -128/+127 range, 0 - let them be limited downstream
m_cb, // [9:0] scale for CB - default 0.564 (10'h90)
m_cr, // [9:0] scale for CB - default 0.713 (10'hb6)
din,
pre_first_in,
// strt,
signed_y, // - now signed char, -128(black) to +127 (white)
// q, // shifted by 'h80, so q=0 - is -128, q='h80 is 0, q='hff is +127
q, // new, q is just signed char
yaddr,
ywe,
caddr,
cwe,
pre_first_out,
bayer_phase,
n000,
n255);
input RST; // global reset
input CLK; // clock
input mono; // 1 - monochrome mode
input limit_diff; // 1 - limit color outputs to -128/+127 range, 0 - let them be limited downstream
input [ 9:0] m_cb; // [9:0] scale for CB - default 0.564 (10'h90)
input [ 9:0] m_cr; // [9:0] scale for CB - default 0.713 (10'hb6)
input [ 7:0] din; // input bayer data in scanline sequence, GR/BG sequence
// input strt; // marks the first input pixel - chaged to first in 3-rd row
input pre_first_in; // marks the first input pixel
output [7:0] signed_y; // output Y (16x16) in scanline sequence. Valid if ys active
// output [7:0] q; // output CbCr (8x8) each. Valid during cbs and crs
output [8:0] q; // output CbCr (8x8) each. Valid during cbs and crs
output [7:0] yaddr; // address for the external buffer memory to write 16x16x8bit Y data
output ywe; // wrire enable of Y data
output [6:0] caddr; // address for the external buffer memory 2x8x8x8bit Cb+Cr data (MSB=0 - Cb, 1 - Cr)
output cwe; // write enable for CbCr data
output pre_first_out;
input [1:0] bayer_phase;
output [7:0] n000;
output [7:0] n255;
// synthesis attribute shreg_extract of csconvert18 is yes;
wire [7:0] din;
wire ystrt,nxtline;
wire [9:0] m_cb;
wire [9:0] m_cr;
reg [7:0] yaddr; // address for the external buffer memory to write 16x16x8bit Y data
reg ywe; // wrire enable of Y data
reg [6:0] caddr; // address for the external buffer memory 2x8x8x8bit Cb+Cr data (MSB=0 - Cb, 1 - Cr)
reg cwe; // write enable for CbCr data
assign pre_first_out=ystrt;
reg odd_pix; // odd pixel (assumes even number of pixels in a line
reg odd_line; // odd line
reg pix_green;// (was "odd_pix==odd_line", now modified with bayer_phase[1:0]: bayer_phase[1]^bayer_phase[0]^(odd_pix==odd_line)
reg y_eq_0, y_eq_255;
reg [7:0] n000;
reg [7:0] n255;
wire [1:0] strt_dly;
wire strt;
reg [7:0] signed_y;
SRL16 i_strt_dly0 (.Q(strt_dly[0]), .D(pre_first_in), .CLK(CLK), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b1)); // dly=15+1
SRL16 i_strt_dly1 (.Q(strt_dly[1]), .D(strt_dly[0]), .CLK(CLK), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b1)); // dly=15+1
SRL16 i_strt (.Q(strt), .D(strt_dly[1]), .CLK(CLK), .A0(1'b0), .A1(1'b0), .A2(1'b1), .A3(1'b0)); // dly=4+1
SRL16 i_ystrt (.Q(ystrt), .D(strt), .CLK(CLK), .A0(1'b1), .A1(1'b0), .A2(1'b1), .A3(1'b0)); // dly=5+1
SRL16 i_nxtline(.Q(nxtline),.D(!RST && ywe && (yaddr[3:0]==4'hf) && (yaddr[7:4]!=4'hf)), .CLK(CLK), .A0(1'b1), .A1(1'b0), .A2(1'b0), .A3(1'b0)); // dly=1+1
always @ (posedge CLK) begin
ywe <= !RST && (ystrt || nxtline || (ywe && (yaddr[3:0]!=4'hf)));
yaddr[7:4] <= (RST || strt)? 4'h0: (nxtline?(yaddr[7:4]+1):yaddr[7:4]);
yaddr[3:0] <= ywe? (yaddr[3:0]+1):4'h0;
odd_pix <= RST || strt || ~odd_pix;
if (RST || strt) odd_line <= 1'b0;
else if (yaddr[3:0]==4'hd) odd_line <= ~odd_line;
if (RST || strt) pix_green <=bayer_phase[1]^bayer_phase[0];
else pix_green <=~(yaddr[3:0]==4'hd)^pix_green;
end
// First block generates 2 8-bit values (latency=3)- pixel (p2) and average value of previous and next pixel in the same
// row (pa). For the first pixel that "average" equals to next pixel, for the last - previous
reg [7:0] p0;
reg [7:0] p1;
reg [7:0] pd0;
reg [7:0] pa0;
wire [8:0] ppa;
always @ (posedge CLK) p0 <= din[7:0];
always @ (posedge CLK) p1 <= p0[7:0];
// always @ (posedge CLK) pd0 <= p1[7:0];
always @ (posedge RST or posedge CLK) if (RST) pd0 <= 8'b0; else pd0 <= p1[7:0]; // generates more effective than with 2-bit SRs (line above)
assign ppa[8:0]={1'b0,pd0}+{1'b0,p0};
always @ (posedge CLK) pa0 <=ppa[8:1]; //loosing 1 bit here!
// next - 2 pairs of 8 bit wide 16-bit long serial-in, serial out shift registers. Verify implementation - Should use 32 LUTs
// update 06/10/2004 - make an output pd_c[7:0] 2 cycles after pd_1[7:0] for color processing without additional resources
reg [17:0] pd_10,pd_11,pd_12,pd_13,pd_14,pd_15,pd_16,pd_17;
// reg [17:0] pd_20,pd_21,pd_22,pd_23,pd_24,pd_25,pd_26,pd_27;
reg [7:0] pd1_dly;
reg [7:0] pdc;
reg [15:0] pd_20,pd_21,pd_22,pd_23,pd_24,pd_25,pd_26,pd_27;
reg [17:0] pa_10,pa_11,pa_12,pa_13,pa_14,pa_15,pa_16,pa_17;
reg [17:0] pa_20,pa_21,pa_22,pa_23,pa_24,pa_25,pa_26,pa_27;
wire [7:0] pd1;
wire [7:0] pd2;
wire [7:0] pa1;
wire [7:0] pa2;
assign pd1={pd_17[17],pd_16[17],pd_15[17],pd_14[17],pd_13[17],pd_12[17],pd_11[17],pd_10[17]};
assign pd2={pd_27[15],pd_26[15],pd_25[15],pd_24[15],pd_23[15],pd_22[15],pd_21[15],pd_20[15]};
assign pa1={pa_17[17],pa_16[17],pa_15[17],pa_14[17],pa_13[17],pa_12[17],pa_11[17],pa_10[17]};
assign pa2={pa_27[17],pa_26[17],pa_25[17],pa_24[17],pa_23[17],pa_22[17],pa_21[17],pa_20[17]};
always @ (posedge CLK) pd_10 <= {pd_10[16:0],pd0[0]};
always @ (posedge CLK) pd_11 <= {pd_11[16:0],pd0[1]};
always @ (posedge CLK) pd_12 <= {pd_12[16:0],pd0[2]};
always @ (posedge CLK) pd_13 <= {pd_13[16:0],pd0[3]};
always @ (posedge CLK) pd_14 <= {pd_14[16:0],pd0[4]};
always @ (posedge CLK) pd_15 <= {pd_15[16:0],pd0[5]};
always @ (posedge CLK) pd_16 <= {pd_16[16:0],pd0[6]};
always @ (posedge CLK) pd_17 <= {pd_17[16:0],pd0[7]};
always @ (posedge CLK) pd1_dly[7:0] <= pd1[7:0];
always @ (posedge CLK) pdc[7:0] <= pd1_dly[7:0];
always @ (posedge CLK) pd_20 <= {pd_20[14:0],pdc[0]};
always @ (posedge CLK) pd_21 <= {pd_21[14:0],pdc[1]};
always @ (posedge CLK) pd_22 <= {pd_22[14:0],pdc[2]};
always @ (posedge CLK) pd_23 <= {pd_23[14:0],pdc[3]};
always @ (posedge CLK) pd_24 <= {pd_24[14:0],pdc[4]};
always @ (posedge CLK) pd_25 <= {pd_25[14:0],pdc[5]};
always @ (posedge CLK) pd_26 <= {pd_26[14:0],pdc[6]};
always @ (posedge CLK) pd_27 <= {pd_27[14:0],pdc[7]};
always @ (posedge CLK) pa_10 <= {pa_10[16:0],pa0[0]};
always @ (posedge CLK) pa_11 <= {pa_11[16:0],pa0[1]};
always @ (posedge CLK) pa_12 <= {pa_12[16:0],pa0[2]};
always @ (posedge CLK) pa_13 <= {pa_13[16:0],pa0[3]};
always @ (posedge CLK) pa_14 <= {pa_14[16:0],pa0[4]};
always @ (posedge CLK) pa_15 <= {pa_15[16:0],pa0[5]};
always @ (posedge CLK) pa_16 <= {pa_16[16:0],pa0[6]};
always @ (posedge CLK) pa_17 <= {pa_17[16:0],pa0[7]};
always @ (posedge CLK) pa_20 <= {pa_20[16:0],pa_10[17]};
always @ (posedge CLK) pa_21 <= {pa_21[16:0],pa_11[17]};
always @ (posedge CLK) pa_22 <= {pa_22[16:0],pa_12[17]};
always @ (posedge CLK) pa_23 <= {pa_23[16:0],pa_13[17]};
always @ (posedge CLK) pa_24 <= {pa_24[16:0],pa_14[17]};
always @ (posedge CLK) pa_25 <= {pa_25[16:0],pa_15[17]};
always @ (posedge CLK) pa_26 <= {pa_26[16:0],pa_16[17]};
always @ (posedge CLK) pa_27 <= {pa_27[16:0],pa_17[17]};
wire [7:0] pd_prev= pd2[7:0];
wire [7:0] pd_next= pd0[7:0];
wire [7:0] pa_prev= pa2[7:0];
wire [7:0] pa_next= pa0[7:0];
// now the result Y calculation depends on the pixel position (bx,by). It consists of 3 terms, each with different coefficient.
// first term always includes pd1[7:0]
// if (bx[1]==by[1]) // 00 or 11
// second term is pa1, third - (pd0+pd2)/2
// else
// second term is (pa1 + (pd0+pd2)/2)/2, third - (pa0+pa2)/2
reg [7:0] m1;
reg [7:0] m2;
reg [7:0] m3;
wire [8:0] pd02s= {1'b0,pd_prev[7:0]}+{1'b0,pd_next[7:0]}; // will use pd02s[8:1]
wire [8:0] pa1pd02s={1'b0,pa1[7:0]}+{1'b0,pd02s[8:1]}; // will use pa1pd02s[8:1]
wire [8:0] pa02s= {1'b0,pa_prev[7:0]}+{1'b0,pa_next[7:0]}; // will use pa02s[8:1]
always @ (posedge CLK) m1 <= pd1[7:0];
// always @ (posedge CLK) m2 <= (odd_pix==odd_line)? pa1[7:0] : pa1pd02s[8:1];
// always @ (posedge CLK) m3 <= (odd_pix==odd_line)? pd02s[8:1] : pa02s[8:1];
always @ (posedge CLK) m2 <= pix_green? pa1[7:0] : pa1pd02s[8:1];
always @ (posedge CLK) m3 <= pix_green? pd02s[8:1] : pa02s[8:1];
/*
Y[0,0]=(0x96*P[0,0]+ 0x4d*((P[0,-1]+P[0,1])/2) + 0x1d*((P[-1,0]+P[1,0])/2))>>8
Y[0,1]=(0x4d*P[0,1]+ 0x96*((P[-1,1]+P[0,0]+P[0,2]+P[1,1])/4)+ 0x1d*((P[-1,0]+P[-1,2]+P[1,0]+P[1,2])/4))>>8
Y[1,0]=(0x1d*P[1,0]+ 0x96*((P[0,0]+P[1,-1]+P[1,1]+P[2,0])/4)+ 0x4d*((P[0,-1]+P[0,1]+P[2,-1]+P[2,1])/4))>>8
Y[1,1]=(0x96*P[1,1]+ 0x1d*((P[1,0]+P[1,2])/2 + 0x4d*((P[0,1] +P[2,1])/2)))>>8
+-----+--------+-------+-------+-------+-------+-------+
| | (0) | | | * | * | * * |
| | G R | * | * + * | + | * + * | + |
| | B G | | | * | * | * * |
+-----+--------+-------+-------+-------+-------+-------+
| 0 | P[0,0] | 0x96 | 0x4d | 0x1d | | |
| +--------+-------+-------+-------+-------+-------+
| G R | P[0,1] | 0x4d | | | 0x96 | 0x1d |
| +--------+-------+-------+-------+-------+-------+
| B G | P[1,0] | 0x1d | | | 0x96 | 0x4d |
| +--------+-------+-------+-------+-------+-------+
| | P[1,1] | 0x96 | 0x1d | 0x4d | | |
+-----+--------+-------+-------+-------+-------+-------+
| 1 | P[0,0] | 0x4d | | | 0x96 | 0x1d |
| +--------+-------+-------+-------+-------+-------+
| R G | P[0,1] | 0x96 | 0x4d | 0x1d | | |
| +--------+-------+-------+-------+-------+-------+
| G B | P[1,0] | 0x96 | 0x1d | 0x4d | | |
| +--------+-------+-------+-------+-------+-------+
| | P[1,1] | 0x1d | | | 0x96 | 0x4d |
+-----+--------+-------+-------+-------+-------+-------+
| 2 | P[0,0] | 0x1d | | | 0x96 | 0x4d |
| +--------+-------+-------+-------+-------+-------+
| B G | P[0,1] | 0x96 | 0x1d | 0x4d | | |
| +--------+-------+-------+-------+-------+-------+
| G R | P[1,0] | 0x96 | 0x4d | 0x1d | | |
| +--------+-------+-------+-------+-------+-------+
| | P[1,1] | 0x4d | | | 0x96 | 0x1d |
+-----+--------+-------+-------+-------+-------+-------+
| 3 | P[0,0] | 0x96 | 0x1d | 0x4d | | |
| +--------+-------+-------+-------+-------+-------+
| G B | P[0,1] | 0x1d | | | 0x96 | 0x4d |
| +--------+-------+-------+-------+-------+-------+
| R G | P[1,0] | 0x4d | | | 0x96 | 0x1d |
| +--------+-------+-------+-------+-------+-------+
| | P[1,1] | 0x96 | 0x4d | 0x1d | | |
+-----+--------+-------+-------+-------+-------+-------+
*/
reg [7:0] k1;
reg [7:0] k2;
reg [7:0] k3;
always @ (posedge CLK) case ({bayer_phase[1:0],odd_line,odd_pix})
// 0 - GR/BG
4'b0000: begin
k1<=8'h96;
k2<=8'h4d;
k3<=8'h1d;
end
4'b0001: begin
k1<=8'h4d;
k2<=8'h96;
k3<=8'h1d;
end
4'b0010: begin
k1<=8'h1d;
k2<=8'h96;
k3<=8'h4d;
end
4'b0011: begin
k1<=8'h96;
k2<=8'h1d;
k3<=8'h4d;
end
// 1 - RG/GB
4'b0100: begin
k1<=8'h4d;
k2<=8'h96;
k3<=8'h1d;
end
4'b0101: begin
k1<=8'h96;
k2<=8'h4d;
k3<=8'h1d;
end
4'b0110: begin
k1<=8'h96;
k2<=8'h1d;
k3<=8'h4d;
end
4'b0111: begin
k1<=8'h1d;
k2<=8'h96;
k3<=8'h4d;
end
// 2 - BG/GR
4'b1000: begin
k1<=8'h1d;
k2<=8'h96;
k3<=8'h4d;
end
4'b1001: begin
k1<=8'h96;
k2<=8'h1d;
k3<=8'h4d;
end
4'b1010: begin
k1<=8'h96;
k2<=8'h4d;
k3<=8'h1d;
end
4'b1011: begin
k1<=8'h4d;
k2<=8'h96;
k3<=8'h1d;
end
// 3 - GB/RG
4'b1100: begin
k1<=8'h96;
k2<=8'h1d;
k3<=8'h4d;
end
4'b1101: begin
k1<=8'h1d;
k2<=8'h96;
k3<=8'h4d;
end
4'b1110: begin
k1<=8'h4d;
k2<=8'h96;
k3<=8'h1d;
end
4'b1111: begin
k1<=8'h96;
k2<=8'h4d;
k3<=8'h1d;
end
endcase
wire [15:0] mm1=m1[7:0]*k1[7:0];
wire [15:0] mm2=m2[7:0]*k2[7:0];
wire [15:0] mm3=m3[7:0]*k3[7:0];
reg [7:0] y;
reg [7:0] y0; // bypass in monochrome mode
// wire [7:0] y0; // bypass in monochrome mode
reg [15:0] y1,y2,y3;
wire [15:0] y_sum =y1+y2+y3;
always @ (posedge CLK) y0 <= m1;
always @ (posedge CLK) y1 <= mm1;
always @ (posedge CLK) y2 <= mm2;
always @ (posedge CLK) y3 <= mm3;
// making y output signed -128..+127
wire [7:0] pre_y= mono ? y0 : (y_sum[15:8]+y_sum[7]);
always @ (posedge CLK) y[7:0] <= pre_y[7:0];
always @ (posedge CLK) signed_y[7:0] <= {~pre_y[7], pre_y[6:0]};
// Try easier and hope better algorithm of color extractions that should perform better on gradients.
// It will rely on the fact that Y is already calculated, so instead of processing 4 pixels it will
// calculate Cb for "B" pixel, and Cr - for "R", subtracting calculated "Y" for that pixel.
//Cb = 0.564*(B-Y)+128
//Cr = 0.713*(R-Y)+128
// First - delay pd1[7:0] by 2 clock periods - to match "Y" output (one ahead, actually)
// It is better to implement it earlier - while calculating pd2 - anyway it had to be delayed by 18 (16+2) form pd1 - make it in 2 stages 2 +16
// pdc[7:0] - one cycle ahead of the "Y" for each pixel
// Try multiplication by constant without the register for that constant, just 2:1 mux. Still use aregister for the other operand (is it needed?)
reg [7:0] cbcrmult1;
//wire [7:0] cbcrmult2; // 1 of 2 constants - should be valid during ywe and 1 more cycle ("use_cr"
wire [9:0] cbcrmult2; // 1 of 2 constants - should be valid during ywe and 1 more cycle ("use_cr"
//wire [15:0] cbcrmulto; // output of 8x8 multiplier
wire [17:0] cbcrmulto; // output of 8x8 multiplier
// ignoring overflow we do not need extra bits
// high saturation can cause overflow, but we have very limited resources in model 313 to port back to
//reg [8:0] cbcrmultr; // 1 extra bit for precision (before subtraction)
reg [10:0] cbcrmultr; // 1 extra bit for precision (before subtraction)
//reg [8:0] cbcr; // after subraction (with extra bit preserved)
reg [10:0] cbcr; // after subraction (with extra bit preserved)
reg sel_cbcrmult1; // 0 - use pdc[7:0], 1 - use y[7:0]. Should be valid 1 cycle ahead of ywe!
reg use_cr; // in this line cr is calculated. Valid during ywe and 1 cycle after
reg sub_y; // output accumulator/subtractor. 0 - load new data, 1 - subtract. Walid 2 cycles after ywe
wire cwe0; // preliminary cwe (to be modulated by odd/even pixels)
reg cstrt; //ystrt dealyed by 1
reg cnxt; // nxtline delayed by 1
always @ (posedge CLK) begin
if (~(ywe || ystrt || nxtline)) sel_cbcrmult1 <= ~(bayer_phase[1] ^ bayer_phase[0] ^ odd_line);
else sel_cbcrmult1 <= ~sel_cbcrmult1;
sub_y <= ~sel_cbcrmult1;
cbcrmult1 <= sel_cbcrmult1?y[7:0]:pdc[7:0];
cbcrmult1 <= sel_cbcrmult1?y[7:0]:pdc[7:0];
if (~ywe) use_cr <= ~(bayer_phase[1] ^ odd_line);
end
assign cbcrmult2=use_cr?m_cr:m_cb; // maybe will need a register? (use_cr will still be good as it is valid early)
assign cbcrmulto=cbcrmult1*cbcrmult2;
// will preserve extra bit, but do not need to add half of the truncated MSB - on average there will be no shift after subtraction
always @ (posedge CLK) begin
// cbcrmultr[8:0] <= cbcrmulto[15:7];
cbcrmultr[10:0] <= cbcrmulto[17:7];
// cbcr[8:0] <= sub_y? (cbcr[8:0]-cbcrmultr[8:0]+ 1'b1):cbcrmultr[8:0];
cbcr[10:0] <= sub_y? (cbcr[10:0]-cbcrmultr[10:0]+ 1'b1):cbcrmultr[10:0];
end
// assign q[7:0]= {~cbcr[8],cbcr[7:1]}; // -128, discarded extra bit (need truncating?)
//limit_diff
// Here 0 is shifted to 0x80
/*
assign q[7:0]= cbcr[10]? ((cbcr[9:8]==2'h3)?{1'b0,cbcr[7:1]}:8'h00):
((cbcr[9:8]==2'h0)?{1'b1,cbcr[7:1]}:8'hff);
*/
// new, q is signed char
assign q[8:0]= ((cbcr[10]==cbcr[9]) && (!limit_diff || (cbcr[10]==cbcr[8])))? cbcr[9:1]: {cbcr[10],limit_diff?cbcr[10]:(~cbcr[10]),{7{~cbcr[10]}}};
SRL16 i_cwe0 (.D(ywe ), .Q(cwe0), .A0(1'b1), .A1(1'b0), .A2(1'b0), .A3(1'b0), .CLK(CLK)); // dly=2=1+1
always @ (posedge CLK) begin
cstrt <= ystrt;
cnxt <= nxtline;
cwe <= cwe0 && sub_y;
caddr[2:0]<= cwe0?(caddr[2:0]+cwe):3'b0;
// if (cstrt) caddr[6:3] <={~bayer_phase[1],3'b0};
// else if (cnxt) caddr[6:3] <={~caddr[6],caddr[5:3]+(bayer_phase[1]^caddr[6])};
if (cstrt) caddr[6] <= ~bayer_phase[1];
else if (cnxt) caddr[6] <= ~caddr[6];
if (cstrt) caddr[5:3] <=3'b0;
else if (cnxt) caddr[5:3] <=(bayer_phase[1]^caddr[6])? caddr[5:3]:(caddr[5:3]+1);
end
always @ (posedge CLK) begin
y_eq_0 <= (y0[7:0] == 8'h0);
y_eq_255 <= (y0[7:0] == 8'hff);
if (strt) n000[7:0] <= 8'h0;
else if ((n000[7:0]!=8'hff) && y_eq_0 && ywe) n000[7:0] <= n000[7:0]+1;
if (strt) n255[7:0] <= 8'h0;
else if ((n255[7:0]!=8'hff) && y_eq_255 && ywe) n255[7:0] <= n255[7:0]+1;
end
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/csconvert_mono.v 0000664 0000000 0000000 00000025103 12555570767 0024672 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** csconvert_mono.v
**
** Monochrome and JP4 modules inplace of color converter ones
**
** Copyright (C) 2008 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X333 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
module csconvert_mono (en,
clk,
din,
pre_first_in,
y_out,
yaddr,
ywe,
pre_first_out);
input en;
input clk; // clock
input [7:0] din; // input data in scanline sequence
input pre_first_in; // marks the first input pixel
output [7:0] y_out; // output Y (16x16) in scanline sequence. Valid if ys active
output [7:0] yaddr; // address for the external buffer memory to write 16x16x8bit Y data
output ywe; // wrire enable of Y data
output pre_first_out;
wire pre_first_out= pre_first_in;
// wire [7:0] y_out= din[7:0];
wire [7:0] y_out= {~din[7],din[6:0]};
reg [7:0] yaddr;
reg ywe;
always @ (posedge clk) begin
ywe <= en & (pre_first_in || (ywe && (yaddr[7:0] !=8'hff)));
if (!en || pre_first_in) yaddr[7:0] <= 8'h0;
else if (ywe) yaddr[7:0] <= yaddr[7:0] + 1;
end
endmodule
module csconvert_jp4 (en,
clk,
din,
pre_first_in,
y_out,
yaddr,
ywe,
pre_first_out);
input en;
input clk; // clock
input [7:0] din; // input data in scanline sequence
input pre_first_in; // marks the first input pixel
output [7:0] y_out; // output Y (16x16) in scanline sequence. Valid if ys active
output [7:0] yaddr; // address for the external buffer memory to write 16x16x8bit Y data
output ywe; // wrire enable of Y data
output pre_first_out;
wire pre_first_out= pre_first_in;
// wire [7:0] y_out= din[7:0];
wire [7:0] y_out= {~din[7],din[6:0]};
reg [7:0] yaddr_cntr;
reg ywe;
wire [7:0] yaddr= {yaddr_cntr[4],yaddr_cntr[7:5],yaddr_cntr[0],yaddr_cntr[3:1]};
always @ (posedge clk) begin
ywe <= en & (pre_first_in || (ywe && (yaddr[7:0] !=8'hff)));
if (!en || pre_first_in) yaddr_cntr[7:0] <= 8'h0;
else if (ywe) yaddr_cntr[7:0] <= yaddr_cntr[7:0] + 1;
end
endmodule
module csconvert_jp4diff (en,
clk,
scale_diff, // divide differences by 2 (to fit in 8-bit range)
hdr, // second green absolute, not difference
din,
pre_first_in,
y_out,
yaddr,
ywe,
pre_first_out,
bayer_phase);
// synthesis attribute shreg_extract of csconvert_jp4diff is yes;
input en;
input clk; // clock
input scale_diff;
input hdr;
input [7:0] din; // input data in scanline sequence
input pre_first_in; // marks the first input pixel
output [8:0] y_out; // output Y (16x16) in scanline sequence. Valid if ys active
output [7:0] yaddr; // address for the external buffer memory to write 16x16x8bit Y data
output ywe; // wrire enable of Y data
output pre_first_out;
input [1:0] bayer_phase; // selected pixel will be absolute, others - difference
reg pre_first_out;
reg [2:0] pre2_first_out;
reg [8:0] y_out;
reg [8:0] pre_y_out;
reg [7:0] yaddr_cntr;
reg [7:0] pre_yaddr_cntr;
reg [7:0] pre2_yaddr_cntr;
// reg [7:0] icntr;
reg ywe;
reg [2:0] pre_ywe;
reg [7:0] yaddr;
// reg [4:0] out_dly;
reg dly_1;
reg [14:0] dly_16;
reg dly_17;
// wire start_out=bayer_phase[1]?(bayer_phase[0]?dly_17:dly_16):(bayer_phase[0]?dly_1:pre_first_in);
///AF2015 - What was supposed to be here for "dly_16" (15 bits, expected 1) - any non-zero or [14]?
// wire start_out=bayer_phase[1]?(bayer_phase[0]?dly_17: (|dly_16)):(bayer_phase[0]?dly_1:pre_first_in);
wire start_out=bayer_phase[1]?(bayer_phase[0]?dly_17: dly_16[14]):(bayer_phase[0]?dly_1:pre_first_in);
reg [7:0] iadr;
reg iadr_run;
reg [1:0] mux_plus_sel;
reg [2:0] mux_minus_sel;
reg hdr_bit;
reg [1:0] scale_color;
reg [1:0] is_color;
reg [7:0] mux_plus;
reg [7:0] mux_minus;
reg [7:0] dd0;
reg [7:0] dd1;
wire [7:0] dd16;
reg [7:0] dd17;
reg [14:0] ddsr0,ddsr1,ddsr2,ddsr3,ddsr4,ddsr5,ddsr6,ddsr7;
wire [8:0] scaled_pre_y_out= (scale_color[1])? +{pre_y_out[8],pre_y_out[8:1]}: pre_y_out[8:0];
assign dd16[7:0]={ddsr7[14],ddsr6[14],ddsr5[14],ddsr4[14],ddsr3[14],ddsr2[14],ddsr1[14],ddsr0[14]};
always @ (posedge clk) begin
dly_1 <= pre_first_in;
dly_17 <= dly_16[14];
dly_16[14:0] <= {dly_16[13:0],dly_1};
pre2_first_out[2:0]<= {pre2_first_out[1:0], start_out};
pre_first_out<= pre2_first_out[2];
iadr_run <= en & (start_out || (iadr_run && (iadr[7:0]!=8'hff)));
pre_ywe[2:0] <= {pre_ywe[1:0],iadr_run};
ywe <= pre_ywe[2];
if (!en || start_out) iadr[7:0] <= 8'h0;
else if (iadr_run) iadr[7:0] <= iadr[7:0] + 1;
pre2_yaddr_cntr[7:0] <= iadr[7:0];
pre_yaddr_cntr [7:0] <= pre2_yaddr_cntr[7:0];
yaddr_cntr[7:0] <= pre_yaddr_cntr[7:0];
yaddr[7:0] <= {yaddr_cntr[4],yaddr_cntr[7:5],yaddr_cntr[0],yaddr_cntr[3:1]};
case ({bayer_phase[1:0],iadr[4],iadr[0]} )
4'b0000: begin mux_plus_sel <= 2'h0; mux_minus_sel <= 3'h4; hdr_bit <=1'h0; end
4'b0001: begin mux_plus_sel <= 2'h0; mux_minus_sel <= 3'h1; hdr_bit <=1'h0; end
4'b0010: begin mux_plus_sel <= 2'h0; mux_minus_sel <= 3'h2; hdr_bit <=1'h0; end
4'b0011: begin mux_plus_sel <= 2'h0; mux_minus_sel <= 3'h3; hdr_bit <=1'h1; end
4'b0100: begin mux_plus_sel <= 2'h1; mux_minus_sel <= 3'h0; hdr_bit <=1'h0; end
4'b0101: begin mux_plus_sel <= 2'h1; mux_minus_sel <= 3'h4; hdr_bit <=1'h0; end
4'b0110: begin mux_plus_sel <= 2'h1; mux_minus_sel <= 3'h2; hdr_bit <=1'h1; end
4'b0111: begin mux_plus_sel <= 2'h1; mux_minus_sel <= 3'h3; hdr_bit <=1'h0; end
4'b1000: begin mux_plus_sel <= 2'h2; mux_minus_sel <= 3'h0; hdr_bit <=1'h0; end
4'b1001: begin mux_plus_sel <= 2'h2; mux_minus_sel <= 3'h1; hdr_bit <=1'h1; end
4'b1010: begin mux_plus_sel <= 2'h2; mux_minus_sel <= 3'h4; hdr_bit <=1'h0; end
4'b1011: begin mux_plus_sel <= 2'h2; mux_minus_sel <= 3'h3; hdr_bit <=1'h0; end
4'b1100: begin mux_plus_sel <= 2'h3; mux_minus_sel <= 3'h0; hdr_bit <=1'h1; end
4'b1101: begin mux_plus_sel <= 2'h3; mux_minus_sel <= 3'h1; hdr_bit <=1'h0; end
4'b1110: begin mux_plus_sel <= 2'h3; mux_minus_sel <= 3'h2; hdr_bit <=1'h0; end
4'b1111: begin mux_plus_sel <= 2'h3; mux_minus_sel <= 3'h4; hdr_bit <=1'h0; end
endcase
/*
if (pre_ywe[0]) case (mux_plus_sel[1:0])
2'h0: mux_plus[7:0] <= dd17[7:0];
2'h1: mux_plus[7:0] <= dd16[7:0];
2'h2: mux_plus[7:0] <= dd1 [7:0];
2'h3: mux_plus[7:0] <= dd0 [7:0];
endcase
if (pre_ywe[0]) casex ({mux_minus_sel[2] | (hdr_bit & hdr), mux_minus_sel[1:0]})
3'h0: mux_minus[7:0] <= dd17[7:0];
3'h1: mux_minus[7:0] <= dd16[7:0];
3'h2: mux_minus[7:0] <= dd1 [7:0];
3'h3: mux_minus[7:0] <= dd0 [7:0];
3'b1xx: mux_minus[7:0] <= 8'h0;
endcase
*/
if (pre_ywe[0]) case (mux_plus_sel[1:0])
2'h0: mux_plus[7:0] <= dd0 [7:0];
2'h1: mux_plus[7:0] <= dd1 [7:0];
2'h2: mux_plus[7:0] <= dd16[7:0];
2'h3: mux_plus[7:0] <= dd17[7:0];
endcase
if (pre_ywe[0]) casex ({mux_minus_sel[2] | (hdr_bit & hdr), mux_minus_sel[1:0]})
3'h0: mux_minus[7:0] <= dd0 [7:0];
3'h1: mux_minus[7:0] <= dd1 [7:0];
3'h2: mux_minus[7:0] <= dd16[7:0];
3'h3: mux_minus[7:0] <= dd17[7:0];
3'b1xx: mux_minus[7:0] <= 8'h0;
endcase
is_color[1:0] <= {is_color[0], ~(mux_minus_sel[2] | (hdr_bit & hdr))}; // 1 for color components (diffs) ([0] valid at pre_ywe[1])
scale_color[1:0] <= {scale_color[0], ~(mux_minus_sel[2] | (hdr_bit & hdr)) & scale_diff}; // 1 for color components (diffs) ([0] valid at pre_ywe[1])
if (pre_ywe[1]) pre_y_out[8:0] <= {1'b0,mux_plus[7:0]} - {1'b0,mux_minus[7:0]};
// if (scaled_pre_y_out[8]==scaled_pre_y_out[7]) y_out[7:0] <= (scaled_pre_y_out[7:0]^ 8'h80); // limit differences by 0/ff
// else y_out[7:0] <= scaled_pre_y_out[8]?8'h0:8'hff;
y_out[8:0] <= scaled_pre_y_out[8:0] - {1'h0, ~is_color[1],7'h0}; // subtract 0x80 from Y components (make them -128+127)
dd0[7:0] <= din [7:0];
dd1[7:0] <= dd0 [7:0];
ddsr0[14:0] <= {ddsr0[13:0],dd1[0]};
ddsr1[14:0] <= {ddsr1[13:0],dd1[1]};
ddsr2[14:0] <= {ddsr2[13:0],dd1[2]};
ddsr3[14:0] <= {ddsr3[13:0],dd1[3]};
ddsr4[14:0] <= {ddsr4[13:0],dd1[4]};
ddsr5[14:0] <= {ddsr5[13:0],dd1[5]};
ddsr6[14:0] <= {ddsr6[13:0],dd1[6]};
ddsr7[14:0] <= {ddsr7[13:0],dd1[7]};
dd17[7:0] <= dd16 [7:0];
end
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/encoderDCAC353.v 0000664 0000000 0000000 00000016627 12555570767 0024134 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** encoderDCAC353.v
**
** RLL encoder for JPEG compressor
**
** Copyright (C) 2002-2008 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
// Accepts 13-bits signed data (only 12-bit can be ecoded), so DC difference (to be encoded) is limited (saturated) to 12 bits, not the value itself
// AC - always limited to 800 .. 7ff
module encoderDCAC(clk,
en,
// firsti, // was "first MCU in a frame" (@ stb)
lasti, // was "last MCU in a frame" (@ stb)
first_blocki, // first block in frame - save fifo write address (@ stb)
comp_numberi, // [2:0] component number 0..2 in color, 0..3 - in jp4diff, >= 4 - don't use (@ stb)
comp_firsti, // fitst this component in a frame (reset DC) (@ stb)
comp_colori, // use color - huffman? (@ stb)
comp_lastinmbi, // last component in a macroblock (@ stb) is it needed?
stb, // strobe that writes firsti, lasti, tni,average
zdi, // [11:0] zigzag-reordered data input
first_blockz, // first block input (@zds)
zds, // strobe - one ahead of the DC component output
last, //
do,
dv
);
input clk;
input en;
// input firsti;
input lasti;
input first_blocki; // first block in frame - save fifo write address (@ stb)
input [2:0] comp_numberi; // [2:0] component number 0..2 in color, 0..3 - in jp4diff, >= 4 - don't use (@ stb)
input comp_firsti; // fitst this component in a frame (reset DC) (@ stb)
input comp_colori; // use color - huffman? (@ stb)
input comp_lastinmbi; // last component in a macroblock (@ stb)
input stb;
input [12:0] zdi;
input first_blockz; // first block input (@zds)
input zds;
output last;
output [15:0] do;
output dv;
// reg [2:0] ic;
// reg [2:0] oc;
reg last;
// 8x13 DC storage memory
reg [12:0] dc_mem[7:0];
reg [12:0] dc_diff0, dc_diff;
wire [11:0] dc_diff_limited= (dc_diff[12]==dc_diff[11])? dc_diff[11:0] : {~dc_diff[11],{11{dc_diff[11]}}}; // difference (to be encoded) limited to fit 12 bits
reg [12:0] dc_restored; // corrected DC value of the current block, compensated to fit difference to 12 bits
reg [5:0] rll_cntr;
reg [15:0] do;
// reg dv0;
reg dv;
//
reg [5:0] cntr;
// reg ac_on;
reg [11:0] ac_in;
wire izero=(ac_in[11:0]==12'b0);
reg [14:0] val_r; // DC diff/AC values to be sent out, registered
reg DCACen; // enable DC/AC (2 cycles ahead of do
wire rll_out;
// wire eob_out;
wire pre_dv;
reg was_nonzero_AC;
reg [12:0] zdi_d;
reg [3:0] zds_d;
// wire dc_mem_we= zds_d[3]; // not needed
wire DC_tosend= zds_d[2];
wire pre_DCACen= zds_d[1];
wire [2:0] comp_numbero; // [2:0] component number 0..2 in color, 0..3 - in jp4diff, >= 4 - don't use
wire comp_firsto; // first this component in a frame (reset DC)
wire comp_coloro; // use color - huffman?
// wire first_blocko; // first block in frame - save fifo write address
wire comp_lastinmbo; // last component in a macroblock
wire lasto; // last macroblock in a frame
reg [2:0] block_mem_ra;
reg [2:0] block_mem_wa;
reg [2:0] block_mem_wa_save;
reg [6:0] block_mem[0:7];
wire [6:0] block_mem_o=block_mem[block_mem_ra[2:0]];
assign comp_numbero[2:0]= block_mem_o[2:0];
assign comp_firsto= block_mem_o[3];
assign comp_coloro= block_mem_o[4];
// assign first_blocko= block_mem_o[5];
assign comp_lastinmbo= block_mem_o[5];
assign lasto= block_mem_o[6];
always @ (posedge clk) begin
if (stb) block_mem[block_mem_wa[2:0]] <= {lasti, comp_lastinmbi, /*first_blocki,*/ comp_colori,comp_firsti,comp_numberi[2:0]};
if (!en) block_mem_wa[2:0] <= 3'h0;
else if (stb) block_mem_wa[2:0] <= block_mem_wa[2:0] +1;
if (stb && first_blocki) block_mem_wa_save[2:0] <= block_mem_wa[2:0];
if (!en) block_mem_ra[2:0] <= 3'h0;
else if (zds) block_mem_ra[2:0] <= first_blockz?block_mem_wa_save[2:0]:(block_mem_ra[2:0] +1);
end
assign rll_out= ((val_r[12] && !val_r[14]) || (ac_in[11:0]!=12'b0)) && (rll_cntr[5:0]!=6'b0);
assign pre_dv=rll_out || val_r[14] || was_nonzero_AC;
always @ (posedge clk) begin
val_r[14:0] <={ DC_tosend?
{en,
comp_coloro,
comp_lastinmbo && lasto, // last component's in a frame DC coefficient
dc_diff_limited[11:0]}:
{2'b0,
(cntr[5:0]==6'h3f),
ac_in[11:0]}};
was_nonzero_AC <= en && (ac_in[11:0]!=12'b0) && DCACen;
if (pre_dv) do <= rll_out? {3'b0,val_r[12],6'b0,rll_cntr[5:0]}:{1'b1,val_r[14:0]};
dv <= pre_dv;
DCACen <= en && (pre_DCACen || (DCACen && (cntr[5:0]!=6'h3f))); // adjust
if (!DCACen) cntr[5:0] <=6'b0;
else cntr[5:0] <=cntr[5:0]+1;
end
always @ (posedge clk) begin
zdi_d[12:0] <= zdi[12:0];
ac_in[11:0] <= (zdi_d[12]==zdi_d[11])? zdi_d[11:0]:{~zdi_d[11],{11{zdi_d[11]}}}; // always // delay + saturation
if (DC_tosend || !izero || !DCACen) rll_cntr[5:0] <= 6'h0;
else if (DCACen) rll_cntr[5:0] <= rll_cntr[5:0] +1 ;
if (DC_tosend) last <= lasto;
end
// DC components
always @ (posedge clk) begin
zds_d[3:0] <= {zds_d[2:0], zds};
if (zds_d[0]) dc_diff0[12:0] <= comp_firsto?13'b0:dc_mem[comp_numbero[2:0]];
if (zds_d[1]) dc_diff [12:0] <= zdi_d[12:0]-dc_diff0[12:0];
if (zds_d[2]) dc_restored[12:0] <= dc_diff0[12:0] + {dc_diff_limited[11],dc_diff_limited[11:0]};
if (zds_d[3]) dc_mem[comp_numbero[2:0]] <= dc_restored[12:0];
end
// Generate output stream to facilitate huffman encoding. The data will go to FIFO (16x) to compensate for possible long Huffman codes
// and/or zero-byte insertions
// format:
// {2'b11, color,last block, dc[11:0]} - DC data
// {2'b10, 1'b0, last coeff, ac[11:0]} - AC data (last coeff is set if it is last- 63-rd AC coefficient)
// {2'h00, 2'b00, 6'b0,rll[ 5:0]} - RLL zeroes.
// {2'h00, 2'b01, 6'b0,rll[ 5:0]} - end of block. lower 6 bits will have length that should be ignored
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/focus_sharp.v 0000664 0000000 0000000 00000036151 12555570767 0024155 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** focus_sharp.v
**
** Module to determine focus sharpness on by integrating
** DCT coefficient, multiplied my 8x8 array and squared
**
** Copyright (C) 2008 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
`timescale 1ns/1ps
//TODO: Modify to work with other modes (now only on color)
module focus_sharp(clk, // pixel clock
en, // enable (0 resets counter)
sclk, // system clock, twe, ta,tdi - valid @negedge (ra, tdi - 2 cycles ahead
twe, // enable write to a table
ta, // [9:0] table address
tdi, // [15:0] table data in (8 LSBs - quantization data)
mode, // focus mode (combine image with focus info) - 0 - none, 1 - replace, 2 - combine all, 3 - combine woi
firsti, // first macroblock
lasti, // last macroblock
tni, // block number in a macronblock - 0..3 - Y, >=4 - color (sync to stb)
stb, // strobe that writes ctypei, dci
start,// marks first input pixel (needs 1 cycle delay from previous DCT stage)
di, // [11:0] pixel data in (signed)
quant_ds, //quantizator ds
quant_d, //[11:0]quantizator data output
quant_dc_tdo, //[15:0], MSB aligned coefficient for the DC component (used in focus module)
// quant_dc_tdo_stb,
do, // [11:0] pixel data out, make timing ignore (valid 1.5 clk earlier that Quantizer output)
ds, // data out strobe (one ahead of the start of dv)
hifreq //[31:0]) // accumulated high frequency components in a frame sub-window
);
input clk;
input en;
input sclk;
input twe;
input [ 9:0] ta;
input [15:0] tdi;
input [ 1:0] mode;
input firsti; // first macroblock (sync to stb)
input lasti; // last macroblock (sync to stb)
input [ 2:0] tni; // block number in a macronblock - 0..3 - Y, >=4 - color (sync to stb)
input stb; // strobe that writes ctypei, dci
input start;
input [12:0] di;
input quant_ds;
input [12:0] quant_d;
input [15:0] quant_dc_tdo; // MSB aligned coefficient for the DC component (used in focus module)
// input quant_dc_tdo_stb;
output[12:0] do;
output ds;
output [31:0] hifreq;
wire [15:0] tdo;
reg [ 5:0] tba;
reg [11:0] wnd_reg; // intermediate register
reg wnd_wr; // writing window
reg [ 2:0] wnd_a; // window register address
// next measured in 8x8 blocks, totalwidth - write one less than needed (i.e. 511 fro the 512-wide window)
// blocks on the border are included
reg [ 8:0] wnd_left;
reg [ 8:0] wnd_right;
reg [ 8:0] wnd_top;
reg [ 8:0] wnd_bottom;
reg [ 8:1] wnd_totalwidth;
reg [ 3:0] filt_sel0; // select filter number, 0..14 (15 used for window parameters)
reg [ 3:0] filt_sel; // select filter number, 0..14 (15 used for window parameters)
reg stren; // strength (visualization)
// if (dcc_stb) dcc_first <= color_first && dcc_run && dcc_stb && ctype && !ctype_prev[0];
reg [ 2:0] ic;
reg [ 2:0] oc;
wire first,last; //valid at start (with first di word), switches immediately after
wire [ 2:0] tn;
reg [31:0] hifreq;
reg [39:0] acc_frame;
// reg [11:0] do; // combined quantizator/focus output
reg [12:0] do; // combined quantizator/focus output
reg [12:0] pre_do;
reg pre_ds;
reg need_corr_max; // limit output by quant_dc_tdo
reg [11:0] fdo; // focus data output
reg ds;
reg start_d; //start delayed by 1
reg [ 2:0] tn_d; //tn delayed by 1
wire out_mono;
wire out_window;
wire [12:0] combined_qf;
wire [12:0] next_do;
wire [12:0] fdo_minus_max;
reg [11:0] di_d;
reg [11:0] d1;
// reg [9:0] start2;
reg [8:0] start2;
// reg [8:0] finish2;
reg [7:0] finish2;
reg [5:0] use_k_dly;
reg [23:0] acc_blk; // accumulator for the sum ((a[i]*d[i])^2)
reg [22:0] sum_blk; // accumulator for the sum ((a[i]*d[i])^2), copied at block end
reg acc_ldval; // value to load to acc_blk: 0 - 24'h0, 1 - 24'h7fffff
wire acc_clear=start2[8];
wire acc_add=use_k_dly[4];
wire acc_corr=use_k_dly[5];
// wire use_prod=use_k_dly[2] ;// feed multiplier input regs with the delayed product
wire acc_to_out=finish2[6];
wire [17:0] mult_a;
wire [17:0] mult_b;
wire [35:0] mult_p;
reg [17:0] mult_s; //truncated and saturated (always positive) multiplier result (before calculating squared)
reg next_ac; // next will be AC component
reg use_coef; // use multiplier for the first operation - DCT coeff. by table elements
reg started_luma;// started Luma block
reg luma_dc_out; // 1 cycle ahead of the luma DC component out (optionally combined with the WOI (mode=3))
reg luma_dc_acc; // 1 cycle ahead of the luma DC component out (always combined with the WOI)
reg was_last_luma;
reg copy_acc_frame;
assign fdo_minus_max[12:0]= {1'b0,fdo[11:0]}-{1'b0,quant_dc_tdo[15:5]};
/*
assign combined_qf[12:0]=stren?({quant_d[11],quant_d[11:0]}+{1'b0,fdo[11:0]}): //original image plus positive
({quant_d[11],quant_d[11],quant_d[11:1]}+ // half original
{fdo_minus_max[12],fdo_minus_max[12:1]}); // plus half signed
assign next_do[12:0] = (mode[1:0]==2'h1)?(luma_dc_out?fdo_minus_max[12:0]:13'h0):
((mode[1] && luma_dc_out )? combined_qf[12:0]: {1'b0,quant_d[11:0]} );
*/
assign combined_qf[12:0]=stren?({quant_d[12:0]}+{1'b0,fdo[11:0]}): //original image plus positive
({quant_d[12],quant_d[12:1]}+ // half original
{fdo_minus_max[12],fdo_minus_max[12:1]}); // plus half signed
assign next_do[12:0] = (mode[1:0]==2'h1)?(luma_dc_out?fdo_minus_max[12:0]:13'h0):
((mode[1] && luma_dc_out )? combined_qf[12:0]: {quant_d[12:0]} );
always @ (posedge clk) begin
if (!en) ic[2:0] <= 3'b0;
else if (stb) ic[2:0] <= ic[2:0]+1;
if (!en) oc[2:0] <= 3'b0;
else if (start) oc[2:0] <= oc[2:0]+1;
end
// writing window parameters in the last bank of a table
always @ (negedge sclk) begin
if (twe) begin
wnd_reg[11:0] <= tdi[11:0] ;
wnd_a <= ta[2:0];
end
wnd_wr <= twe && (ta[9:3]==7'h78) ; // first 8 location in the last 64-word bank
if (wnd_wr) begin
case (wnd_a[2:0])
3'h0: wnd_left[8:0] <= wnd_reg[11:3] ;
3'h1: wnd_right[8:0] <= wnd_reg[11:3] ;
3'h2: wnd_top[8:0] <= wnd_reg[11:3] ;
3'h3: wnd_bottom[8:0] <= wnd_reg[11:3] ;
3'h4: wnd_totalwidth[8:1] <= wnd_reg[11:4] ;
3'h5: filt_sel0[3:0] <= wnd_reg[3:0] ;
3'h6: stren <= wnd_reg[0] ;
endcase
end
end
// determine if this block needs to be processed (Y, inside WOI)
reg [ 7:0] mblk_hor; //horizontal macroblock (2x2 blocks) counter
reg [ 7:0] mblk_vert; //vertical macroblock (2x2 blocks) counter
wire start_of_line= (first || (mblk_hor[7:0] == wnd_totalwidth[8:1]));
wire first_in_macro= (tn[2:0]==3'h0);
reg in_woi; // maybe specified as slow
always @(posedge clk) begin
if (first_in_macro && start) mblk_hor[7:0] <= start_of_line? 8'h0:(mblk_hor[7:0]+1);
if (first_in_macro && start && start_of_line) mblk_vert[7:0] <= first? 8'h0:(mblk_vert[7:0]+1);
start_d <= start;
tn_d[2:0] <= tn[2:0];
if (start_d) in_woi <= !tn_d[2] &&
({mblk_hor [7:0],tn_d[0]} >= wnd_left[8:0]) &&
({mblk_hor [7:0],tn_d[0]} <= wnd_right[8:0]) &&
({mblk_vert[7:0],tn_d[1]} >= wnd_top[8:0]) &&
({mblk_vert[7:0],tn_d[1]} <= wnd_bottom[8:0]);
end
//Will use posedge sclk to balance huffman and system
wire clkdiv2;
FD i_clkdiv2(.C(clk), .D(!clkdiv2), .Q(clkdiv2));
reg [2:0] clksync;
wire csync=clksync[2];
always @ (posedge sclk) begin
clksync[2:0] <= {(clksync[1]==clksync[0]),clksync[0],clkdiv2};
end
always @ (posedge clk) begin
if (di[11]==di[12]) di_d[11:0] <=di[11:0];
else di_d[11:0] <= {~di[11],{11{di[11]}}}; //saturate
end
assign mult_a[17:0] = use_coef ? {1'b0,tdo[15:0],1'b0}: mult_s[17:0];
assign mult_b[17:0] = use_coef ? {d1[10:0],{7{d1[0]}}}: mult_s[17:0];
always @ (posedge sclk) begin
filt_sel[3:0] <= filt_sel0[3:0];
if (clksync[2]) d1[11:0]<=di_d[11:0];
// start2[9:0] <= {start2[8:0], start && csync};
start2[8:0] <= {start2[7:0], start && csync};
// finish2[8:0]<= {finish2[7:0],use_coef && !next_ac};
finish2[7:0]<= {finish2[6:0],use_coef && !next_ac};
if (!en || start2[0]) tba[5:0] <= 6'h0;
else if (!csync && (tba[5:0] != 6'h3f)) tba[5:0] <= tba[5:0] + 1;
mult_s[17:0] <= (&mult_p[35:31] || !(&mult_p[35:31]))?mult_p[31:14]:18'h1ffff;
next_ac <= en && (start2[3] || (next_ac && ((tba[5:0] != 6'h3f) || csync )));
use_coef <= next_ac && !csync;
use_k_dly[5:0]<={use_k_dly[4:0],use_coef};
acc_ldval <= !(|start2[7:6]);
if (acc_clear || (acc_corr && acc_blk[23])) acc_blk[23:0] <= {1'b0,{23{acc_ldval}}};
///AF: else if (acc_add) acc_blk[23:0] <= acc_blk[23:0]+mult_p[35:8];
else if (acc_add) acc_blk[23:0] <= acc_blk[23:0]+mult_p[31:8];
if (acc_to_out) fdo[11:0] <= (|acc_blk[23:20])?12'hfff:acc_blk[19:8]; // positive, 0..0xfff
if (acc_to_out) sum_blk[22:0] <= acc_blk[22:0]; // accumulator for the sum ((a[i]*d[i])^2), copied at block end
end
// acc_blk will (after corr) be always with MSB=0 - max 24'h7fffff
// for image output - max 24'h0fffff->12 bit signed, shifted
// combining output
//assign combined_qf[12:0]={quant_d[11],quant_d[11:0]}+{fdo[11],fdo[11:0]};
SRL16 i_out_mono (.Q(out_mono), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b1), .CLK(clk), .D(started_luma)); // timing not critical
SRL16 i_out_window (.Q(out_window), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b1), .CLK(clk), .D(in_woi)); // timing not critical
always @ (posedge clk) begin
if (start) started_luma <= !tn[2];
luma_dc_out <= quant_ds && out_mono && ((mode[1:0]!=3) || out_window);
luma_dc_acc <= quant_ds && out_mono && out_window;
was_last_luma <= en && last && out_mono;
copy_acc_frame <= was_last_luma && !out_mono;
if (first && first_in_macro) acc_frame[39:0] <= 40'h0;
else if (luma_dc_acc) acc_frame[39:0] <= acc_frame[39:0] + sum_blk[22:0];
if (copy_acc_frame) hifreq[31:0] <= acc_frame[39:8];
pre_ds <= quant_ds;
ds <= pre_ds;
pre_do[12:0] <= next_do[12:0];
need_corr_max <=luma_dc_out && (mode[1:0]!=2'h0);
/* do[11:0] <= (need_corr_max && !pre_do[12] && (pre_do[11] || (pre_do[10:0]>quant_dc_tdo[15:5])) )?
{1'b0,quant_dc_tdo[15:5]} :
pre_do[11:0];
*/
do[12:0] <= (need_corr_max && !pre_do[12] && (pre_do[11] || (pre_do[10:0]>quant_dc_tdo[15:5])) )?
{2'b0,quant_dc_tdo[15:5]} :
pre_do[12:0];
end
MULT18X18SIO #(
.AREG(1), // Enable the input registers on the A port (1=on, 0=off)
.BREG(1), // Enable the input registers on the B port (1=on, 0=off)
.B_INPUT("DIRECT"), // B cascade input "DIRECT" or "CASCADE"
.PREG(1) // Enable the input registers on the P port (1=on, 0=off)
) i_focus_mult (
.BCOUT(), // 18-bit cascade output
.P(mult_p), // 36-bit multiplier output
.A(mult_a), // 18-bit multiplier input
.B(mult_b), // 18-bit multiplier input
.BCIN(18'h0), // 18-bit cascade input
.CEA(en), // Clock enable input for the A port
.CEB(en), // Clock enable input for the B port
.CEP(en), // Clock enable input for the P port
.CLK(sclk), // Clock input
.RSTA(1'b0), // Synchronous reset input for the A port
.RSTB(1'b0), // Synchronous reset input for the B port
.RSTP(1'b0) // Synchronous reset input for the P port
);
RAM16X1D i_tn0 (.D(tni[0]),.DPO(tn[0]),.A0(ic[0]),.A1(ic[1]),.A2(1'b0),.A3(1'b0),.DPRA0(oc[0]),.DPRA1(oc[1]),.DPRA2(1'b0),.DPRA3(1'b0),.WCLK(clk),.WE(stb),.SPO());
RAM16X1D i_tn1 (.D(tni[1]),.DPO(tn[1]),.A0(ic[0]),.A1(ic[1]),.A2(1'b0),.A3(1'b0),.DPRA0(oc[0]),.DPRA1(oc[1]),.DPRA2(1'b0),.DPRA3(1'b0),.WCLK(clk),.WE(stb),.SPO());
RAM16X1D i_tn2 (.D(tni[2]),.DPO(tn[2]),.A0(ic[0]),.A1(ic[1]),.A2(1'b0),.A3(1'b0),.DPRA0(oc[0]),.DPRA1(oc[1]),.DPRA2(1'b0),.DPRA3(1'b0),.WCLK(clk),.WE(stb),.SPO());
RAM16X1D i_first (.D(firsti),.DPO(first),.A0(ic[0]),.A1(ic[1]),.A2(1'b0),.A3(1'b0),.DPRA0(oc[0]),.DPRA1(oc[1]),.DPRA2(1'b0),.DPRA3(1'b0),.WCLK(clk),.WE(stb),.SPO());
RAM16X1D i_last (.D(lasti), .DPO(last), .A0(ic[0]),.A1(ic[1]),.A2(1'b0),.A3(1'b0),.DPRA0(oc[0]),.DPRA1(oc[1]),.DPRA2(1'b0),.DPRA3(1'b0),.WCLK(clk),.WE(stb),.SPO());
RAMB16_S18_S18 i_focus_dct_tab (
.DOA(tdo[15:0]), // Port A 16-bit Data Output
.DOPA(), // Port A 2-bit Parity Output
.ADDRA({filt_sel[3:0],tba[2:0],tba[5:3]}), // Port A 10-bit Address Input
.CLKA(sclk), // Port A Clock
.DIA(16'b0), // Port A 16-bit Data Input
.DIPA(2'b0), // Port A 2-bit parity Input
.ENA(1'b1), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(1'b0), // Port A Write Enable Input
.DOB(), // Port B 16-bit Data Output
.DOPB(), // Port B 4-bit Parity Output
.ADDRB({ta[9:0]}), // Port B 2-bit Address Input
.CLKB(!sclk), // Port B Clock
.DIB(tdi[15:0]), // Port B 16-bit Data Input
.DIPB(2'b0), // Port-B 2-bit parity Input
.ENB(1'b1), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(twe) // Port B Write Enable Input
);
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/huffman333.v 0000664 0000000 0000000 00000051161 12555570767 0023514 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** huffman333.v
**
** Huffman encoder for JPEG compressorrdy
**
** Copyright (C) 2002-2004 Elphelk, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X333
** X333 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
// 01/22/2004 - extended flush until ready (modified stuffer.v too)
module huffman (pclk, // half frequency, sync to incoming data
clk, // pixel clock
en, // enable (0 resets) sync to pclk
// cwr, // CPU WR global clock
twe, // enable write to a table - now the following will be valid ant negedge clk
ta, // [8:0] table address
tdi, // [15:0] table data in
// readback, // [23:0] readback data
di, // [15:0] specially RLL prepared 16-bit data (to FIFO) (sync to pclk)
ds, // di valid strobe (sync to pclk)
rdy, // receiver (bit stuffer) is ready to accept data
do, // [15:0] output data
dl, // [3:0] data length (4'h0 is 'h16)
dv, // output data valid
flush, // last block done - flush the rest bits
last_block,
test_lbw,
gotLastBlock
);
input pclk;
input clk;
input en;
// input cwr;
input twe;
input [ 8:0] ta;
input [15:0] tdi;
// output [23:0] readback; // readback data
input [15:0] di;
input ds;
input rdy;
output [15:0] do;
output [ 3:0] dl;
output dv;
output flush;
output last_block;
output test_lbw;
output gotLastBlock;
reg test_lbw;
wire [19:0] tables_out;
wire [15:0] hcode; // table output huffman code (1..16 bits)
wire [ 3:0] hlen; // table - code length only 4 LSBs are used
wire [11:0] unused; // SuppressThisWarning Veditor UNUSED
reg [ 7:0] haddr_r; // index in huffman table
wire [ 7:0] haddr_next;
wire [ 8:0] haddr; // index in huffman table (after latches)
wire [15:0] fifo_o;
reg stuffer_was_rdy;
wire tables_re;
wire read_next; // assigned depending on steps (each other cycle for normal codes, each for special 00/F0
reg [5:0] steps;
// first stage registers
reg [5:0] rll; // 2 MSBs - counter to send "f0" codes
// replacing SRL16 with FD as SRL has longer output delay from clock
reg [3:0] rll1;
reg [3:0] rll2;
reg typeDC;
reg typeAC;
reg [11:0] sval; // signed input value
wire [1:0] code_typ0; // valid at steps[0]
reg tbsel_YC0; // valid at steps[0] - 0 -Y table, 1 - CbCr
reg [1:0] code_typ1;
reg [1:0] code_typ2;
reg code_typ3;
reg code_typ4;
reg tbsel_YC1;
reg tbsel_YC2;
reg tbsel_YC3;
reg last_block; //
reg [15:0] out_bits; // bits to send
reg [3:0] out_len; // length of bits to send (4'h0 means 16)
wire fifo_or_full; // fifo output register full read_next
wire will_read;
wire [10:0] var_do;
wire [3:0] var_dl;
wire [3:0] var_dl_late;
//wire dv;
reg dv;
reg dv0;
//reg dv_d; // dv0 delayed
//reg [15:0] out_bits_d; // bits to send (delayed)
//reg [3:0] out_len_d; // length of bits to send (4'h0 means 16) (delayed)
reg flush;
//wire [23:0] readback; // readback data
reg eob;
wire gotDC;
wire gotAC;
wire gotRLL;
wire gotEOB;
wire gotLastBlock;
wire gotLastWord;
wire gotColor;
wire want_read; // as will_read, but w/o fifo status
reg ready_to_flush; // read the last data from fifo
reg en2x; // en sync to clk;
reg [15:0] do;
reg [ 3:0] dl;
wire pre_dv;
wire [15:0] pre_bits;
wire [ 3:0] pre_len;
reg twe_d; // table write enable (twe) delayued by 1 clock
always @ (negedge clk) en2x <= en;
assign gotDC= fifo_o[15] && fifo_o[14];
assign gotAC= fifo_o[15] && !fifo_o[14];
assign gotRLL= !fifo_o[15] && !fifo_o[12];
assign gotEOB= !fifo_o[15] && fifo_o[12];
assign gotLastBlock= fifo_o[15] && fifo_o[14] && fifo_o[12];
assign gotLastWord= !fifo_o[14] && fifo_o[12]; // (AC or RLL) and last bit set
assign gotColor= fifo_o[13];
always @(negedge clk) stuffer_was_rdy <= !en2x || rdy; // stuffer ready shoud be on if !en (move to register?)for now]
wire stuffer_was_rdy_early;
wire want_read_early;
LD i_stuffer_was_rdy_early (.Q(stuffer_was_rdy_early),.G(clk),.D(!en2x || rdy));
LD i_tables_re (.Q(tables_re),.G(clk),.D(en2x && rdy));
assign read_next= en2x && ((!steps[0] && !rll[5]) || eob ) && fifo_or_full; // fifo will never have data after the last block...
assign will_read= stuffer_was_rdy && fifo_or_full && en2x && ((!steps[0] && !rll[5]) || eob ); // fifo will never have data after the last block...
assign want_read= stuffer_was_rdy && ((!steps[0] && !rll[5]) || eob ); // for FIFO
assign want_read_early= stuffer_was_rdy_early && ((!steps[0] && !rll[5]) || eob ); // for FIFO
always @ (negedge clk) if (stuffer_was_rdy) begin
eob <= read_next && gotEOB;// will be 1 only during step[0]
if (!en2x) steps[5:0] <= 'b0;
else steps[5:0] <= { steps[4] && code_typ4, // will be skipped for codes 00/F0
steps[3:0],
(read_next && !(gotRLL && (fifo_o[5:4]==2'b00))) || rll[5] }; // will not start if it was <16, waiting for AC
end
always @ (negedge clk) begin
last_block <= en2x && (last_block?(!flush):(stuffer_was_rdy && will_read && gotLastBlock));
ready_to_flush <= en2x && (ready_to_flush?(!flush):(stuffer_was_rdy && last_block && will_read && gotLastWord));
test_lbw <= en2x && last_block && gotLastWord;
// did not work if flush was just after not ready?
flush <= en2x &&( flush?(!rdy):(rdy && stuffer_was_rdy && ready_to_flush && !(|steps)) );
end
always @ (negedge clk) if (will_read) begin
typeDC <= gotDC;
typeAC <= gotAC;
sval[11:0] <= fifo_o[11:0];
if (gotDC) tbsel_YC0 <= gotColor;
end
always @ (negedge clk) if (stuffer_was_rdy) begin
if (!en2x || (read_next && gotAC) || (steps[0] && typeAC)) rll[5:4] <= 2'b0;
else if (read_next && gotRLL) rll[5:4] <= fifo_o[5:4];
else if (rll[5:4]!=2'b00) rll[5:4] <= rll[5:4]-1;
if (!en2x || (read_next && !gotAC && !gotRLL) || (steps[0] && typeAC)) rll[3:0] <= 4'b0;
else if (read_next && gotRLL) rll[3:0] <= fifo_o[3:0];
end
assign code_typ0={typeDC || (!eob && (rll[5:4]==2'b0)),
typeDC || (!eob && (rll[5:4]!=2'b0))};
assign haddr_next[7:0] = code_typ2[1]?
(code_typ2[0]?{var_dl[3:0],4'hf}: // DC (reusing the spare cells of the AC table)
{rll2[3:0],var_dl[3:0]}): // AC normal code
(code_typ2[0]?8'hf0: //skip 16 zeros code
8'h00); //skip to end of block code
always @ (negedge clk) if (stuffer_was_rdy && steps[2]) begin // may be just if (stuffer_was_rdy)
haddr_r[7:0] <= haddr_next[7:0];
end
LD i_haddr_7 (.Q(haddr[7]),.G(clk),.D((stuffer_was_rdy && steps[2])?haddr_next[7]:haddr_r[7]));
LD i_haddr_6 (.Q(haddr[6]),.G(clk),.D((stuffer_was_rdy && steps[2])?haddr_next[6]:haddr_r[6]));
LD i_haddr_5 (.Q(haddr[5]),.G(clk),.D((stuffer_was_rdy && steps[2])?haddr_next[5]:haddr_r[5]));
LD i_haddr_4 (.Q(haddr[4]),.G(clk),.D((stuffer_was_rdy && steps[2])?haddr_next[4]:haddr_r[4]));
LD i_haddr_3 (.Q(haddr[3]),.G(clk),.D((stuffer_was_rdy && steps[2])?haddr_next[3]:haddr_r[3]));
LD i_haddr_2 (.Q(haddr[2]),.G(clk),.D((stuffer_was_rdy && steps[2])?haddr_next[2]:haddr_r[2]));
LD i_haddr_1 (.Q(haddr[1]),.G(clk),.D((stuffer_was_rdy && steps[2])?haddr_next[1]:haddr_r[1]));
LD i_haddr_0 (.Q(haddr[0]),.G(clk),.D((stuffer_was_rdy && steps[2])?haddr_next[0]:haddr_r[0]));
//
assign pre_dv = steps[4] || (steps[5] && (var_dl_late[3:0]!=4'b0));
assign pre_bits[15:0] = steps[5]?{5'b0,var_do[10:0]}: hcode[15:0];
assign pre_len [ 3:0] = steps[5]? var_dl_late[ 3:0]: hlen [3:0];
always @ (negedge clk) if (stuffer_was_rdy) begin
dv0 <= pre_dv;
out_bits[15:0] <= pre_bits[15:0];
out_len [ 3:0] <= pre_len [ 3:0];
end
always @ (negedge clk) if (!en2x || rdy) begin
dv <= stuffer_was_rdy? pre_dv:dv0;
do[15:0] <= stuffer_was_rdy? pre_bits[15:0]:out_bits[15:0];
dl[ 3:0] <= stuffer_was_rdy? pre_len [ 3:0]:out_len [ 3:0];
end
// "Extract shift registers" in synthesis should be off! FD has lower output delay than SRL16
always @ (negedge clk) if (stuffer_was_rdy) begin
code_typ1[1:0] <= code_typ0[1:0];
code_typ2[1:0] <= code_typ1[1:0];
code_typ3 <= code_typ2[1];
code_typ4 <= code_typ3;
rll1[3:0] <= rll[3:0];
rll2[3:0] <= rll1[3:0];
tbsel_YC1 <= tbsel_YC0;
tbsel_YC2 <= tbsel_YC1;
tbsel_YC3 <= tbsel_YC2;
end
LD i_haddr_8 (.Q(haddr[8]),.G(clk),.D(stuffer_was_rdy?tbsel_YC2:tbsel_YC3));
LD_1 i_hlen3 (.Q( hlen[ 3]),.G(clk),.D(tables_out[19]));
LD_1 i_hlen2 (.Q( hlen[ 2]),.G(clk),.D(tables_out[18]));
LD_1 i_hlen1 (.Q( hlen[ 1]),.G(clk),.D(tables_out[17]));
LD_1 i_hlen0 (.Q( hlen[ 0]),.G(clk),.D(tables_out[16]));
LD_1 i_hcode15(.Q(hcode[15]),.G(clk),.D(tables_out[15]));
LD_1 i_hcode14(.Q(hcode[14]),.G(clk),.D(tables_out[14]));
LD_1 i_hcode13(.Q(hcode[13]),.G(clk),.D(tables_out[13]));
LD_1 i_hcode12(.Q(hcode[12]),.G(clk),.D(tables_out[12]));
LD_1 i_hcode11(.Q(hcode[11]),.G(clk),.D(tables_out[11]));
LD_1 i_hcode10(.Q(hcode[10]),.G(clk),.D(tables_out[10]));
LD_1 i_hcode9 (.Q(hcode[ 9]),.G(clk),.D(tables_out[ 9]));
LD_1 i_hcode8 (.Q(hcode[ 8]),.G(clk),.D(tables_out[ 8]));
LD_1 i_hcode7 (.Q(hcode[ 7]),.G(clk),.D(tables_out[ 7]));
LD_1 i_hcode6 (.Q(hcode[ 6]),.G(clk),.D(tables_out[ 6]));
LD_1 i_hcode5 (.Q(hcode[ 5]),.G(clk),.D(tables_out[ 5]));
LD_1 i_hcode4 (.Q(hcode[ 4]),.G(clk),.D(tables_out[ 4]));
LD_1 i_hcode3 (.Q(hcode[ 3]),.G(clk),.D(tables_out[ 3]));
LD_1 i_hcode2 (.Q(hcode[ 2]),.G(clk),.D(tables_out[ 2]));
LD_1 i_hcode1 (.Q(hcode[ 1]),.G(clk),.D(tables_out[ 1]));
LD_1 i_hcode0 (.Q(hcode[ 0]),.G(clk),.D(tables_out[ 0]));
huff_fifo i_huff_fifo(.pclk(pclk),
.clk(clk),
.en(en), // will reset if ==0 (sync to pclk)
.di(di[15:0]), // data in (sync to pclk)
.ds(ds), // din valid (sync to pclk)
.want_read(want_read),
.want_read_early(want_read_early),
.dav(fifo_or_full), // FIFO output register has data
.q(fifo_o[15:0])); // output data (will add extra buffering if needed)
varlen_encode i_varlen_encode(.clk(clk),
.en(stuffer_was_rdy), //will enable registers. 0 - freese
.start(steps[0]),
.d(sval[11:0]), // 12-bit signed
.l(var_dl[ 3:0]), // [3:0] code length
.l_late(var_dl_late[3:0]),
.q(var_do[10:0])); // [10:0]code
always @ (negedge clk) twe_d <= twe;
RAMB16_S18_S36 i_htab (
.DOA(), // Port A 16-bit Data Output
.DOPA(), // Port A 2-bit Parity Output
.ADDRA({ta[8:0],twe_d}), // Port A 10-bit Address Input
.CLKA(!clk), // Port A Clock
.DIA(tdi[15:0]), // Port A 16-bit Data Input
.DIPA(2'b0), // Port A 2-bit parity Input
.ENA(1'b1), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(twe | twe_d),// Port A Write Enable Input
.DOB({unused[11:0],tables_out[19:0]}), // Port B 32-bit Data Output
.DOPB(), // Port B 4-bit Parity Output
.ADDRB(haddr[8:0]), // Port B 9-bit Address Input
.CLKB(clk), // Port B Clock
.DIB(32'b0), // Port B 32-bit Data Input
.DIPB(4'b0), // Port-B 4-bit parity Input
.ENB(tables_re), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(1'b0) // Port B Write Enable Input
);
endmodule
//used the other edge of the clk2x
module huff_fifo (pclk,
clk,
en, // will reset if ==0 (sync to pclk)
di, // data in (sync to pclk)
ds, // din valid (sync to pclk)
want_read,
want_read_early,
dav, // FIFO output register has data (fifo_or_full)
q); // output data
input pclk,clk,en,ds, want_read, want_read_early; //,got; // will_read;
input [15:0] di;
output dav;
output[15:0] q;
reg [9:0] wa;
reg [9:0] sync_wa; // delayed wa, re-calculated at output clock
reg [9:0] ra_r;
wire [9:0] ra;
wire [15:0] q;
reg load_q; // SuppressThisWarning Veditor VDT_BUG
wire [15:0] fifo_o;
reg ds1; // ds delayed by one pclk to give time to block ram to write data. Not needed likely.
reg synci;
reg [1:0] synco;
reg sync_we; // single clk period pulse for each ds@pclk
reg en2x; // en sync to clk;
reg re_r;
wire re;
reg dav; // output latch has data
reg fifo_dav; // RAM output reg has data
reg dav_and_fifo_dav;
wire ram_dav; // RAM has data inside
reg [9:0] diff_a;
wire next_re;
always @ (posedge pclk) begin // input stage, no overrun detection
if (!en) wa[9:0] <= 10'b0;
else if (ds) wa[9:0] <= wa[9:0]+1;
ds1 <= ds && en;
if (!en) synci <= 1'b0;
else if (ds1) synci <= ~synci;
end
always @ (negedge clk) begin
en2x <= en;
synco[1:0] <= {synco[0],synci};
sync_we <= en2x && (synco[0] != synco[1]);
end
assign ram_dav= sync_we || (diff_a[9:0] != 10'b0);
// assign next_re= ram_dav && (!dav || !fifo_dav || want_read);
assign next_re= ram_dav && (!dav_and_fifo_dav || want_read);
always @ (negedge clk) begin
dav <= en2x && (fifo_dav || (dav && !want_read));
fifo_dav <= en2x && (ram_dav ||(dav && fifo_dav && !want_read));
dav_and_fifo_dav <= en2x && (fifo_dav || (dav && !want_read)) && (ram_dav ||(dav && fifo_dav && !want_read)); // will optimize auto
re_r <= en2x && next_re;
if (!en2x) sync_wa[9:0] <= 10'b0;
else if (sync_we) sync_wa[9:0] <= sync_wa[9:0]+1;
if (!en2x) ra_r [9:0] <= 10'b0;
else if (next_re) ra_r [9:0] <= ra_r[9:0]+1;
if (!en2x) diff_a[9:0] <= 10'b0;
else if (sync_we && !next_re) diff_a[9:0] <= diff_a[9:0]+1;
else if (!sync_we && next_re) diff_a[9:0] <= diff_a[9:0]-1;
end
LD i_re (.Q(re),.G(clk),.D(next_re));
LD i_ra9 (.Q(ra[9]),.G(clk),.D(ra_r[9]));
LD i_ra8 (.Q(ra[8]),.G(clk),.D(ra_r[8]));
LD i_ra7 (.Q(ra[7]),.G(clk),.D(ra_r[7]));
LD i_ra6 (.Q(ra[6]),.G(clk),.D(ra_r[6]));
LD i_ra5 (.Q(ra[5]),.G(clk),.D(ra_r[5]));
LD i_ra4 (.Q(ra[4]),.G(clk),.D(ra_r[4]));
LD i_ra3 (.Q(ra[3]),.G(clk),.D(ra_r[3]));
LD i_ra2 (.Q(ra[2]),.G(clk),.D(ra_r[2]));
LD i_ra1 (.Q(ra[1]),.G(clk),.D(ra_r[1]));
LD i_ra0 (.Q(ra[0]),.G(clk),.D(ra_r[0]));
always @ (posedge clk) begin
load_q <= dav?want_read_early:re_r;
end
LD_1 i_q15 (.Q( q[15]),.G(clk),.D(load_q?fifo_o[15]:q[15]));
LD_1 i_q14 (.Q( q[14]),.G(clk),.D(load_q?fifo_o[14]:q[14]));
LD_1 i_q13 (.Q( q[13]),.G(clk),.D(load_q?fifo_o[13]:q[13]));
LD_1 i_q12 (.Q( q[12]),.G(clk),.D(load_q?fifo_o[12]:q[12]));
LD_1 i_q11 (.Q( q[11]),.G(clk),.D(load_q?fifo_o[11]:q[11]));
LD_1 i_q10 (.Q( q[10]),.G(clk),.D(load_q?fifo_o[10]:q[10]));
LD_1 i_q9 (.Q( q[ 9]),.G(clk),.D(load_q?fifo_o[ 9]:q[ 9]));
LD_1 i_q8 (.Q( q[ 8]),.G(clk),.D(load_q?fifo_o[ 8]:q[ 8]));
LD_1 i_q7 (.Q( q[ 7]),.G(clk),.D(load_q?fifo_o[ 7]:q[ 7]));
LD_1 i_q6 (.Q( q[ 6]),.G(clk),.D(load_q?fifo_o[ 6]:q[ 6]));
LD_1 i_q5 (.Q( q[ 5]),.G(clk),.D(load_q?fifo_o[ 5]:q[ 5]));
LD_1 i_q4 (.Q( q[ 4]),.G(clk),.D(load_q?fifo_o[ 4]:q[ 4]));
LD_1 i_q3 (.Q( q[ 3]),.G(clk),.D(load_q?fifo_o[ 3]:q[ 3]));
LD_1 i_q2 (.Q( q[ 2]),.G(clk),.D(load_q?fifo_o[ 2]:q[ 2]));
LD_1 i_q1 (.Q( q[ 1]),.G(clk),.D(load_q?fifo_o[ 1]:q[ 1]));
LD_1 i_q0 (.Q( q[ 0]),.G(clk),.D(load_q?fifo_o[ 0]:q[ 0]));
/*
RAMB4_S16_S16 i_fifo (.DOB(fifo_o[15:0]),
.ADDRA(wa[7:0]),
.CLKA(pclk),
.DIA(di[15:0]),
.ENA(ds),.RSTA(1'b0),.WEA(1'b1),
.ADDRB(ra[7:0]),
.CLKB(clk),
.DIB(16'b0),.ENB(re),.RSTB(1'b0),.WEB(1'b0));
*/
RAMB16_S18_S18 i_fifo (
.DOA(), // Port A 16-bit Data Output
.DOPA(), // Port A 2-bit Parity Output
.ADDRA(wa[9:0]), // Port A 10-bit Address Input
.CLKA(pclk), // Port A Clock
.DIA(di[15:0]), // Port A 16-bit Data Input
.DIPA(2'b0), // Port A 2-bit parity Input
.ENA(ds), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(1'b1), // Port A Write Enable Input
.DOB(fifo_o[15:0]),// Port B 16-bit Data Output
.DOPB(), // Port B 2-bit Parity Output
.ADDRB(ra[9:0]), // Port B 10-bit Address Input
.CLKB(clk), // Port B Clock
.DIB(16'b0), // Port B 16-bit Data Input
.DIPB(2'b0), // Port-B 2-bit parity Input
.ENB(re), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(1'b0) // Port B Write Enable Input
);
endmodule
// Encoder will work 2 cycles/"normal" word, 1 cycle for codes "00" and "f0",
// only magnitude output is needed ASAP (2 cycles, the value out should be
// valid on the 5-th cycle - it will latency 4 cycles run each other cycle
// I'll make a shortcut - all codes processed in 2 cycles.
module varlen_encode (clk,
en, // will enable registers. 0 - "freese" at once
start, // (not faster than each other cycle)
d, // 12-bit signed
l, // [3:0] code length
l_late,// delayed l (sync to q)
q); // [10:0]code
input clk, en,start;
input [11:0] d;
output [ 3:0] l;
output [ 3:0] l_late;
output [10:0] q;
reg [11:0] d1;
reg [10:0] q,q0;
reg [ 3:0] l,l_late;
reg [2:0] cycles;
wire this0= |d1[ 3:0];
wire this1= |d1[ 7:4];
wire this2= |d1[10:8];
wire [1:0] codel0={|d1[ 3: 2],d1[ 3] || (d1[ 1] & ~d1[ 2])};
wire [1:0] codel1={|d1[ 7: 6],d1[ 7] || (d1[ 5] & ~d1[ 6])};
wire [1:0] codel2={|d1[ 10], (d1[ 9] & ~d1[10])};
wire [3:0] codel= this2? {2'b10,codel2[1:0]} :
(this1? {2'b01,codel1[1:0]} :
(this0? {2'b00,codel0[1:0]} : 4'b1111)); // after +1 will be 0;
always @ (negedge clk) if (en) begin
cycles[2:0] <= {cycles[1:0],start};
end
always @ (negedge clk) if (en && start) begin
d1[ 11] <= d[11];
d1[10:0] <= d[11]?-d[10:0]:d[10:0];
end
always @ (negedge clk) if (en & cycles[0]) begin
q0[10:0] <= d1[11]?~d1[10:0]:d1[10:0];
l <= codel[3:0]+1; // needed only ASAP, valid only 2 cycles after start
end
always @ (negedge clk) if (en & cycles[2]) begin
q[10:0] <= q0[10:0];
l_late[3:0] <= l[3:0];
end
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/quantizator353.v 0000664 0000000 0000000 00000041130 12555570767 0024446 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** quantizator353.v
**
** Quantizator module for JPEG compressor
**
** Copyright (C) 2002-2010 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
`timescale 1ns/1ps
// will add extracted DC (8 bits) to data from DCT here that will make data 12 bits (signed) long.
// It will be possible to make a sequincial multiplier for DC - but I'll skip this opportunity now.
//********** TODO: switch to 16-bit tables instead of the 12-bit ones **************
module quantizator(clk, // pixel clock
en, // enable (0 resets counter)
sclk, // system clock, twqe, twce, ta,tdi - valid @negedge (ra, tdi - 2 cycles ahead
twqe, // enable write to a quantization table
twce, // enable write to a coring table
ta, // [6:0] table address
tdi, // [15:0] table data in (8 LSBs - quantization data)
// readback, // readback data
ctypei, // component type input (Y/C)
dci, // [7:0] - average value in a block - subtracted before DCT
first_stb, //this is first stb pulse in a frame
stb, // strobe that writes ctypei, dci
tsi, // table (quality) select [2:0]
pre_start,// marks first input pixel (one before)
first_in, // first block in (valid @ start)
first_out, // valid @ ds
di, // [11:0] pixel data in (signed)
do, // [11:0] pixel data out (AC is only 9 bits long?) - changed to 10
dv, // data out valid
ds, // data out strobe (one ahead of the start of dv)
dc_tdo, //[15:0], MSB aligned coefficient for the DC component (used in focus module)
// dc_tdo_stb,
dcc_en, // enable dcc (sync to beginning of a new frame)
hfc_sel, // hight frequency components select [2:0] (includes components with both numbers >=hfc_sel
// hfc_sel == 3'h7 - now high frequency output - just 3 words - brightness and 2 color diffs
color_first, // first MCU in a frame
coring_num, // coring table pair number (0..7)
dcc_vld, // single cycle when dcc_data is valid
dcc_data, // [15:0] dc component data out (for reading by software)
n000, // input [7:0] number of zero pixels (255 if 256) - to be multiplexed with dcc
n255); // input [7:0] number of 0xff pixels (255 if 256) - to be multiplexed with dcc
input clk;
input en;
input sclk;
input twqe;
input twce;
input [ 8:0] ta;
input [15:0] tdi;
input ctypei;
input [ 8:0] dci; // now normal signed number
input first_stb; //this is first stb pulse in a frame
input stb;
input [ 2:0] tsi;
input pre_start;
input first_in; // first block in (valid @ start)
output first_out; // valid @ ds
input [12:0] di;
output[12:0] do;
output dv;
output ds;
output [15:0] dc_tdo;
input dcc_en;
input [2:0] hfc_sel;
input color_first;
input [2:0] coring_num; // Coring table number (0..7)
output dcc_vld;
output[15:0] dcc_data;
input [7:0] n000;
input [7:0] n255;
wire [3:0] tdco; // coring table output
reg [3:0] tbac; // coring memory table number (LSB - color)
reg coring_range; // input <16, use coring LUT
wire [15:0] tdo;
reg [ 9:0] tba; // table output (use) address
wire [15:0] zigzag_q;
reg wpage,
rpage;
wire [5:0] zwa;
reg [5:0] zra;
reg [12:0] qdo;
reg [12:0] qdo0;
reg zwe;
reg [12:0] d1;
reg [12:0] d2,d3; // registered data in, converted to sign+ absolute value
wire [27:0] qmul;
wire start_a;
reg [15:0] tdor;
reg [20:0] qmulr; // added 7 bits to total8 fractional for biasing/zero bin
wire start_out;
wire start_z;
reg ds;
reg dv;
reg [ 8:0] dc1; // registered DC average - with restored sign
// for fifo for ctype, dc
wire ctype;
wire [8:0] dc;
wire next_dv;
reg [ 5:0] start;
wire [15:0] dcc_data;
wire dcc_stb;
reg dcc_vld;
reg dcc_run;
reg dcc_first;
reg dcc_Y;
reg [1:0] ctype_prev;
reg [12:0] dcc_acc;
reg [12:0] hfc_acc;
wire hfc_en;
reg hfc_copy; // copy hfc_acc to dcc_acc
wire [10:0] d2_dct; // 11 bits enough, convetred to positive (before - 0 was in the middle - pixel value 128) - dcc only
reg sel_satnum; // select saturation numbers - dcc only
reg twqe_d; //twqe delayed (write MSW)
reg twce_d; //twce delayed (write MSW)
reg [15:0] dc_tdo;
reg [15:0] pre_dc_tdo;
wire copy_dc_tdo;
wire first_in; // first block in (valid @ pre_start)
reg first_interm, first_out; // valid @ ds
wire [2:0] ts;
wire [2:0] coring_sel;
reg [2:0] block_mem_ra;
reg [2:0] block_mem_wa;
reg [2:0] block_mem_wa_save;
reg [15:0] block_mem[0:7];
wire [15:0] block_mem_o=block_mem[block_mem_ra[2:0]];
assign dc[8:0]= block_mem_o[8:0];
assign ctype= block_mem_o[9];
assign ts[2:0]= block_mem_o[12:10];
assign coring_sel[2:0]= block_mem_o[15:13];
assign start_a=start[5];
assign start_z=start[4];
assign dcc_stb=start[2];
always @ (posedge clk) begin
if (stb) block_mem[block_mem_wa[2:0]] <= {coring_num[2:0],tsi[2:0], ctypei, dci[8:0]};
if (!en) block_mem_wa[2:0] <= 3'h0;
else if (stb) block_mem_wa[2:0] <= block_mem_wa[2:0] +1;
if (stb && first_stb) block_mem_wa_save[2:0] <= block_mem_wa[2:0];
if (!en) block_mem_ra[2:0] <= 3'h0;
else if (pre_start) block_mem_ra[2:0] <= first_in?block_mem_wa_save[2:0]:(block_mem_ra[2:0] +1);
end
assign d2_dct[10:0]={!d2[11] ^ ctype_prev[0], d2[9:0]};
assign dcc_data[15:0]=sel_satnum?
{n255[7:0],n000[7:0]}:
{dcc_first || (!dcc_Y && dcc_acc[12]) ,(!dcc_Y && dcc_acc[12]), (!dcc_Y && dcc_acc[12]), dcc_acc[12:0]};
assign do[12:0]=zigzag_q[12:0];
// assign qmul[23:0]=tdor[11:0]*d3[11:0];
assign qmul[27:0]=tdor[15:0]*d3[11:0];
assign start_out = zwe && (zwa[5:0]== 6'h3f); //adjust?
assign copy_dc_tdo = zwe && (zwa[5:0]== 6'h37); // not critical
assign next_dv=en && (ds || (dv && (zra[5:0]!=6'h00)));
always @ (posedge clk) begin
d1[12:0] <= di[12:0];
//inv_sign
// dc1[8:0] <= start[0]?{{2{~dc[7]}},dc[6:0]}:9'b0; // sync to d1[8:0]ctype valid at start, not later
dc1[8:0] <= start[0]?dc[8:0]:9'b0; // sync to d1[8:0]ctype valid at start, not later
d2[12:0] <= {dc1[8],dc1[8:0],3'b0} + d1[12:0];
d3[12] <= d2[12];
d3[11:0] <= d2[12]? -d2[11:0]:d2[11:0];
if (start[0] || !en) tba[9:6] <= {ts[2:0],ctype};
/// TODO - make sure ctype switches at needed time (compensate if needed) *****************************************
if (start[3] || !en) tbac[3:0] <= {coring_sel[2:0],ctype}; // table number to use
if (start[0]) tba[5:0] <= 6'b0;
else if (tba[5:0]!=6'h3f) tba[5:0] <= tba[5:0]+1;
tdor[15:0] <= tdo[15:0]; // registered table data out
if (start[3]) pre_dc_tdo[15:0] <= tdor[15:0]; //16-bit q. tables)
if (copy_dc_tdo) dc_tdo[15:0] <= pre_dc_tdo[15:0];
qmulr[19:0] <= qmul[27:8]; // absolute value
qmulr[20] <= d3[12]; // sign
qdo0[12] <= qmulr[20]; // sign
// tdco[3:0] - same timing as qdo0;
// use lookup table from 8 bits of absolute value (4.4 - 4 fractional) to calculate 4 bit coring output that would replace output
// if input is less thahn 16. For larger values the true rounding will be used.
// Absolute values here have quantization coefficients already applied, so we can use the same coring table for all DCT coefficients.
// there are be 16 tables - 8 Y/C pairs to switch
qdo0[11:0] <= qmulr[19:8] + qmulr[7]; // true rounding of the absolute value
coring_range<= !(|qmulr[19:12]) && !(&qmulr[11:7]) ; // valid with qdo0
// qdo[11:0] <= coring_range? {8'h0,tdco[3:0]}:qdo0[11:0];
qdo[11:0] <= coring_range? (qdo0[12]?-{8'h0,tdco[3:0]}:{8'h0,tdco[3:0]}):(qdo0[12]?-qdo0[11:0]:qdo0[11:0]);
qdo[12] <= qdo0[12] && (!coring_range || (tdco[3:0]!=4'h0));
if (start_out) rpage <= wpage;
if (start_out) zra[5:0] <= 6'b0;
else if (zra[5:0]!=6'h3f) zra[5:0] <=zra[5:0]+1; // conserving energy
ds <= start_out;
dv <= next_dv;
if (start_a) first_interm <= first_in;
if (start_out) first_out <=first_interm;
// zwe???
zwe <= en && (start_a || (zwe && (zwa[5:0]!=6'h3f)));
if (!en) wpage <= 1'b0;
else if (start_a) wpage <= ~wpage;
end
always @ (posedge clk) begin
sel_satnum <= dcc_run && (start[0]? (ctype_prev[1:0]==2'b10): sel_satnum);
hfc_copy <= dcc_run && (hfc_sel[2:0]!=3'h7) && (tba[5:0]==6'h1f) && ctype_prev[0] && ctype_prev[1];
start[5:0] <= {start[4:0], pre_start}; // needed?
if (!dcc_en) dcc_run <= 1'b0;
else if (start[0]) dcc_run <= 1'b1;
if (!dcc_en) ctype_prev[1:0] <= 2'b11;
else if (start[0]) ctype_prev[1:0] <= {ctype_prev[0],ctype && dcc_run};
if (dcc_stb || hfc_copy) dcc_acc[12:0] <= hfc_copy?
hfc_acc[12:0]:
{(d2_dct[10]&&ctype_prev[0]),(d2_dct[10]&&ctype_prev[0]),d2_dct[10:0]}+((ctype_prev[0] || ctype_prev[1])?13'h0:dcc_acc[12:0]);
if (!dcc_run || hfc_copy) hfc_acc <=13'b0;
else if (hfc_en) hfc_acc <= hfc_acc + {2'b0, d3[10:0]};
if (dcc_stb) dcc_first <= color_first && dcc_run && dcc_stb && ctype && !ctype_prev[0];
if (dcc_stb) dcc_Y <= dcc_run && dcc_stb && ctype && !ctype_prev[0];
dcc_vld <= (dcc_run && dcc_stb && (ctype || ctype_prev[0] || sel_satnum)) || hfc_copy;
end
SRL16 i_hfc_en (.Q(hfc_en), .A0(1'b1), .A1(1'b0), .A2(1'b0), .A3(1'b0), .CLK(clk),
.D(((tba[2:0]>hfc_sel[2:0]) || (tba[5:3]>hfc_sel[2:0])) && dcc_run && !ctype_prev[0])); // dly=1+1
zigzag i_zigzag( .clk(clk),
.start(start_z),
.q(zwa[5:0]));
always @ (negedge sclk) twqe_d <= twqe;
always @ (negedge sclk) twce_d <= twce;
RAMB16_S18_S18 i_quant_table (
.DOA(tdo[15:0]), // Port A 16-bit Data Output
.DOPA(), // Port A 2-bit Parity Output
.ADDRA({tba[9:6],tba[2:0],tba[5:3]}), // Port A 10-bit Address Input
.CLKA(clk), // Port A Clock
.DIA(16'b0), // Port A 16-bit Data Input
.DIPA(2'b0), // Port A 2-bit parity Input
.ENA(1'b1), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(1'b0), // Port A Write Enable Input
.DOB(), // Port B 16-bit Data Output
.DOPB(), // Port B 2-bit Parity Output
.ADDRB({ta[8:0],twqe_d}), // Port B 10-bit Address Input
.CLKB(!sclk), // Port B Clock
.DIB(tdi[15:0]), // Port B 16-bit Data Input
.DIPB(2'b0), // Port-B 2-bit parity Input
.ENB(1'b1), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(twqe || twqe_d) // Port B Write Enable Input
);
RAMB16_S4_S18 i_coring_table (
.DOA(tdco[3:0]), // Port A 4-bit Data Output
.ADDRA({tbac[3:0],qmulr[11:4]}), // Port A 12-bit Address Input
.CLKA(clk), // Port A Clock
.DIA(4'b0), // Port A 4-bit Data Input
.ENA(1'b1), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(1'b0), // Port A Write Enable Input
.DOB(), // Port B 16-bit Data Output
.DOPB(), // Port B 2-bit Parity Output
.ADDRB({ta[8:0],twce_d}), // Port B 10-bit Address Input
.CLKB(!sclk), // Port B Clock
.DIB(tdi[15:0]), // Port B 16-bit Data Input
.DIPB(2'b0), // Port-B 2-bit parity Input
.ENB(1'b1), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(twce || twce_d) // Port B Write Enable Input
);
RAMB16_S18_S18 i_zigzagbuf (
.DOA(), // Port A 16-bit Data Output
.DOPA(), // Port A 2-bit Parity Output
.ADDRA({3'b0,wpage,zwa[5:0]}), // Port A 10-bit Address Input
.CLKA(clk), // Port A Clock
.DIA({3'b0,qdo[12:0]}), // Port A 16-bit Data Input
.DIPA(2'b0), // Port A 2-bit parity Input
.ENA(1'b1), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(zwe), // Port A Write Enable Input
.DOB(zigzag_q[15:0]), // Port B 16-bit Data Output
.DOPB(), // Port B 2-bit Parity Output
.ADDRB({3'b0,rpage,zra[5:0]}), // Port B 10-bit Address Input
.CLKB(clk), // Port B Clock
.DIB(16'b0), // Port B 16-bit Data Input
.DIPB(2'b0), // Port-B 2-bit parity Input
.ENB(next_dv), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(1'b0) // Port B Write Enable Input
);
endmodule
// Alternative ZigZag distributed ROM. More convinient, but extra resources. Use upper half of quantization table to save slices.
module zigzag (clk,
start,
q);
input clk, start;
output [5:0] q;
reg [5:0] a;
reg [5:0] q;
wire [4:0] rom_a;
wire [5:0] rom_q;
assign rom_a[4:0]=a[5]?(~a[4:0]):a[4:0];
always @ (posedge clk) begin
if (start) a[5:0] <= 6'b0;
// else a[5:0] <= a[5:0]+1; // may add if (a[5:0]!=6'h3f) to make cleaner simulation and conserve energy
else if (a[5:0]!=6'h3f) a[5:0] <= a[5:0]+1;
q[5:0] <= a[5]? (~rom_q[5:0]):rom_q[5:0];
end
ROM32X1 #(.INIT(32'hC67319CC)) i_z0 ( .A0(rom_a[0]), .A1(rom_a[1]), .A2(rom_a[2]), .A3(rom_a[3]), .A4(rom_a[4]), .O(rom_q[0]));
ROM32X1 #(.INIT(32'h611A7896)) i_z1 ( .A0(rom_a[0]), .A1(rom_a[1]), .A2(rom_a[2]), .A3(rom_a[3]), .A4(rom_a[4]), .O(rom_q[1]));
ROM32X1 #(.INIT(32'h6357A260)) i_z2 ( .A0(rom_a[0]), .A1(rom_a[1]), .A2(rom_a[2]), .A3(rom_a[3]), .A4(rom_a[4]), .O(rom_q[2]));
ROM32X1 #(.INIT(32'h4A040C18)) i_z3 ( .A0(rom_a[0]), .A1(rom_a[1]), .A2(rom_a[2]), .A3(rom_a[3]), .A4(rom_a[4]), .O(rom_q[3]));
ROM32X1 #(.INIT(32'h8C983060)) i_z4 ( .A0(rom_a[0]), .A1(rom_a[1]), .A2(rom_a[2]), .A3(rom_a[3]), .A4(rom_a[4]), .O(rom_q[4]));
ROM32X1 #(.INIT(32'hF0E0C080)) i_z5 ( .A0(rom_a[0]), .A1(rom_a[1]), .A2(rom_a[2]), .A3(rom_a[3]), .A4(rom_a[4]), .O(rom_q[5]));
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/stuffer333.v 0000664 0000000 0000000 00000042362 12555570767 0023551 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** stuffer333.v
**etrax_dma
** Bit stuffer for JPEG encoder
**
** Copyright (C) 2002-2010 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X333
** X333 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
`define debug_compressor
// 08.27.2005 - modified "rdy" - moved register to make it faster.
// 01.22.2004 - fixed bug if flush comes with !rdy (required mod of huffman.v to extend "flush" until ready)
// 02.05.2004 - modified data length output. It is 24 it ow, in bytes and is output as last 4 bytes in the
// data block that is 32-byte DMA page aligned
// running on v8.2i - does not meet constraints with enabled global USE_SYNC_SET yes/auto because set input is slower. Trying to selectively disable it
// synthesis attribute use_sync_set of stuffer is no;
// synthesis attribute use_sync_reset of stuffer is no;
// synthesis attribute use_clock_enable of stuffer is no;
module stuffer (clk, //clock
en, // enable, 0- reset
reset_data_counters, // reset data transfer counters (only when DMA and compressor are disabled)
flush, // flush output data (fill byte with 0, long word with 0
stb, // input data strobe
dl, // [3:0] number of bits to send (0 - 16)
d, // [15:0] input data to shift (only lower bits are valid)
// time stamping - will copy time at the end of color_first (later than the first hact after vact in the current froma, but before the next one
// and before the data is needed for output
color_first, //
sec, // [31:0] number of seconds
usec, // [19:0] number of microseconds
rdy, // enable huffman encoder to proceed. Used as CE for many huffman encoder registers
q, // [15:0] output data
qv, // output data valid
done,// reset by !en, goes high after some delay after flushing
imgptr, // [23:0]image pointer in 32-byte chunks
flushing
`ifdef debug_stuffer
,etrax_dma_r, // [3:0] just for testing
test_cntr,
test_cntr1
`endif
);
input clk;
input en;
input reset_data_counters; // reset data transfer counters (only when DMA and compressor are disabled)
input flush;
input stb;
input [ 3:0] dl;
input [15:0] d;
input color_first; //
input [31:0] sec; // sync to pclk at first hact after vact
input [19:0] usec;
output rdy;
output [15:0] q;
output qv;
output done;
output [23:0] imgptr;
output flushing;
`ifdef debug_stuffer
output [3:0] etrax_dma_r; // just for testing
output [3:0] test_cntr; // just for testing
output [7:0] test_cntr1; // just for testing
reg [3:0] etrax_dma_r; // just for testing
reg [3:0] test_cntr; // just for testing
reg [7:0] test_cntr1; // just for testing
reg en_d;
`endif
wire rdy; // can only go low while flushing and inserting 00 after ff
// reg rdy_reg;
// wire inc8; // increment bit counter by 8 after inserting 00 after ff TBD
reg [23:1] stage1; // stage 1 register (after right-shifting input data by 0..7 - actually left by 7..0)
wire [2:0] shift1; // shift amount for stage 1
reg [4:0] stage1_bits; // number of topmost invalid bits in stage1 register - 2 MSBs, use lower 3 stage2_bits
reg [4:0] stage1_length; // number of bits (1..16) in stage 1 register
reg flushing;
wire flush_end;
reg stage1_full;
wire [7:0] byteMask;
wire [31:1] longMask;
wire [31:1] dflt_stage2;
wire [ 2:0] sel;
wire [ 1:0] st2m;
wire [31:1] st2_d;
reg [31:1] stage2;
reg [ 4:0] stage2_bits;
wire send8h, send8l, send8;
reg [15:0] q;
reg qv;
reg flush_end_delayed; // update: fixed delay some delay after flush_end to ensure combining with output FIFO empty
wire pre_flush_end_delayed; // some delay after flush_end to ensure combining with output FIFO empty
wire done;
reg [23:0] size_count; //(now will be byte count)
// to make it faster - split in parts
reg inc_size_count2316;
reg [ 2:0] size_out;
reg size_out_over; // only needed with extra 32 bytes of zeroes added.
reg busy_eob; // flushing and sending length
reg trailer, was_trailer; // sending out data length and 32 bytes for ETRAX
reg [ 3:0] etrax_dma; // count words to make total size multiple of 32 bytes.
// Last 4 bytes of data will have actual length in bytes
// There will always be at least 4 more bytes (0-es) before length - needed for software
reg will_flush; // next dv will be flushing byte/word
wire flush_now;
wire start_sizeout; //delay by 2 cycles
reg send8h_r, send8l_r;
wire pre_stage2_bits_3; // what will be registered to stage2_bits[3];
wire [4:3] willbe_stage1_bits;
wire [3:0] sum_lengths;
reg [1:0] st2m_r;
reg [2:0] stb_time;
reg [31:0] sec_r;
reg [19:0] usec_r;
reg time_out;
reg time_size_out;
wire start_time_out;
// stb_time[2] - single-cycle pulse after color_first goes low
reg [23:0] imgptr; //updated after each frame compressed (points to start of next frame)
reg [19:0] imgsz32; // current image size in multiples of 32-bytes
reg inc_imgsz32;
always @ (negedge clk) flushing <= en && !flush_end && ((flush && rdy) || flushing);
wire [4:0] pre_stage1_bits;
assign pre_stage1_bits[4:0]={2'b00,stage1_bits[2:0]} + {(dl[3:0]==4'b0),dl[3:0]};
always @ (negedge clk) begin
if (!en || flush_end) stage1_bits[4:0] <= 5'b0;
else if (stb && rdy) stage1_bits <= {(2'b10-pre_stage1_bits[4:3]),pre_stage1_bits[2:0]};
end
assign shift1[2:0]= stage1_bits[2:0] + dl[2:0];
always @ (negedge clk) if (stb && rdy) begin
case (shift1[2:0])
0: stage1[23:1] <= { d[15:0],7'b0};
1: stage1[23:1] <= {1'b0,d[15:0],6'b0};
2: stage1[23:1] <= {2'b0,d[15:0],5'b0};
3: stage1[23:1] <= {3'b0,d[15:0],4'b0};
4: stage1[23:1] <= {4'b0,d[15:0],3'b0};
5: stage1[23:1] <= {5'b0,d[15:0],2'b0};
6: stage1[23:1] <= {6'b0,d[15:0],1'b0};
7: stage1[23:1] <= {7'b0,d[15:0] };
endcase
stage1_length[4:0] <= {(dl[3:0]==4'b0),dl[3:0]};
end
//*****************************
always @ (negedge clk) begin
if (!en) stage2_bits <= 5'b0;
else if (send8) stage2_bits[4:0] <= stage2_bits[4:0] - 8;
else if (flushing && !stage1_full && !stage2_bits[4] && (stage2_bits[3:0]!=4'b0)) stage2_bits[4:0]<=5'h10; // actual flushing to word size
else stage2_bits[4:0] <= (rdy && stage1_full)? {1'b0,stage2_bits[3:0]}+stage1_length[4:0]:{1'b0,stage2_bits[3:0]};
end
assign sum_lengths=stage2_bits[3:0]+stage1_length[3:0];
assign pre_stage2_bits_3= en &&
(send8? (~stage2_bits[3]): (
!(flushing && !stage1_full && !stage2_bits[4] && (stage2_bits[3:0]!=4'b0)) && // not flushing
((rdy && stage1_full)?sum_lengths[3]: stage2_bits[3] )
));
assign willbe_stage1_bits[4:3]={2{en && !flush_end}} & ((stb && rdy)?(2'b10-pre_stage1_bits[4:3]):stage1_bits[4:3]);
// assign rdy =(!stage2_bits[4] || (!send8h_r && !send8l_r)) && !busy_eob;
// accelerating rdy calculation - making it a register
wire pre_busy_eob=en && !flush_end_delayed && (busy_eob || (flush && rdy));
wire [4:3] pre_stage2_bits_4_interm1=stage2_bits[4:3]-2'h1;
wire [4:0] pre_stage2_bits_4_interm2={1'b0,stage2_bits[3:0]}+stage1_length[4:0];
wire pre_stage2_bits_4=en && (send8?
(pre_stage2_bits_4_interm1[4]):
((flushing && !stage1_full && !stage2_bits[4] && (stage2_bits[3:0]!=4'b0))?
(1'b1):
(((rdy && stage1_full))?
(pre_stage2_bits_4_interm2[4]):
(1'b0)
)
)
);
// if ( send8h_r && stage2_bits[4]) send8h_r <= &stage2[23:16];
// else if (!send8l_r || !stage2_bits[4]) send8h_r <= &((longMask[31:24] & st2_d[31:24]) | (~longMask[31:24] & dflt_stage2[31:24]));
wire pre_send8h_r= (( send8h_r && stage2_bits[4])?
(&stage2[23:16]):
((!send8l_r || !stage2_bits[4])?
(&((longMask[31:24] & st2_d[31:24]) | (~longMask[31:24] & dflt_stage2[31:24]))):
(send8h_r)
)
);
// if (( send8h_r || send8l_r) && stage2_bits[4]) send8l_r <= &stage2[15:8];
// else send8l_r <= &((longMask[23:16] & st2_d[23:16]) | (~longMask[23:16] & dflt_stage2[23:16]));
wire pre_send8l_r= ((( send8h_r || send8l_r) && stage2_bits[4] )?
(&stage2[15:8]):
(&((longMask[23:16] & st2_d[23:16]) | (~longMask[23:16] & dflt_stage2[23:16])))
);
// assign rdy =(!stage2_bits[4] || (!send8h_r && !send8l_r)) && !busy_eob;
//Trying to delay rdy to make more room before it
reg rdy_rega,rdy_regb, rdy_regc, rdy_regd;
// s ynthesis attribute use_sync_set of {module_name|signal_name|instance_name} [is] no;
always @ (negedge clk) begin
// rdy_reg <= (!pre_stage2_bits_4 || (!pre_send8h_r && !pre_send8l_r)) && !pre_busy_eob;
rdy_rega <= !pre_stage2_bits_4;
rdy_regb <= !pre_send8h_r;
rdy_regc <= !pre_send8l_r;
rdy_regd <= !pre_busy_eob;
busy_eob <= pre_busy_eob;
//**********************************
send8h_r<=pre_send8h_r;
send8l_r<=pre_send8l_r;
end
// assign rdy = rdy_reg;
assign rdy = (rdy_rega || (rdy_regb && rdy_regc)) && rdy_regd;
assign send8h= send8h_r && stage2_bits[4];
assign send8l= send8l_r && stage2_bits[4];
assign send8=stage2_bits[4] && (send8h_r || send8l_r);
always @ (negedge clk) begin
if (!en) stage1_full <= 1'b0;
/// else if (rdy) stage1_full <=stb;
/* TODO: MAke sure it is OK !! 05/12/2010 */
// else if (rdy) stage1_full <=stb && !flushing; //force flush does not turn off stb, in normal operation flushing is after last stb
else if (flushing) stage1_full <= 1'b0; //force flush does not turn off stb, in normal operation flushing is after last stb
else if (rdy) stage1_full <=stb; //force flush does not turn off stb, in normal operation flushing is after last stb
end
assign sel[2:0]=stage2_bits[2:0];
assign byteMask[7:0]= {!sel[2] && !sel[1] && !sel[0],
!sel[2] && !sel[1],
!sel[2] && (!sel[1] || !sel[0]),
!sel[2],
!sel[2] || (!sel[1] && !sel[0]),
!sel[2] || !sel[1],
!sel[2] || !sel[1] || !sel[0],
1'b1
};
//TODO: Try to move stage1_full up here, this is the time-limiting path 05.26.2010
assign longMask[31:1]={{8{(flushing || stage1_full) && !stage2_bits[3]}} & byteMask[7:0],
{8{flushing || stage1_full}} & ({8{!stage2_bits[3]}} | byteMask[7:0]),
{8{stage1_full}},
{7{stage1_full}}};
always @ (negedge clk) st2m_r[1:0]<=willbe_stage1_bits[4:3]-{1'b0,pre_stage2_bits_3};
assign st2m[1:0]=st2m_r[1:0];
assign st2_d[31:1]= {{8{!flushing || stage1_full}} & (st2m[1]?{stage1[7:1],1'b0}:(st2m[0]? stage1[15:8]: stage1[23:16])),
{8{!flushing || stage1_full}} & (st2m[1]? stage1[23:16]: (st2m[0]?{stage1[7:1],1'b0}:stage1[15: 8])),
st2m[1]? stage1[15: 8]: {stage1[7:1],1'b0},
{stage1[7:1]}};
assign dflt_stage2=stage2_bits[4]?{stage2[15:1],16'b0}:{stage2[31:1]};
always @ (negedge clk) begin
if (send8h) stage2[31:24] <= stage2[23:16];
else if (send8l) stage2[31:24] <= 8'h00;
else stage2[31:24] <= (longMask[31:24] & st2_d[31:24]) | (~longMask[31:24] & dflt_stage2[31:24]);
if (send8) stage2[23:16] <= stage2[15:8];
else stage2[23:16] <= (longMask[23:16] & st2_d[23:16]) | (~longMask[23:16] & dflt_stage2[23:16]);
if (send8) stage2[15: 8] <= {stage2[7:1],1'b0};
else stage2[15: 8] <= (longMask[15: 8] & st2_d[15: 8]) | (~longMask[15: 8] & dflt_stage2[15: 8]);
if (send8) stage2[7: 1] <= 7'b0;
else stage2[7: 1] <= (longMask[7: 1] & st2_d[7: 1]) | (~longMask[7: 1] & dflt_stage2[7: 1]);
end
// output stage
assign flush_end= !stage2_bits[4] && flushing && !stage1_full && (stage2_bits[3:0]==4'b0);
assign flush_now= en && (!send8) && (flushing && !stage1_full && !stage2_bits[4]) && !will_flush;
always @ (negedge clk) begin
stb_time[2:0] <= {stb_time[1] & ~stb_time[0], stb_time[0],color_first};
if (stb_time[2]) sec_r[31:0] <= sec[31:0];
else if (start_sizeout) sec_r[31:0] <= {8'hff, size_count[23:0]};
else if (time_size_out) sec_r[31:0] <= {usec_r[15:0],sec_r[31:16]};
if (stb_time[2]) usec_r[19:0] <= usec[19:0];
else if (time_out) usec_r[19:0] <= {16'h0,usec_r[19:16]};
//reset_data_counters; // reset data transfer counters (only when DMA and compressor are disabled)
// if (!en ) etrax_dma[3:0] <= 0; // not needed to be reset after frame, and that was wrong (to early)
if (reset_data_counters ) etrax_dma[3:0] <= 0; // not needed to be reset after frame, and that was wrong (to early)
else if (qv) etrax_dma[3:0] <= etrax_dma[3:0] + 1;
// just for testing
`ifdef debug_stuffer
reg [3:0] tst_done_dly;
en_d<= en;
if (en) etrax_dma_r[3:0] <= etrax_dma[3:0];
// if (en && ! en_d) test_cntr[3:0] <= test_cntr[3:0]+1;
if (done) test_cntr1[7:0] <= 0;
else if (qv) test_cntr1[7:0] <= test_cntr1[7:0] +1 ; // normally should be one (done 1 ahead of end of qv)
tst_done_dly[3:0] <= {tst_done_dly[2:0],done};
if (tst_done_dly[1]) test_cntr[3:0] <= 0;
else if (qv) test_cntr[3:0] <= test_cntr[3:0] +1 ;
`endif
size_out_over <= en && (size_out_over?(!done):size_out[0]);
size_out[2:0]<={size_out[1:0],start_sizeout};
// time_out <= en && (start_time_out || (time_out && !(etrax_dma[3:0]== 4'hc)));
// time_size_out <= en && (start_time_out || (time_out && !(etrax_dma[3:0]== 4'he)));
time_out <= en && (start_time_out || (time_out && !(etrax_dma[3:2]== 2'h3)));
time_size_out <= en && (start_time_out || (time_size_out && !(etrax_dma[3:1]== 3'h7)));
trailer <= en && (trailer?(!flush_end_delayed):(flush_end));
was_trailer<=trailer;
will_flush <= en && (will_flush?(!qv):(flush_now && (stage2_bits[3:0]!=4'b0)));
if (flush_now) size_count[0] <= stage2_bits[3] ^ (|stage2_bits[2:0]); // odd number of bytes
if (!en || size_out[2]) size_count[15:1] <= 0;
else if (!trailer && !was_trailer && qv && (!will_flush || !size_count[0])) size_count[15:1] <= size_count[15:1]+1;
inc_size_count2316 <= (!trailer && !was_trailer && qv && (!will_flush || !size_count[0])) && (&size_count[15:1]);
//reset_data_counters instead of !en here?
if (!en || size_out[2]) size_count[23:16] <= 0;
else if (inc_size_count2316) size_count[23:16] <= size_count[23:16]+1;
qv <= en && (stage2_bits[4] || trailer);
// to make it faster (if needed) use a single register as a source for q[15:0] in two following lines
// if (time_out) q[15:0] <= sec_r[15:0];
// else if (|size_out[1:0]) q[15:0] <= size_out[0]?{size_count[7:0],size_count[15:8]}:{size_count[23:16],8'hff};
if (time_size_out) q[15:0] <= {sec_r[7:0],sec_r[15:8]};
// else if (|size_out[1:0]) q[15:0] <= size_out[0]?{size_count[7:0],size_count[15:8]}:{size_count[23:16],8'hff};
else q[15:0] <= {(stage2_bits[4]?stage2[31:24]:8'b0),
((stage2_bits[4] && !send8h)? stage2[23:16]:8'b0)};
inc_imgsz32 <= (etrax_dma[3:0]== 4'h0) && qv;
//reset_data_counters instead of !en here?
// if (!en || done) imgsz32[19:0] <= 0;
if (reset_data_counters || done) imgsz32[19:0] <= 0;
else if (inc_imgsz32) imgsz32[19:0]<=imgsz32[19:0]+1;
// if (!en) imgptr[23:0] <= 0;
if (reset_data_counters) imgptr[23:0] <= 0;
else if (done) imgptr[23:0] <= imgptr[23:0]+ imgsz32[19:0];
flush_end_delayed <= en & pre_flush_end_delayed; // en just to prevent optimizing pre_flush_end_delayed+flush_end_delayed into a single SRL16
end
//start_sizeout
//assign start_sizeout= qv && trailer && (etrax_dma[3:0]== 4'hc) && !size_out_over;
assign start_time_out= qv && trailer && (etrax_dma[3:0]== 4'h8) && !size_out_over;
assign start_sizeout= time_out && (etrax_dma[3:0]== 4'hc);
SRL16_1 i_pre_flush_end_delayed (.D(size_out[1]),.Q(pre_flush_end_delayed), .A0(1'b0), .A1(1'b1), .A2(1'b1), .A3(1'b1), .CLK(clk)); // dly=3+1 // rather arbitrary?
assign done = flush_end_delayed;
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/compressor/xdct353.v 0000664 0000000 0000000 00000065072 12555570767 0023042 0 ustar 00root root 0000000 0000000
/**********************************************************************
** -----------------------------------------------------------------------------**
** xdct333.v
**
** 8x8 discrete Cosine Transform
**
** Copyright (C) 2002-2008 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X333
** X333 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
** Modified by Andrey Filippov - goal to make it work in start/stop mode, using
** "start" input (going together with the first data, no restriction on the gap between 64-pixel blocks (>=0)
** Removed "RST" input ("en" is only used to reset ping-pong transpose memory address)
** Split module in 2 stages
** Lost architecture-independence, but it is OK for me
** Also saved some area - original design compiled by XST to 865 slices (XC2S300e), this one - 780!
**
** It is based on the original design (Xilix app. note XAPP610) by:
** Author: Latha Pillai
** Senior Applications Engineer
**
** Video Applications
** Advanced Products Group
** Xilinx, Inc.
**
** Copyright (c) 2001 Xilinx, Inc.
** All rights reserved
**
** Date: Feb. 10, 2002
**
** RESTRICTED RIGHTS LEGEND
**
** This software has not been published by the author, and
** has been disclosed to others for the purpose of enhancing
** and promoting design productivity in Xilinx products.
**
** Therefore use, duplication or disclosure, now and in the
** future should give consideration to the productivity
** enhancements afforded the user of this code by the author's
** efforts. Thank you for using our products !
**
** Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY
** WHATSOEVER AND XILINX SPECIFICALLY DISCLAIMS ANY
** IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
** A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT.
***********************************************************************/
/*
after I added DC subtraction before DCT I got 9-bit (allthough not likely to go out of 8bit range) signed data.
also increased transpose memory to 9 bits (anyway it is 16-bit wide) - see if it will help to prevent saturation
without significant increase in gates
Saturatuion is still visible on real pictures, but there was a bug - addsuba_comp, addsubb_comp where not using their
MSB. I added 1 more bit to add_suba and add_subb and fixed that bug. Only 2 mofre slices were used
Device utilization summary:
Number of External GCLKIOBs 1 out of 4 25%
Number of External IOBs 23 out of 178 12%
Number of LOCed External IOBs 0 out of 23 0%
Number of BLOCKRAMs 1 out of 16 6%
Number of SLICEs 855 out of 3072 27%
Number of GCLKs 1 out of 4 25%
*/
// still not enough - maybe one tiny bit more??
/*
Device utilization summary:
Number of External GCLKIOBs 1 out of 4 25%
Number of External IOBs 26 out of 178 14%
Number of LOCed External IOBs 0 out of 26 0%
Number of BLOCKRAMs 1 out of 16 6%
Number of SLICEs 837 out of 3072 27%
Number of GCLKs 1 out of 4 25%
*/
`timescale 1ns/1ps
// For xdct353 - increasing data in 9 bits -> 10 bits, out 12 bits ->13 bits
module xdct ( clk, // top level module
en, // if zero will reset transpose memory page njumbers
start, // single-cycle start pulse that goes with the first pixel data. Other 63 should follow
xin, // [7:0] - input data
last_in, // output high during input of the last of 64 pixels in a 8x8 block
pre_first_out,// 1 cycle ahead of the first output in a 64 block
dv, // data output valid. Will go high on the 94-th cycle after the start
d_out);// [8:0]output data
input clk;
input en,start;
input [9:0] xin;
output last_in;
output pre_first_out;
output dv;
output [12:0] d_out;
wire clk, en,start,dv,stage1_done, tm_page,tm_we;
wire [9:0] xin;
wire [12:0] d_out;
wire [6:0] tm_ra;
wire [6:0] tm_wa;
wire [15:0] tm_out;
wire [15:0] tm_di;
reg last_in;
wire pre_first_out;
always @ (posedge clk) last_in <= (tm_wa[5:0]== 6'h30);
dct_stage1 i_dct_stage1( .clk(clk),
.en(en),
.start(start),
.xin(xin), // [7:0]
.we(tm_we), // write to transpose memory
.wr_cntr(tm_wa), // [6:0] transpose memory write address
.z_out(tm_di[15:0]),
.page(tm_page),
.done(stage1_done));
dct_stage2 i_dct_stage2( .clk(clk),
.en(en),
.start(stage1_done), // stage 1 finished, data available in transpose memory
.page(tm_page), // transpose memory page finished, valid at start
.rd_cntr(tm_ra[6:0]), // [6:0] transpose memory read address
.tdin(tm_out[15:0]), // [7:0] - data from transpose memory
.endv(pre_first_out),
.dv(dv), // data output valid
.dct2_out(d_out[12:0]));// [10:0]output data
RAMB16_S18_S18 i_transpose_mem (
.DOA(), // Port A 16-bit Data Output
.DOPA(), // Port A 2-bit Parity Output
.ADDRA({3'b0,tm_wa[6:0]}), // Port A 10-bit Address Input
.CLKA(clk), // Port A Clock
// .DIA({6'b0,tm_di[9:0]}), // Port A 16-bit Data Input
.DIA(tm_di[15:0]), // Port A 16-bit Data Input
.DIPA(2'b0), // Port A 2-bit parity Input
.ENA(1'b1), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(tm_we), // Port A Write Enable Input
.DOB(tm_out[15:0]), // Port B 16-bit Data Output
.DOPB(), // Port B 2-bit Parity Output
.ADDRB({3'b0,tm_ra[6:0]}), // Port B 10-bit Address Input
.CLKB(clk), // Port B Clock
.DIB(16'b0), // Port B 16-bit Data Input
.DIPB(2'b0), // Port-B 2-bit parity Input
.ENB(1'b1), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(1'b0) // Port B Write Enable Input
);
endmodule
// 01/24/2004: Moved all clocks in stage 1 to "negedge" to reduce current pulses
module dct_stage1 ( clk,
en,
start, // single-cycle start pulse to replace RST
xin, // [7:0]
we, // write to transpose memory
wr_cntr, // [6:0] transpose memory write address
z_out, //data to transpose memory
page, // transpose memory page just filled (valid @ done)
done); // last cycle writing to transpose memory - may use after it (move it earlier?)
input clk;
input en,start;
input [9:0] xin;
output we;
output [6:0] wr_cntr;
output [15:0] z_out;
output page;
output done;
/* constants */
parameter C3= 16'd54491;
parameter S3= 16'd36410;
parameter C4= 16'd46341;
parameter C6= 16'd25080;
parameter S6= 16'd60547;
parameter C7= 16'd12785;
parameter S7= 16'd64277;
reg[16:0] memory1a, memory2a, memory3a, memory4a;
/* 1D section */
/* The max value of a pixel after processing (to make their expected mean to zero)
is 127. If all the values in a row are 127, the max value of the product terms
would be (127*2)*(23170/256) and that of z_out_int would be (127*8)*23170/256.
This value divided by 2raised to 8 is equivalent to ignoring the 8 lsb bits of the value */
reg[9:0] xa0_in, xa1_in, xa2_in, xa3_in, xa4_in, xa5_in, xa6_in, xa7_in;
reg[9:0] xa0_reg, xa1_reg, xa2_reg, xa3_reg, xa4_reg, xa5_reg, xa6_reg, xa7_reg;
reg[9:0] addsub1a_comp,addsub2a_comp,addsub3a_comp,addsub4a_comp;
reg[10:0] add_sub1a,add_sub2a,add_sub3a,add_sub4a;
reg save_sign1a, save_sign2a, save_sign3a, save_sign4a;
reg[17:0] p1a,p2a,p3a,p4a;
wire[35:0] p1a_all,p2a_all,p3a_all,p4a_all;
reg toggleA;
reg[18:0] z_out_int1,z_out_int2;
reg[18:0] z_out_int;
wire[15:0] z_out_prelatch;
reg [2:0] indexi;
/* clks and counters */
reg [6:0] wr_cntr_prelatch;
/* memory section */
reg done_prelatch;
reg we_prelatch;
wire enwe;
wire pre_sxregs;
reg sxregs;
reg page_prelatch;
// outputs from output latches to cross clock edge boundary
//wire[9:0] z_out;
//wire[6:0] wr_cntr;
//wire done;
//wire we;
//wire page;
// outputs from output latches to cross clock edge boundary
reg [15:0] z_out;
reg [ 6:0] wr_cntr;
reg done;
reg we;
reg page;
// to conserve energy by disabling toggleA
wire sxregs_d8;
reg enable_toggle;
SRL16_1 i_sxregs_d8 (.Q(sxregs_d8), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b0), .CLK(clk),.D(sxregs)); // dly=7+1
always @ (negedge clk) enable_toggle <= en && (sxregs || (enable_toggle && !sxregs_d8));
always @ (negedge clk) done_prelatch<= (wr_cntr_prelatch[5:0]==6'h3f);
always @ (negedge clk) if (wr_cntr_prelatch[5:0]==6'h3f) page_prelatch <= wr_cntr_prelatch[6];
always @ (negedge clk) we_prelatch<= enwe || (en && we_prelatch && (wr_cntr_prelatch[5:0]!=6'h3f));
always @ (negedge clk )
if (!en) wr_cntr_prelatch <= 7'b0;
else if (we_prelatch) wr_cntr_prelatch <= wr_cntr_prelatch + 1;
SRL16_1 i_pre_sxregs (.Q(pre_sxregs), .A0(1'b0), .A1(1'b1), .A2(1'b1), .A3(1'b0), .CLK(clk), .D(start)); // dly=6+1
SRL16_1 i_enwe (.Q(enwe), .A0(1'b1), .A1(1'b0), .A2(1'b1), .A3(1'b0), .CLK(clk), .D(pre_sxregs)); // dly=5+1
always @ (negedge clk ) sxregs <= pre_sxregs || ((wr_cntr_prelatch[2:0]==3'h1) && (wr_cntr_prelatch[5:3]!=3'h7));
always @ (negedge clk) toggleA <= sxregs || (enable_toggle && (~toggleA));
always @ (negedge clk)
if (sxregs) indexi <= 3'h7;
else if (enable_toggle) indexi<=indexi+1;
/* 1D-DCT BEGIN */
// store 1D-DCT constant coeeficient values for multipliers */
always @ (negedge clk)
begin
case (indexi)
0 : begin memory1a <= {1'b0,C4}; //8'd91
memory2a <= {1'b0,C4}; //8'd91
memory3a <= {1'b0,C4}; //8'd91
memory4a <= {1'b0,C4}; //8'd91
end
1 : begin memory1a <= {1'b0,S7}; //8'd126;
memory2a <= {1'b0,C3}; //8'd106;
memory3a <= {1'b0,S3}; //8'd71;
memory4a <= {1'b0,C7}; //8'd25;
end
2 : begin memory1a <= {1'b0,S6}; //8'd118;
memory2a <= {1'b0,C6}; //8'd49;
memory3a <= {1'b1,C6}; //-8'd49;
memory4a <= {1'b1,S6}; //-8'd118
end
3 : begin memory1a <= {1'b0,C3}; // 8'd106;
memory2a <= {1'b1,C7}; //-8'd25;
memory3a <= {1'b1,S7}; //-8'd126;
memory4a <= {1'b1,S3}; //-8'd71;
end
4 : begin memory1a <= {1'b0,C4}; // 8'd91;
memory2a <= {1'b1,C4}; //-8'd91;
memory3a <= {1'b1,C4}; //-8'd91;
memory4a <= {1'b0,C4}; // 8'd91;
end
5 : begin memory1a <= {1'b0,S3}; // 8'd71;
memory2a <= {1'b1,S7}; //-8'd126;
memory3a <= {1'b0,C7}; // 8'd25;
memory4a <= {1'b0,C3}; // 8'd106;
end
6 : begin memory1a <= {1'b0,C6}; // 8'd49;
memory2a <= {1'b1,S6}; //-8'd118;
memory3a <= {1'b0,S6}; // 8'd118;
memory4a <= {1'b1,C6}; //-8'd49;
end
7 : begin memory1a <= {1'b0,C7}; // 8'd25;
memory2a <= {1'b1,S3}; //-8'd71;
memory3a <= {1'b0,C3}; // 8'd106;
memory4a <= {1'b1,S7}; //-8'd126;
end
endcase
end
/* 8-bit input shifted 8 times thru a shift register*/
// xa0_in will see output registers from posedge, may be replaced by latches if needed - but currently delay is under 5ns
always @ (negedge clk)
begin
xa0_in <= xin; xa1_in <= xa0_in; xa2_in <= xa1_in; xa3_in <= xa2_in;
xa4_in <= xa3_in; xa5_in <= xa4_in; xa6_in <= xa5_in; xa7_in <= xa6_in;
end
/* shifted inputs registered every 8th clk (using cntr8)*/
always @ (negedge clk)
if (sxregs)
begin
xa0_reg <= {xa0_in}; xa1_reg <= {xa1_in};
xa2_reg <= {xa2_in}; xa3_reg <= {xa3_in};
xa4_reg <= {xa4_in}; xa5_reg <= {xa5_in};
xa6_reg <= {xa6_in}; xa7_reg <= {xa7_in};
end
/* adder / subtractor block */
always @ (negedge clk)
if (toggleA == 1'b1) begin
add_sub1a <= ({xa7_reg[9],xa7_reg[9:0]} + {xa0_reg[9],xa0_reg[9:0]});
add_sub2a <= ({xa6_reg[9],xa6_reg[9:0]} + {xa1_reg[9],xa1_reg[9:0]});
add_sub3a <= ({xa5_reg[9],xa5_reg[9:0]} + {xa2_reg[9],xa2_reg[9:0]});
add_sub4a <= ({xa4_reg[9],xa4_reg[9:0]} + {xa3_reg[9],xa3_reg[9:0]});
end else begin
add_sub1a <= ({xa7_reg[9],xa7_reg[9:0]} - {xa0_reg[9],xa0_reg[9:0]});
add_sub2a <= ({xa6_reg[9],xa6_reg[9:0]} - {xa1_reg[9],xa1_reg[9:0]});
add_sub3a <= ({xa5_reg[9],xa5_reg[9:0]} - {xa2_reg[9],xa2_reg[9:0]});
add_sub4a <= ({xa4_reg[9],xa4_reg[9:0]} - {xa3_reg[9],xa3_reg[9:0]});
end
// First valid add_sub appears at the 10th clk (8 clks for shifting inputs,
// 9th clk for registering shifted input and 10th clk for add_sub
// to synchronize the i value to the add_sub value, i value is incremented
// only after 10 clks
// Adding these wires to get rid of the MSB that is always 0
wire [10:0] addsub1a_comp_w = add_sub1a[10]? (-add_sub1a) : add_sub1a;
wire [10:0] addsub2a_comp_w = add_sub2a[10]? (-add_sub2a) : add_sub2a;
wire [10:0] addsub3a_comp_w = add_sub3a[10]? (-add_sub3a) : add_sub3a;
wire [10:0] addsub4a_comp_w = add_sub4a[10]? (-add_sub4a) : add_sub4a;
always @ (negedge clk) begin
save_sign1a <= add_sub1a[10];
save_sign2a <= add_sub2a[10];
save_sign3a <= add_sub3a[10];
save_sign4a <= add_sub4a[10];
addsub1a_comp <= addsub1a_comp_w[9:0]; //add_sub1a[10]? (-add_sub1a) : add_sub1a;
addsub2a_comp <= addsub2a_comp_w[9:0]; //add_sub2a[10]? (-add_sub2a) : add_sub2a;
addsub3a_comp <= addsub3a_comp_w[9:0]; //add_sub3a[10]? (-add_sub3a) : add_sub3a;
addsub4a_comp <= addsub4a_comp_w[9:0]; //add_sub4a[10]? (-add_sub4a) : add_sub4a;
end
assign p1a_all = addsub1a_comp * memory1a[15:0];
assign p2a_all = addsub2a_comp * memory2a[15:0];
assign p3a_all = addsub3a_comp * memory3a[15:0];
assign p4a_all = addsub4a_comp * memory4a[15:0];
always @ (negedge clk)
begin
p1a <= (save_sign1a ^ memory1a[16]) ? (-p1a_all[26:9]) :(p1a_all[26:9]);
p2a <= (save_sign2a ^ memory2a[16]) ? (-p2a_all[26:9]) :(p2a_all[26:9]);
p3a <= (save_sign3a ^ memory3a[16]) ? (-p3a_all[26:9]) :(p3a_all[26:9]);
p4a <= (save_sign4a ^ memory4a[16]) ? (-p4a_all[26:9]) :(p4a_all[26:9]);
end
//
/* Final adder. Adding the ouputs of the 4 multipliers */
always @ (negedge clk)
begin
z_out_int1 <= ({p1a[17],p1a} + {p2a[17],p2a});
z_out_int2 <= ({p3a[17],p3a} + {p4a[17],p4a});
z_out_int <= (z_out_int1 + z_out_int2);
end
// rounding of the value
//assign z_out_rnd[15:0] = z_out_int[17:2];
//assign z_out_prelatch[15:0] = z_out_int[17:2]+ z_out_int[1]; // correct rounding
assign z_out_prelatch[15:0] = z_out_int[18:3]+ z_out_int[2]; // correct rounding
//wire TEST_zout= z_out_int[17] ^z_out_int[16];
// outputs from output latches to cross clock edge boundary
always @ (posedge clk)
begin
z_out[15:0] <= z_out_prelatch[15:0];
wr_cntr[6:0] <= wr_cntr_prelatch[6:0];
done <= done_prelatch;
we <= we_prelatch;
page <= page_prelatch;
end
/* 1D-DCT END */
endmodule
module dct_stage2 ( clk,
en,
start, // stage 1 finished, data available in transpose memory
page, // transpose memory page finished, valid at start
rd_cntr, // [6:0] transpose memory read address
tdin, // [15:0] - data from transpose memory
endv, // one cycle ahead of starting (continuing) dv
dv, // data output valid
dct2_out);// [8:0]output data
input clk;
input en,start,page;
// input [9:0] tdin;
input [15:0] tdin; //added 6 bit fractional part
output [6:0] rd_cntr;
// output [11:0] dct2_out;
output [12:0] dct2_out;
output dv;
output endv;
// wire [11:0] dct2_out;
wire [12:0] dct2_out;
/* constants */
parameter C3= 16'd54491;
parameter S3= 16'd36410;
parameter C4= 16'd46341;
parameter C6= 16'd25080;
parameter S6= 16'd60547;
parameter C7= 16'd12785;
parameter S7= 16'd64277;
//reg[7:0] memory1a, memory2a, memory3a, memory4a;
reg[16:0] memory1a, memory2a, memory3a, memory4a;
reg [2:0] indexi;
reg dv;
/* 2D section */
//reg[9:0] xb0_in, xb1_in, xb2_in, xb3_in, xb4_in, xb5_in, xb6_in, xb7_in;
//reg[9:0] xb0_reg, xb1_reg, xb2_reg, xb3_reg, xb4_reg, xb5_reg, xb6_reg, xb7_reg;
//reg[9:0] addsub1b_comp,addsub2b_comp,addsub3b_comp,addsub4b_comp;
//reg[10:0] add_sub1b,add_sub2b,add_sub3b,add_sub4b;
reg[15:0] xb0_in, xb1_in, xb2_in, xb3_in, xb4_in, xb5_in, xb6_in, xb7_in;
reg[15:0] xb0_reg, xb1_reg, xb2_reg, xb3_reg, xb4_reg, xb5_reg, xb6_reg, xb7_reg;
reg[16:0] add_sub1b,add_sub2b,add_sub3b,add_sub4b;
reg[15:0] addsub1b_comp,addsub2b_comp,addsub3b_comp,addsub4b_comp;
reg save_sign1b, save_sign2b, save_sign3b, save_sign4b;
//reg[17:0] p1b,p2b,p3b,p4b;
reg[18:0] p1b,p2b,p3b,p4b;
wire[35:0] p1b_all,p2b_all,p3b_all,p4b_all;
reg toggleB;
reg[19:0] dct2d_int1,dct2d_int2;
reg[20:0] dct_2d_int;
wire[12:0] dct_2d_rnd;
// transpose memory read address
wire [6:0] rd_cntr;
reg [5:0] rd_cntrs;
reg rd_page;
// start with the same as stage1
//wire pre_sxregs;
wire endv;
wire sxregs;
// to conserve energy by disabling toggleB
wire sxregs_d8;
reg enable_toggle;
reg en_started;
wire disdv;
SRL16 i_endv (.Q(endv), .A0(1'b0), .A1(1'b1), .A2(1'b1), .A3(1'b1), .CLK(clk), .D(start)); // dly=14+1
SRL16 i_disdv (.Q(disdv), .A0(1'b0), .A1(1'b1), .A2(1'b1), .A3(1'b1), .CLK(clk), .D(rd_cntr[5:0]==6'h3f)); // dly=14+1
SRL16 i_sxregs (.Q(sxregs), .A0(1'b0), .A1(1'b0), .A2(1'b0), .A3(1'b1), .CLK(clk),.D((rd_cntr[5:3]==3'h0) && en_started)); // dly=8+1
SRL16 i_sxregs_d8 (.Q(sxregs_d8), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b0), .CLK(clk),.D(sxregs && en_started)); // dly=7+1
always @ (posedge clk) enable_toggle <= en && (sxregs || (enable_toggle && !sxregs_d8));
always @ (posedge clk) en_started <= en && (start || en_started);
always @ (posedge clk) dv <= en && (endv || (dv && ~disdv));
// always @ (posedge clk) toggleB <= sxregs || (~toggleB);
always @ (posedge clk) toggleB <= sxregs || (enable_toggle && (~toggleB));
always @ (posedge clk)
if (sxregs) indexi <= 3'h7;
// else indexi<=indexi+1;
else if (enable_toggle) indexi<=indexi+1;
always @ (posedge clk) begin
if (start) rd_page <= page;
if (start) rd_cntrs[5:0] <=6'b0; // will always count, but that does not matter- What about saving energy ;-) ? Saved...
else if (rd_cntrs[5:0]!=6'h3f) rd_cntrs[5:0] <= rd_cntrs[5:0]+1;
// else rd_cntrs[5:0] <= rd_cntrs[5:0]+1;
end
assign rd_cntr[6:0]= {rd_page,rd_cntrs[2:0],rd_cntrs[5:3]};
// duplicate memorya from stage 1
// store 1D-DCT constant coeeficient values for multipliers */
always @ (posedge clk)
begin
case (indexi)
0 : begin memory1a <= {1'b0,C4}; //8'd91
memory2a <= {1'b0,C4}; //8'd91
memory3a <= {1'b0,C4}; //8'd91
memory4a <= {1'b0,C4}; //8'd91
end
1 : begin memory1a <= {1'b0,S7}; //8'd126;
memory2a <= {1'b0,C3}; //8'd106;
memory3a <= {1'b0,S3}; //8'd71;
memory4a <= {1'b0,C7}; //8'd25;
end
2 : begin memory1a <= {1'b0,S6}; //8'd118;
memory2a <= {1'b0,C6}; //8'd49;
memory3a <= {1'b1,C6}; //-8'd49;
memory4a <= {1'b1,S6}; //-8'd118
end
3 : begin memory1a <= {1'b0,C3}; // 8'd106;
memory2a <= {1'b1,C7}; //-8'd25;
memory3a <= {1'b1,S7}; //-8'd126;
memory4a <= {1'b1,S3}; //-8'd71;
end
4 : begin memory1a <= {1'b0,C4}; // 8'd91;
memory2a <= {1'b1,C4}; //-8'd91;
memory3a <= {1'b1,C4}; //-8'd91;
memory4a <= {1'b0,C4}; // 8'd91;
end
5 : begin memory1a <= {1'b0,S3}; // 8'd71;
memory2a <= {1'b1,S7}; //-8'd126;
memory3a <= {1'b0,C7}; // 8'd25;
memory4a <= {1'b0,C3}; // 8'd106;
end
6 : begin memory1a <= {1'b0,C6}; // 8'd49;
memory2a <= {1'b1,S6}; //-8'd118;
memory3a <= {1'b0,S6}; // 8'd118;
memory4a <= {1'b1,C6}; //-8'd49;
end
7 : begin memory1a <= {1'b0,C7}; // 8'd25;
memory2a <= {1'b1,S3}; //-8'd71;
memory3a <= {1'b0,C3}; // 8'd106;
memory4a <= {1'b1,S7}; //-8'd126;
end
endcase
end
always @ (posedge clk)
begin
xb0_in <= tdin; xb1_in <= xb0_in; xb2_in <= xb1_in; xb3_in <= xb2_in;
xb4_in <= xb3_in; xb5_in <= xb4_in; xb6_in <= xb5_in; xb7_in <= xb6_in;
end
/* register inputs, inputs read in every eighth clk*/
always @ (posedge clk)
if (sxregs) begin
xb0_reg <= xb0_in; xb1_reg <= xb1_in;
xb2_reg <= xb2_in; xb3_reg <= xb3_in;
xb4_reg <= xb4_in; xb5_reg <= xb5_in;
xb6_reg <= xb6_in; xb7_reg <= xb7_in;
end
always @ (posedge clk)
if (toggleB == 1'b1) begin
// add_sub1b <= ({xb7_reg[9],xb7_reg[9:0]} + {xb0_reg[9],xb0_reg[9:0]});
// add_sub2b <= ({xb6_reg[9],xb6_reg[9:0]} + {xb1_reg[9],xb1_reg[9:0]});
// add_sub3b <= ({xb5_reg[9],xb5_reg[9:0]} + {xb2_reg[9],xb2_reg[9:0]});
// add_sub4b <= ({xb4_reg[9],xb4_reg[9:0]} + {xb3_reg[9],xb3_reg[9:0]});
add_sub1b <= ({xb7_reg[15],xb7_reg[15:0]} + {xb0_reg[15],xb0_reg[15:0]});
add_sub2b <= ({xb6_reg[15],xb6_reg[15:0]} + {xb1_reg[15],xb1_reg[15:0]});
add_sub3b <= ({xb5_reg[15],xb5_reg[15:0]} + {xb2_reg[15],xb2_reg[15:0]});
add_sub4b <= ({xb4_reg[15],xb4_reg[15:0]} + {xb3_reg[15],xb3_reg[15:0]});
end else begin
// add_sub1b <= ({xb7_reg[9],xb7_reg[9:0]} - {xb0_reg[9],xb0_reg[9:0]});
// add_sub2b <= ({xb6_reg[9],xb6_reg[9:0]} - {xb1_reg[9],xb1_reg[9:0]});
// add_sub3b <= ({xb5_reg[9],xb5_reg[9:0]} - {xb2_reg[9],xb2_reg[9:0]});
// add_sub4b <= ({xb4_reg[9],xb4_reg[9:0]} - {xb3_reg[9],xb3_reg[9:0]});
add_sub1b <= ({xb7_reg[15],xb7_reg[15:0]} - {xb0_reg[15],xb0_reg[15:0]});
add_sub2b <= ({xb6_reg[15],xb6_reg[15:0]} - {xb1_reg[15],xb1_reg[15:0]});
add_sub3b <= ({xb5_reg[15],xb5_reg[15:0]} - {xb2_reg[15],xb2_reg[15:0]});
add_sub4b <= ({xb4_reg[15],xb4_reg[15:0]} - {xb3_reg[15],xb3_reg[15:0]});
end
// Adding these wires to get rid of the MSB that is always 0
wire [16:0] addsub1b_comp_w = add_sub1b[16]? (-add_sub1b) : add_sub1b;
wire [16:0] addsub2b_comp_w = add_sub2b[16]? (-add_sub2b) : add_sub2b;
wire [16:0] addsub3b_comp_w = add_sub3b[16]? (-add_sub3b) : add_sub3b;
wire [16:0] addsub4b_comp_w = add_sub4b[16]? (-add_sub4b) : add_sub4b;
always @ (posedge clk) begin
// save_sign1b <= add_sub1b[10];
// save_sign2b <= add_sub2b[10];
// save_sign3b <= add_sub3b[10];
// save_sign4b <= add_sub4b[10];
// addsub1b_comp <= add_sub1b[10]? (-add_sub1b) : add_sub1b;
// addsub2b_comp <= add_sub2b[10]? (-add_sub2b) : add_sub2b;
// addsub3b_comp <= add_sub3b[10]? (-add_sub3b) : add_sub3b;
// addsub4b_comp <= add_sub4b[10]? (-add_sub4b) : add_sub4b;
save_sign1b <= add_sub1b[16];
save_sign2b <= add_sub2b[16];
save_sign3b <= add_sub3b[16];
save_sign4b <= add_sub4b[16];
addsub1b_comp <= addsub1b_comp_w[15:0]; // add_sub1b[16]? (-add_sub1b) : add_sub1b;
addsub2b_comp <= addsub2b_comp_w[15:0]; // add_sub2b[16]? (-add_sub2b) : add_sub2b;
addsub3b_comp <= addsub3b_comp_w[15:0]; // add_sub3b[16]? (-add_sub3b) : add_sub3b;
addsub4b_comp <= addsub4b_comp_w[15:0]; // add_sub4b[16]? (-add_sub4b) : add_sub4b;
end
// assign p1b_all = addsub1b_comp * memory1a[15:0];
// assign p2b_all = addsub2b_comp * memory2a[15:0];
// assign p3b_all = addsub3b_comp * memory3a[15:0];
// assign p4b_all = addsub4b_comp * memory4a[15:0];
///AF2015:
// assign p1b_all = addsub1b_comp[15:0] * memory1a[15:0];
// assign p2b_all = addsub2b_comp[15:0] * memory2a[15:0];
// assign p3b_all = addsub3b_comp[15:0] * memory3a[15:0];
// assign p4b_all = addsub4b_comp[15:0] * memory4a[15:0];
assign p1b_all = addsub1b_comp * memory1a;
assign p2b_all = addsub2b_comp * memory2a;
assign p3b_all = addsub3b_comp * memory3a;
assign p4b_all = addsub4b_comp * memory4a;
always @ (posedge clk)
begin
/// Next line was simulated differently in Icarus 0.9 (wrong?) than in Icarus 0.8 (right?)
/// Xilinx probably did as 0.8
/// p1b_all[31:14] - 18-bit number, p1b - 19-bit. in 0.9 (-p1b_all[31:14]) was also 18, not expand to 19 bits, 0.8 - did
/// p1b <= (save_sign1b ^ memory1a[16]) ? (-p1b_all[31:14]) :(p1b_all[31:14]);
p1b[18:0] <= (save_sign1b ^ memory1a[16]) ? (-p1b_all[32:14]) :(p1b_all[32:14]);
p2b[18:0] <= (save_sign2b ^ memory2a[16]) ? (-p2b_all[32:14]) :(p2b_all[32:14]);
p3b[18:0] <= (save_sign3b ^ memory3a[16]) ? (-p3b_all[32:14]) :(p3b_all[32:14]);
p4b[18:0] <= (save_sign4b ^ memory4a[16]) ? (-p4b_all[32:14]) :(p4b_all[32:14]);
end
/* multiply the outputs of the add/sub block with the 8 sets of stored coefficients */
/* Final adder. Adding the ouputs of the 4 multipliers */
always @ (posedge clk)
begin
dct2d_int1 <= ({p1b[18],p1b[18:0]} + {p2b[18],p2b[18:0]});
dct2d_int2 <= ({p3b[18],p3b[18:0]} + {p4b[18],p4b[18:0]});
dct_2d_int <= ({dct2d_int1[19],dct2d_int1[19:0]} + {dct2d_int2[19],dct2d_int2[19:0]});
end
assign dct_2d_rnd[12:0] = dct_2d_int[20:8];
assign dct2_out[12:0] = dct_2d_rnd[12:0] + dct_2d_int[7];
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/ 0000775 0000000 0000000 00000000000 12555570767 0020730 5 ustar 00root root 0000000 0000000 x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/camsync.v 0000664 0000000 0000000 00000051416 12555570767 0022563 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** camsync.v
**
** Synchronization between cameras using GPIO lines on th 10353 board:
** - triggering from selected line(s) with filter;
** - programmable delay to actual trigger (in pixel clock periods)
** - Generating trigger output to selected GPIO line (and polarity)
** or directly to the input delay generator (see bove)
** - single/repetitive output with specified period in pixel clocks
**
** Copyright (C) 2007 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
module camsync (sclk, // @negedge
pre_wen, // 1 cycle ahead of write data
// di, // [31:0] data in
di, // [15:0] data in
wa, // [1:0] write address
// 0 - source of trigger (12 bit pairs, LSB - level to trigger, MSB - use this bit). All 0 - internal trigger
// in internal mode output has variable delay from the internal trigger (relative to sensor trigger)
// 1 - input trigger delay (pixel clocks) (NOTE: 0 - trigger disabled - WRONG)
// 2 - 24 bit pairs: MSB - enable selected line, LSB - level to send when trigger active
// bit 25==1 some of the bits use test mode signals:
// 3 - output trigger period (duration constant of 256 pixel clocks).
// d==0 - disable (stop periodic mode)
// d==1 - single trigger
// d==2..255 - set output pulse / input-output serial bit duration (no start generated)
// 256>=d - repetitive trigger
pclk, // pixel clock (global)
triggered_mode, // use triggered mode (0 - sensor is free-running)
trigrst, // single-clock start of frame input (resets trigger output) posedge
gpio_in, // 12-bit input from GPIO pins
gpio_out,// 12-bit output to GPIO pins
gpio_out_en,// 12-bit output enable to GPIO pins
trigger1, // 1 cycle-long trigger output
trigger, // active high trigger to the sensor (reset by vacts)
overdue, // prevents lock-up when no vact was detected during one period and trigger was toggled
ts_snd_en, // enable sending timestamp over sync line
ts_external, // 1 - use external timestamp, if available. 0 - always use local ts
ts_snap, // make a timestamp pulse single @(posedge pclk)
// timestamp should be valid in <16 pclk cycles
ts_snd_sec, // [31:0] timestamp seconds to be sent over the sync line
ts_snd_usec, // [19:0] timestamp microseconds to be sent over the sync line
ts_rcv_sec, // [31:0] timestamp seconds received over the sync line
ts_rcv_usec,// [19:0] timestamp microseconds received over the sync line
ts_stb); // strobe when received timestamp is valid
parameter PRE_MAGIC= 6'b110100;
parameter POST_MAGIC=6'b001101;
input sclk;
input pre_wen;
// input [31:0] di;
input [15:0] di;
input [ 1:0] wa;
input pclk;
input triggered_mode; // use triggered mode (0 - sensor is free-running)
input trigrst; //vacts;
input [11:0] gpio_in;
output [11:0] gpio_out;
output [11:0] gpio_out_en;
output trigger1;
output trigger;
output overdue;
input ts_snd_en; // enable sending timestamp over sync line
input ts_external; // 1 - use external timestamp, if available. 0 - always use local ts
output ts_snap; // make a timestamp pulse (from the internal generator
// timestamp should be valid in <16 pclk cycles
input [31:0] ts_snd_sec; // [31:0] timestamp seconds to be sent over the sync line
input [19:0] ts_snd_usec; // [19:0] timestamp microseconds to be sent over the sync line
output [31:0] ts_rcv_sec; // [31:0] timestamp seconds received over the sync line
output [19:0] ts_rcv_usec;// [19:0] timestamp microseconds received over the sync line
output ts_stb; // strobe when received timestamp is valid
// delaying everything by 1 clock to reduce data fan in
reg [1:0] wad;
reg [31:0] did;
reg pre_wend;
reg [3:0] wen;
reg high_zero; // 24 MSBs are zero
reg [11:0] input_use; // 1 - use this bit
reg [11:0] input_pattern; // data to be compared for trigger event to take place
reg pre_input_use_intern;// @(negedge sclk) Use internal trigger generator, 0 - use external trigger (also switches delay from input to output)
reg input_use_intern;// @(posedge clk)
reg [31:0] input_dly; // delay value for the trigger
reg [11:0] gpio_out_en; // which GPIO lines to drive
reg [11:0] gpio_active; // output levels on the selected GPIO lines during output pulse (will be negated when inactive)
reg testmode; // drive some internal signals to GPIO bits
reg outsync; // during output active
reg out_data; // output data (modulated with timestamp if enabled)
reg [31:0] repeat_period; // restart period in repetitive mode
reg start,start_d; // start single/repetitive output pulse(s)
reg rep_en; // enable repetitive mode
reg start_en;
wire start_to_pclk;
reg [2:0] start_pclk; // start and restart
reg [31:0] restart_cntr; // restart period counter
reg [1:0] restart_cntr_run; // restart counter running
wire restart; // restart out sync
///AF: reg [8:0] out_pulse_cntr;
reg trigger_condition; // GPIO input trigger condition met
reg trigger_condition_d; // GPIO input trigger condition met, delayed (for edge detection)
reg trigger_condition_filtered; // trigger condition filtered
// reg trigger_condition_filtered_d; // trigger condition filtered, delayed (for edge detection)
reg [6:0] trigger_filter_cntr;
reg trigger1;
wire trigger1_dly16; // trigger1 delayed by 16 clk cycles to get local timestamp
// reg trigger;
wire trigger; // for happy simulator
reg overdue;
reg start_dly; // start delay (external input filtered or from internal single/rep)
reg [31:0] dly_cntr; // trigger delay counter
// reg dly_cntr_run; // trigger delay counter running
wire dly_cntr_run; // trigger delay counter running (to use FD for simulation)
reg dly_cntr_run_d; // trigger delay counter running - delayed by 1
wire pre_start_out_pulse;
reg start_out_pulse; /// start generation of output pulse. In internal trigger mode uses delay counter, in external - no delay
///AF: reg pre_start;
reg [31:0] pre_period;
reg [ 7:0] bit_length='hff; /// Output pulse duration or bit duration in timestamp mode
/// input will be filtered with (bit_length>>2) duration
wire [ 7:0] bit_length_plus1; // bit_length+1
reg [ 7:0] bit_length_short; /// 3/4 bit duration, delay for input strobe from the leading edge.
wire pre_start0;
reg start0;
wire pre_set_bit;
reg set_bit;
wire pre_set_period;
reg set_period;
wire start_pclk16 ;// delayed start to wait for time stamp to be available
reg [31:0] sr_snd_first;
reg [31:0] sr_snd_second;
reg [31:0] sr_rcv_first;
reg [31:0] sr_rcv_second;
reg [ 7:0] bit_snd_duration;
reg [ 5:0] bit_snd_counter;
reg [ 7:0] bit_rcv_duration;
reg bit_rcv_duration_zero; // to make it faster, duration always >=2
reg [ 6:0] bit_rcv_counter; // includes "deaf" period ater receving
reg bit_snd_duration_zero; //
// input ts_snd_en; // enable sending timestamp over sync line
reg ts_snd_en_pclk;
reg [31:0] ts_rcv_sec; // timestamp seconds received over the sync line
reg [19:0] ts_rcv_usec; // timestamp microseconds received over the sync line
reg rcv_run_or_deaf; // counters active
wire rcv_run; // receive in progress, will always last for 64 bit_length+1 intervals before ready for the new input pulse
reg rcv_run_d;
reg rcv_done_rq; // request to copy time stamp (if it is not ready yet)
reg rcv_done_rq_d;
reg rcv_done; /// rcv_run ended, copy timestamp if requested
// reg rcv_deaf; // would not accept new trigger until this is over
// reg rcv_run_or_deaf; // counters active
wire pre_rcv_error; // pre/post magic does not match, set ts to all ff-s
reg rcv_error;
reg ts_external_pclk; // 1 - use external timestamp (combines ts_external and input_use_intern)
reg triggered_mode_pclk;
reg ts_snap;
reg ts_stb; // strobe when received timestamp is valid (single sclk cycle)
wire ts_stb_pclk;
reg [2:0] ts_pre_stb;
//! in testmode GPIO[11] and GPIO[10] use internal signals instead of the outsync:
//! bit 11 - same as TRIGGER output to the sensor (signal to the sensor may be disabled externally)
//! then that bit will be still from internall trigger to frame valid
//! bit 10 - dly_cntr_run (delay counter run) - active during trigger delay
assign rcv_run=rcv_run_or_deaf && bit_rcv_counter[6];
assign bit_length_plus1 [ 7:0] =bit_length[7:0]+1;
assign pre_start_out_pulse=input_use_intern?(dly_cntr_run_d && !dly_cntr_run):start_pclk16;
assign gpio_out[9: 0] = out_data? gpio_active[9: 0]: ~gpio_active[9: 0];
assign gpio_out[10] = (testmode? dly_cntr_run: out_data)? gpio_active[10]: ~gpio_active[10];
assign gpio_out[11] = (testmode? trigger: out_data)? gpio_active[11]: ~gpio_active[11];
assign restart= restart_cntr_run[1] && !restart_cntr_run[0];
assign pre_set_bit= (|did[31:8]==0) && |did[7:1]; // 2..255
assign pre_start0= |did[31:0] && !pre_set_bit;
assign pre_set_period = !pre_set_bit;
always @ (negedge sclk) begin
pre_wend <= pre_wen;
if (pre_wen) wad[1:0] <= wa[1:0];
if (pre_wen) did[15: 0] <= di[15:0];
if (pre_wend) did[31:16] <= di[15:0];
wen[3:0] <= pre_wend?{(wad[1:0]==2'h3),(wad[1:0]==2'h2),(wad[1:0]==2'h1),(wad[1:0]==2'h0)}:4'b0;
if (wen[0]) input_use[11:0] <= {did[23],did[21],did[19],did[17],did[15],did[13],did[11],did[9],did[7],did[5],did[3],did[1]};
pre_input_use_intern <= (input_use[11:0]==12'h0); // use internal source for triggering
if (wen[0]) input_pattern[11:0] <= {did[22],did[20],did[18],did[16],did[14],did[12],did[10],did[8],did[6],did[4],did[2],did[0]};
if (wen[1]) input_dly[31:0] <= did[31:0];
if (wen[2]) gpio_out_en[11:0] <= {did[23],did[21],did[19],did[17],did[15],did[13],did[11],did[9],did[7],did[5],did[3],did[1]};
if (wen[2]) gpio_active[11:0] <= {did[22],did[20],did[18],did[16],did[14],did[12],did[10],did[8],did[6],did[4],did[2],did[0]};
if (wen[2]) testmode <= did[24];
// if (wen[3]) repeat_period[31:0] <= did[31:0];
if (wen[3]) pre_period[31:0] <= did[31:0];
if (wen[3]) high_zero <= did[31:8]==24'b0;
// start <= wen[3] && (did[31:0]!=32'h0);
start0 <= wen[3] && pre_start0;
set_bit <= wen[3] && pre_set_bit;
set_period <= wen[3] && pre_set_period;
if (set_period) repeat_period[31:0] <= pre_period[31:0];
if (set_bit) bit_length[7:0] <= pre_period[ 7:0];
start <= start0;
start_d <= start;
start_en <= (repeat_period[31:0]!=0);
if (set_period) rep_en <= !high_zero;
end
MSRL16 i_start_pclk16 (.Q(start_pclk16), .A(4'hf), .CLK(pclk), .D(start_pclk[2]));
MSRL16 i_strigger1_dly16(.Q(trigger1_dly16), .A(4'hf), .CLK(pclk), .D(trigger1));
//! synchronize start from sclk to pclk
//! Generating repetition (period should be exactly N, not N+/-1) and output pulse
FDCE_1 i_start_to_pclk (.C(sclk), .CE(start_d),.CLR(start_pclk[1] || !start_en),.D(1'b1),.Q(start_to_pclk));
always @ (posedge pclk) begin
ts_snap <= (start_pclk[2] && ts_snd_en_pclk) || //strobe by internal generator if output timestamp is enabled
(trigger1 && !ts_external_pclk); // get local timestamp of trigger1 if it is used
ts_snd_en_pclk<=ts_snd_en;
input_use_intern <= pre_input_use_intern;
ts_external_pclk<= ts_external && !input_use_intern;
// start_pclk[1:0] <= {start_pclk[0] || (restart && rep_en), start_to_pclk && !start_pclk[0]};
start_pclk[2:0] <= {(restart && rep_en) || (start_pclk[1] && !restart_cntr_run[1] && !restart_cntr_run[0] && !start_pclk[2]),
start_pclk[0],
start_to_pclk && !start_pclk[0]};
restart_cntr_run[1:0] <= {restart_cntr_run[0],start_en && (start_pclk[2] || (restart_cntr_run[0] && (restart_cntr[31:2] !=0)))};
if (restart_cntr_run[0]) restart_cntr[31:0] <= restart_cntr[31:0] - 1;
else restart_cntr[31:0] <= repeat_period[31:0];
start_out_pulse <= pre_start_out_pulse;
/// Generating output pulse - 64* bit_length if timestamp is disabled or
/// 64 bits with encoded timestamp, including pre/post magic for error detectrion
outsync <= start_en && (start_out_pulse || (outsync && !((bit_snd_duration[7:0]==0) &&(bit_snd_counter[5:0]==0))));
if (!outsync || (bit_snd_duration[7:0]==0)) bit_snd_duration[7:0] <= bit_length[7:0];
else bit_snd_duration[7:0] <= bit_snd_duration[7:0] - 1;
bit_snd_duration_zero <= bit_snd_duration[7:0]==8'h1;
if (!outsync) bit_snd_counter[5:0] <=ts_snd_en_pclk?63:3; /// when no ts serial, send pulse 4 periods long (max 1024 pclk)
/// Same bit length (1/4) is used in input filter/de-glitcher
else if (bit_snd_duration[7:0]==0) bit_snd_counter[5:0] <= bit_snd_counter[5:0] -1;
if (!outsync) sr_snd_first[31:0] <= {PRE_MAGIC,ts_snd_sec[31:6]};
// else if (bit_snd_duration[7:0]==0) sr_snd_first[31:0] <={sr_snd_first[30:0],sr_snd_second[31]};
else if (bit_snd_duration_zero) sr_snd_first[31:0] <={sr_snd_first[30:0],sr_snd_second[31]};
if (!outsync) sr_snd_second[31:0] <= {ts_snd_sec[5:0], ts_snd_usec[19:0],POST_MAGIC};
// else if (bit_snd_duration[7:0]==0) sr_snd_second[31:0] <={sr_snd_second[30:0],1'b0};
else if (bit_snd_duration_zero) sr_snd_second[31:0] <={sr_snd_second[30:0],1'b0};
out_data <=outsync && (ts_snd_en_pclk?sr_snd_first[31]:1'b1);
end
// Detecting input sync pulse (filter - 64 pclk, pulse is 256 pclk)
// FD i_dly_cntr_run (.C(pclk),.D(start_dly || (dly_cntr_run && (dly_cntr[31:0]!=0))),.Q(dly_cntr_run)); // for simulator to be happy
// even more for simulator
FD i_dly_cntr_run (.C(pclk),.D(triggered_mode && (start_dly || (dly_cntr_run && (dly_cntr[31:0]!=0)))),.Q(dly_cntr_run)); // for simulator to be happy
// FD i_trigger (.C(pclk),.D(trigger1 || (trigger && !trigrst)), .Q(trigger)); // for simulator to be happy
/// Now trigger1 toggles trigger output to prevent lock-up if no vacts
/// Lock-up could take place if:
/// 1 - Sesnoris in snapshot mode
/// 2 - trigger was applied before end of previous frame.
/// With implemented toggling 1 extra pulse can be missed (2 with the original missed one), but the system will not lock-up
/// if the trigger pulses continue to come.
assign pre_rcv_error= (sr_rcv_first[31:26]!=PRE_MAGIC) || (sr_rcv_second[5:0]!=POST_MAGIC);
FD i_trigger (.C(pclk),.D(trigrst?1'b0:(trigger1 ^ trigger)), .Q(trigger)); // for simulator to be happy
always @ (posedge pclk) begin
if (trigrst) overdue <= 1'b0;
else if (trigger1) overdue <= trigger;
triggered_mode_pclk<= triggered_mode;
bit_length_short[7:0] <= bit_length[7:0]-bit_length_plus1[7:2]-1; // 3/4 of the duration
trigger_condition <= (((gpio_in[11:0] ^ input_pattern[11:0]) & input_use[11:0]) == 12'b0);
trigger_condition_d <= trigger_condition;
if (!triggered_mode || (trigger_condition !=trigger_condition_d)) trigger_filter_cntr <= {1'b0,bit_length[7:2]};
else if (!trigger_filter_cntr[6]) trigger_filter_cntr<=trigger_filter_cntr-1;
if (input_use_intern) trigger_condition_filtered <= 1'b0;
else if (trigger_filter_cntr[6]) trigger_condition_filtered <= trigger_condition_d;
rcv_run_or_deaf <= start_en && (trigger_condition_filtered ||
// (rcv_run_or_deaf && !((bit_rcv_duration[7:0]==0) &&(bit_rcv_counter[6:0]==0))));
(rcv_run_or_deaf && !(bit_rcv_duration_zero && (bit_rcv_counter[6:0]==0))));
rcv_run_d <= rcv_run;
start_dly <= input_use_intern ? (start_pclk16 && start_en) : (rcv_run && !rcv_run_d);
// simulation problems w/o "start_en &&" ?
dly_cntr_run_d <= dly_cntr_run;
if (dly_cntr_run) dly_cntr[31:0] <= dly_cntr[31:0] -1;
else dly_cntr[31:0] <= input_dly[31:0];
trigger1 <= input_use_intern ? (start_pclk16 && start_en):(dly_cntr_run_d && !dly_cntr_run);/// bypass delay to trigger1 in internal trigger mode
/// 64-bit serial receiver (52 bit payload, 6 pre magic and 6 bits post magic for error checking
if (!rcv_run_or_deaf) bit_rcv_duration[7:0] <= bit_length_short[7:0]; // 3/4 bit length-1
else if (bit_rcv_duration[7:0]==0) bit_rcv_duration[7:0] <= bit_length[7:0]; // bit length-1
else bit_rcv_duration[7:0] <= bit_rcv_duration[7:0]-1;
bit_rcv_duration_zero <= bit_rcv_duration[7:0]==8'h1;
if (!rcv_run_or_deaf) bit_rcv_counter[6:0] <= 127;
// else if (bit_rcv_duration[7:0]==0) bit_rcv_counter[6:0] <= bit_rcv_counter[6:0] -1;
else if (bit_rcv_duration_zero) bit_rcv_counter[6:0] <= bit_rcv_counter[6:0] -1;
// if (rcv_run && (bit_rcv_duration[7:0]==0)) begin
if (rcv_run && bit_rcv_duration_zero) begin
sr_rcv_first[31:0] <={sr_rcv_first[30:0],sr_rcv_second[31]};
sr_rcv_second[31:0] <={sr_rcv_second[30:0],trigger_condition_filtered};
end
rcv_done_rq <= start_en && ((ts_external_pclk && trigger1_dly16) || (rcv_done_rq && rcv_run));
rcv_done_rq_d <= rcv_done_rq;
rcv_done <= rcv_done_rq_d && !rcv_done_rq;
// triggered_mode_pclk<= triggered_mode;
rcv_error <= pre_rcv_error;
if (rcv_done) begin
ts_rcv_sec [31:0] <= {sr_rcv_first[25:0],sr_rcv_second[31:26]};
ts_rcv_usec [19:0] <= rcv_error?20'hfffff: sr_rcv_second[25:6];
end else if (!triggered_mode_pclk || (!ts_external_pclk && trigger1_dly16 )) begin
ts_rcv_sec [31:0] <= ts_snd_sec [31:0];
ts_rcv_usec [19:0] <= ts_snd_usec[19:0];
end
// ts_stb<= rcv_done || (!ts_external_pclk && trigger1_dly16 ); // strobe when received timestamp is valid
end
FDCE i_ts_stb_pclk (.C(pclk), .CE(rcv_done || (!ts_external_pclk && trigger1_dly16 )),.CLR(ts_stb),.D(1'b1),.Q(ts_stb_pclk));
always @ (negedge sclk) begin
ts_pre_stb[2:0] <= {ts_pre_stb[1:0],ts_stb_pclk};
ts_stb <= ts_pre_stb[1] && !ts_pre_stb[2];
end
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/clkios353.v 0000664 0000000 0000000 00000013522 12555570767 0022641 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** clkios353.v
**
** I/O pads related circuitry
**
** Copyright (C) 2002-2006 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
// Some placement constraints are in this file
module dcm333#(
parameter IOSTANDARD_SDRAM_DIFF = "DIFF_SSTL2_I",
parameter SLEW_SDRAM_DIFF = "SLOW"
)(
sclk, // input global clock, 120MHz, phase=0
SDCLK, // positive clock to SDRAM
SDNCLK, // negative clock to SDRAM
sdcl_fb,
xclk, // 60MHz for compressor
phsel, // additional phase control for SDRAM CLK
dcm_rst, // reset DCM phase
dcm_incdec, // variable phase control to adjust SDCLK so read DQS is aligned with sclk90/sclk270
dcm_en,
dcm_clk,
dcm_done,
locked, // dcm locked
status // dcm status (bit 1 - dcm clkin stopped)
);
input sclk;
output xclk;
output SDCLK, SDNCLK;
input [1:0] phsel;
input sdcl_fb; // SuppressThisWarning Veditor UNUSED - was designed to use external pin sync (maybe still use it?)
input dcm_rst, dcm_incdec, dcm_en, dcm_clk;
output dcm_done;
output [7:0] status; // dcm status (bit 1 - dcm clkin stopped)
output locked; // dcm locked
wire isdclk0, isdclk90, isdclk180, isdclk270;
wire ixclk;
// wire gsdclk; //used only for the feedback
wire isdclk;
reg dcm_done;
wire dcm_done_dcm; // single-cycle
assign isdclk=phsel[1]? (phsel[0]?isdclk270:isdclk180):(phsel[0]?isdclk90:isdclk0);
FD i_ixclk (.C(sclk), .D(!ixclk), .Q(ixclk));
BUFG i_xclk (.I(ixclk), .O(xclk));
// second - adjustable DCM. Will be adjusted so read DQS (dependent on SDCLK) will be aligned with sclk90/270
// maybe will need some delay as there is DLL in SDRAM and responce may be slow.
DCM #(
.CLKIN_DIVIDE_BY_2 ("FALSE"),
.CLKIN_PERIOD (8.33333),
.CLK_FEEDBACK ("1X"),
.DESKEW_ADJUST ("SYSTEM_SYNCHRONOUS"),
.DLL_FREQUENCY_MODE ("LOW"),
.DUTY_CYCLE_CORRECTION ("TRUE"),
.PHASE_SHIFT (0),
.CLKOUT_PHASE_SHIFT ("VARIABLE")
) i_dcm2(
.CLKIN (sclk),
.CLKFB (isdclk90),
.RST (dcm_rst),
.PSEN (dcm_en),
.PSINCDEC (dcm_incdec),
.PSCLK (dcm_clk),.DSSEN (1'b0),
// .CLK0 (isdclk0),
// .CLK90 (isdclk90),
// .CLK180 (isdclk180),
// .CLK270 (isdclk270),
.CLK0 (isdclk90),
.CLK90 (isdclk180),
.CLK180 (isdclk270),
.CLK270 (isdclk0),
.CLKDV (),
.CLK2X (),
.CLK2X180 (),
.CLKFX (),
.CLKFX180 (),
.STATUS (status[7:0]),
.LOCKED (locked),
.PSDONE (dcm_done_dcm));
// BUFG i_gsdclk (.I(isdclk90), .O(gsdclk));
OBUFDS #(
.IOSTANDARD(IOSTANDARD_SDRAM_DIFF),
.SLEW(SLEW_SDRAM_DIFF))
i_SDCLK (.O(SDCLK),.OB(SDNCLK),.I(isdclk));
// OBUFDS i_SDCLK (.O(SDNCLK),.OB(SDCLK),.I(!isdclk));
// make dcm_done behave as dcm_ready
always @ (posedge dcm_clk or posedge dcm_rst)
if (dcm_rst) dcm_done <= 1'b1;
else if (dcm_en) dcm_done <=1'b0;
else if (dcm_done_dcm) dcm_done <=1'b1;
endmodule
module clockios353#(
parameter IOSTANDARD = "LVCMOS33"
)(
CLK0, // input clock pad - 120MHz
sclk0, // global clock, 120MHz, phase=0 (addresses, commands should be strobed at neg edge)
/*sclk90,*/ // global clock, 120MHz, phase=90 (strobe data write to sdram)
sclk180, // global clock, 120MHz, phase=180 (just to generate DQS :-( )
sclk270, // global clock, 120MHz, phase=270 (strobe data write to sdram)
iclk0, //before BUFG
dcmrst, //reset dcm
locked, // dcm locked
status // dcm status (bit 1 - dcm clkin stopped)
);
input CLK0;
output sclk0,/*sclk90,*/sclk270,sclk180;
output iclk0;
input dcmrst; //reset dcm
output [7:0] status; // dcm status (bit 1 - dcm clkin stopped)
output locked; // dcm locked
wire iclk0;
wire isclk0, /*isclk90,*/ isclk270, isclk180;
IBUFG #(.IOSTANDARD(IOSTANDARD)) i_iclk0 (.I(CLK0), .O(iclk0));
// DCM - just 4 phases out
DCM #(
.CLKIN_DIVIDE_BY_2("FALSE"),
.CLKIN_PERIOD(8.33333),
.CLK_FEEDBACK("1X"),
.DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"),
.DLL_FREQUENCY_MODE("LOW"),
.DUTY_CYCLE_CORRECTION("TRUE")
) i_dcm1(
.CLKIN (iclk0),
.CLKFB (sclk0),
.RST (dcmrst), .PSEN (1'b0),.PSINCDEC (1'b0), .PSCLK (1'b0),.DSSEN (1'b0),
.CLK0 (isclk0),
.CLK90 (/*isclk90*/),
.CLK180 (isclk180),
.CLK270 (isclk270),
.CLKDV (),
.CLK2X (),
.CLK2X180 (),
.CLKFX (),
.CLKFX180 (),
.STATUS (status[7:0]),
.LOCKED (locked),
.PSDONE ());
BUFG i_sclk0 (.I(isclk0),. O(sclk0));
// s-ynthesis attribute loc of i_sclk0 is "BUFGMUX0"
/* BUFG i_sclk90 (.I(isclk90), .O(sclk90)); */
// s-ynthesis attribute loc of i_sclk90 is "BUFGMUX1"
BUFG i_sclk180(.I(isclk180),.O(sclk180));
// s-ynthesis attribute loc of i_sclk180 is "BUFGMUX2"
BUFG i_sclk270(.I(isclk270),.O(sclk270));
// s-ynthesis attribute loc of i_sclk270 is "BUFGMUX3"
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/cmd_sequencer.v 0000664 0000000 0000000 00000026575 12555570767 0023753 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** cmd_sequencer.v
**
** command sequencer with FIFO
**
** Copyright (C) 2008 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
// This command sequencer is designed (together with i2c sequencer) to provide
// pipelined operation of the sensor, FPGA pre-processor and compressor, to avoid
// requirement of resetting the circuitry and loosing several frames when the sensor
// acquisition parameters are changed (especially geometry - WOI, decimation).
// It also reduces real-time requirements to the software, as it is possible to
// program parameters related to the events several frames in the future.
//
// Commands related to the particular frames go to one of the 8 FIFO buffers (64 commands deep each),
// each command is 32 bits wide, with 8MSBs being register address, and the remaining 24 bits - data
// to be written.
// That limits data that can be written to the FPGA registers compared to the direct register writes
// (8MSBs are always zero), but all the relevant information can be written with just 24 data bits.
//
//
// Controller is programmed through 16 locations (currently mapped to 0x60..0x6f):
// 0x0..0x7 write directly to the frame number [2:0] modulo 8, except if you write to the frame
// "just missed" - in that case data will go to the current frame.
// 0x8 - write seq commands to be sent ASAP
// 0x9 - write seq commands to be sent after the next frame starts
//
// 0xe - write seq commands to be sent after the next 6 frames start
// 0xf - control register:
// [14] - reset all FIFO (takes 16 clock pulses), also - stops seq until run command
// [13:12] - 3 - run seq, 2 - stop seq , 1,0 - no change to run state
module cmd_sequencer (sclk, // @negedge
wen, // sync to address and d[0:15]
wa, // [3:0] 0..7 - absolute data, 8..0x0e relative data, 0x0f - command
di, // [15:0] data in
sync, // frame sync (used to synchronize data), vacts_sclk @negedge sclk
// condition,// condition to wait
seq_rq, // request from the sequencer
seq_ack, // sequencer acknowledge
seq_a, // address from the sequencer
seq_d, // data from the sequencer
frame_no);// [2:0] current frame modulo 8
input sclk;
input wen;
input [ 3:0] wa;
input [15:0] di;
input sync;
// output [ 7:0] condition;
output seq_rq; // request from the sequencer
input seq_ack; // sequencer acknowledge
output [ 7:0] seq_a; // address from the sequencer
output [23:0] seq_d; // data from the sequencer
output [2:0] frame_no;
// reg [4:0] wen_d; // [0] - not just fifo, but any PIO writes, [1] and next - filtered for FIFO only
reg [3:0] wen_d; // [0] - not just fifo, but any PIO writes, [1] and next - filtered for FIFO only
reg [3:0] wad;
reg [15:0] di_1;
reg [15:0] di_2;
reg [15:0] di_3;
reg [2:0] wpage0; // FIFO page were ASAP writes go
reg [2:0] wpage7; // unused page, currently being cleared
reg [2:0] page_r; // FIFO page were current write goes (reading)
reg [2:0] wpage_w; // FIFO page were current write goes (reading)
reg wpage0_inc; // increment wpage0 (after frame syn or during reset
reg wpage0_inc_d; // next cycle after wpage0_inc
reg reset_cmd;
reg run_cmd;
reg reset_on; // reset FIFO in progress
wire seq_enrun; // enable seq
reg we_fifo_wp; // enable writing to fifo write pointer memory
reg req_clr; // request for clearing fifo_wp
wire is_ctl= (wad[3:0]==4'hf);
// wire is_rel= ((wad[3]==1) && (wad[2:0]!=3'h7));
wire is_abs= (wad[3]==0);
wire pre_wpage0_inc;
wire [2:0] frame_no=wpage0[2:0];
//fifo write pointers (dual port distributed RAM)
reg [5:0] fifo_wr_pointers [0:7];
wire [5:0] fifo_wr_pointers_outw=fifo_wr_pointers[wpage_w[2:0]];
wire [5:0] fifo_wr_pointers_outr=fifo_wr_pointers[page_r[2:0]];
reg [5:0] fifo_wr_pointers_outw_r;
reg [5:0] fifo_wr_pointers_outr_r;
// command seq fifo (RAMB16_S9_S18)
reg [9:0] seq_cmd_wa; // wite address for the current pair of 16-bit data words
// {page[2:0],word[5:0],MSW[0]}
reg seq_cmd_we; // write enable to blockRAM
reg [1:0] page_r_inc; // increment page_r[2:0]; - signal and delayed version
reg [5:0] rpointer; // FIFO read pointer for current page
// wire word_number; // BlockRAM output word (0 - low, 1 - high)
reg seq_rq; // request from the sequencer
reg [15:0] seq_dh; // address from the sequencer
wire [15:0] seq_dl; // sequencer data as read from BlockRAM
reg seq_re; // read enable from BlockRAM
reg seq_re_last; // second clock of seq_re
wire [1:0] por; //power on reset
wire initialized; // command fifo initialized
assign seq_a[ 7:0]= seq_dh[15:8];
assign seq_d[23:0]= {seq_dh[7:0],seq_dl[15:0]};
assign pre_wpage0_inc = (!wen_d[0] && !wen_d[1] && !wpage0_inc) && ((req_clr && initialized)|| reset_on) ;
// input seq_ack; // sequencer acknowledge
// setting control parameters
// if (reset_cmd || (run_cmd && !di_2[12])) seq_enrun <= 1'b0;
// else if (run_cmd && di_2[12]) seq_enrun <= 1'b1;
FD_1 i_seq_enrun (.Q(seq_enrun), .C(sclk),.D( !(reset_cmd || (run_cmd && !di_2[12])) &&
((run_cmd && di_2[12]) || seq_enrun )));
FD_1 i_por0 (.Q(por[0]), .C(sclk),.D( 1'b1));
FD_1 i_por1 (.Q(por[1]), .C(sclk),.D(por[0]));
FD_1 i_initialized ( .Q(initialized), .C(sclk), .D(por[1] && ( initialized || (reset_on && !(wpage0_inc && ( wpage0[2:0]==3'h7))))) );
always @ (negedge sclk) begin
// signals related to writing to seq FIFO
// delayed versions of address, data write strobe
if (wen) wad [ 3:0] <= wa[ 3:0];
if (wen || wen_d[0]) di_1[15:0] <= di[15:0];
di_2[15:0] <= di_1[15:0];
di_3[15:0] <= di_2[15:0];
// wen_d[4:0] <= {wen_d[3:1],wen_d[0] && !is_ctl,wen};
wen_d[3:0] <= {wen_d[2:1],wen_d[0] && !is_ctl, !reset_on && wen};
// decoded commands
reset_cmd <= (!reset_on & wen_d[0] && is_ctl && di_1[14]) || (por[0] && !por[1]);
run_cmd <= wen_d[0] && is_ctl && di_1[13];
// write pointer memory
wpage0_inc <= pre_wpage0_inc && &por[1:0];
wpage0_inc_d <= wpage0_inc && &por[1:0];
if (reset_cmd || !por[1]) wpage0[2:0]<=3'h0;
else if (wpage0_inc) wpage0[2:0]<=wpage0[2:0]+1;
if (reset_cmd || !por[1]) wpage7[2:0]<=3'h7;
else if (wpage0_inc) wpage7[2:0]<=wpage0[2:0];
reset_on <= por[1] && (reset_cmd || (reset_on && !(wpage0_inc && ( wpage0[2:0]==3'h7))));
req_clr <= sync || (req_clr && !wpage0_inc);
if (wen_d[0]) wpage_w[2:0] <= is_abs?((wad[2:0]==wpage7[2:0])? wpage0[2:0] : wad[2:0]):(wpage0[2:0]+wad[2:0]);
else if (wpage0_inc) wpage_w[2:0] <= wpage7[2:0];
we_fifo_wp <= wen_d[1] || wpage0_inc;
if (wen_d[1]) fifo_wr_pointers_outw_r[5:0] <= fifo_wr_pointers_outw[5:0];
if (we_fifo_wp) fifo_wr_pointers[wpage_w[2:0]] <= wpage0_inc_d? 6'h0:(fifo_wr_pointers_outw_r[5:0]+1);
fifo_wr_pointers_outr_r[5:0] <= fifo_wr_pointers_outr[5:0]; // just register distri
// command seq fifo (RAMB16_S9_S18)
if (wen_d[1]) seq_cmd_wa[9:1] <= {wpage_w[2:0],fifo_wr_pointers_outw[5:0]};
seq_cmd_wa[0] <= !wen_d[1]; // 0 for the first in a pair, 1 - for the second
seq_cmd_we <= !reset_cmd && (wen_d[1] || (seq_cmd_we && !wen_d[3])); //reset_cmd added to keep simulator happy
// signals related to reading from seq FIFO
seq_re_last<=seq_re && !seq_re_last;
if (seq_re_last) seq_dh[15:0]<=seq_dl[15:0];
if (reset_cmd || page_r_inc[0]) rpointer[5:0] <= 6'h0;
else if (seq_re_last) rpointer[5:0] <= rpointer[5:0] + 1;
seq_re <= seq_enrun &&
!seq_re_last &&
!reset_on &&
!page_r_inc[1] &&
!page_r_inc[0] &&
(((rpointer[5:0]!= fifo_wr_pointers_outr_r[5:0]) &&
!(seq_rq && !seq_ack)) ||
seq_re);
seq_rq <= seq_enrun && (seq_re_last || (seq_rq && !seq_ack));
page_r_inc[1:0] <= {page_r_inc[0] && !(seq_re && !seq_re_last),
!(page_r_inc[0] && !(seq_re && !seq_re_last)) &&
(rpointer[5:0] == fifo_wr_pointers_outr_r[5:0]) &&
(page_r[2:0]!=wpage0[2:0])};
if (reset_on) page_r[2:0]<=3'h0;
else if (page_r_inc[0] && !(seq_re && !seq_re_last)) page_r[2:0]<=page_r[2:0]+1;
end
RAMB16_S18_S18 i_fifo (
.DOA(seq_dl[15:0]), // Port A 16-bit Data Output
.DOPA(), // Port A 2-bit Parity Output
.ADDRA({page_r[2:0],
rpointer[5:0],
~seq_re_last}), // Port A 10-bit Address Input
.CLKA(!sclk), // Port A Clock
.DIA(16'h0), // Port A 16-bit Data Input
.DIPA(2'b0), // Port A 2-bit parity Input
.ENA(seq_re), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(1'b0), // Port A Write Enable Input
.DOB(), // Port B 16-bit Data Output
.DOPB(), // Port B 2-bit Parity Output
.ADDRB(seq_cmd_wa[9:0]), // Port B 10-bit Address Input
.CLKB(!sclk), // Port B Clock
.DIB(di_3[15:0]), // Port B 16-bit Data Input
.DIPB(2'b0), // Port-B 2-bit parity Input
.ENB(seq_cmd_we), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(1'b1) // Port B Write Enable Input
);
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/control_regs.v 0000664 0000000 0000000 00000015016 12555570767 0023622 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** control_regs.v
**
** various control bits (what was a single control register before)
**
** Copyright (C) 2008 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
module control_regs (sclk, // @negedge
wen, // sync to address and d[0:15]
wa, // [1:0] register select
di, // [15:0] data in
/// outputs
bayer_phase, //[1:0]
hact_regen,
reset_mcontr,
break_frames, /// Enable ending frame if no more data is available
zoran,
use_sensor_clk,
xt_pol,
arst,
aro,
encnvclk,
sensor_trigger,
mrst,
external_timestamp, // use external timestamp if available
output_timestamp, // output timestamp, not just pulse
dclkmode,
pxd14,
latehact, //[1:0]=dcr[22:21];// register hact, vact N/4 Tpclk later than data (needed for MT9P001 @ 96MHz)
pclksrc, //[1:0]=dcr[25:24]; // pclk source
hfc_sel, //[2:0]=dcr[30:28];
blockvsync, // block vsync from sensor to sequencers
compressed_frames // 8-bit selection of which frames (modulo 8) to compress. deafaults to 'hff
); // [2:0] current frame modulo 8
input sclk;
input wen;
input [ 1:0] wa;
input [15:0] di;
output [ 1:0] bayer_phase; //[1:0]
output hact_regen;
output reset_mcontr;
output break_frames; /// Enable ending frame if no more data is available
output zoran;
output use_sensor_clk;
output xt_pol;
output arst;
output aro;
output encnvclk;
output sensor_trigger;
output mrst;
output external_timestamp;
output output_timestamp;
output [7:0] compressed_frames;
output dclkmode;
output pxd14;
output [1:0] latehact; //[1:0]=dcr[22:21];// register hact, vact N/4 Tpclk later than data (needed for MT9P001 @ 96MHz)
output [1:0] pclksrc; //[1:0]=dcr[25:24]; // pclk source
output [2:0] hfc_sel; //[2:0]=dcr[30:28];
output blockvsync; // block vsync from sensor to sequencers
reg [1:0] wend; // we delayed
reg [1:0] wad; // address delayed
reg [2:0] reg_wr; // write data to registers (group 0, group1)
reg [15:0] d1;
reg [31:0] d2;
reg [7:0] compressed_frames=8'hff; // TODO change other FDE_1 to registers
always @ (negedge sclk) begin
wend[1:0] <= {wend[0], wen};
if (wen) wad[1:0] <= wa[1:0];
reg_wr[2:0] <= {wend[1] & (wad[1:0]==2'h1), wend[1] & (wad[1:0]==2'h3), wend[1] & (wad[1:0]==2'h2)};
if (wen || wend[0]) d1[15:0] <= di[15:0];
if (wend[0]) d2[15: 0] <= d1[15:0];
if (wend[1]) d2[31:16] <= d1[15:0];
end
FDE_1 i_bayer_phase_0 (.C(sclk),.CE(reg_wr[0] & d2[ 2]),.D(d2[ 0]), .Q(bayer_phase[0]));
FDE_1 i_bayer_phase_1 (.C(sclk),.CE(reg_wr[0] & d2[ 2]),.D(d2[ 1]), .Q(bayer_phase[1]));
FDE_1 i_hact_regen (.C(sclk),.CE(reg_wr[0] & d2[ 4]),.D(d2[ 3]), .Q(hact_regen));
FDE_1 i_reset_mcontr (.C(sclk),.CE(reg_wr[0] & d2[ 6]),.D(d2[ 5]), .Q(reset_mcontr));
FDE_1 i_zoran (.C(sclk),.CE(reg_wr[0] & d2[ 8]),.D(d2[ 7]), .Q(zoran));
FDE_1 i_use_sensor_clk (.C(sclk),.CE(reg_wr[0] & d2[10]),.D(d2[ 9]), .Q(use_sensor_clk));
FDE_1 i_xt_pol (.C(sclk),.CE(reg_wr[0] & d2[12]),.D(d2[11]), .Q(xt_pol));
FDE_1 i_arst (.C(sclk),.CE(reg_wr[0] & d2[14]),.D(d2[13]), .Q(arst));
FDE_1 i_aro (.C(sclk),.CE(reg_wr[0] & d2[16]),.D(d2[15]), .Q(aro));
FDE_1 i_encnvclk (.C(sclk),.CE(reg_wr[0] & d2[18]),.D(d2[17]), .Q(encnvclk));
FDE_1 i_sensor_trigger (.C(sclk),.CE(reg_wr[0] & d2[20]),.D(d2[19]), .Q(sensor_trigger));
FDE_1 i_break_frames (.C(sclk),.CE(reg_wr[0] & d2[22]),.D(d2[21]), .Q(break_frames));
FDE_1 i_mrst (.C(sclk),.CE(reg_wr[1] & d2[ 1]),.D(d2[ 0]), .Q(mrst));
FDE_1 i_external_timestamp(.C(sclk),.CE(reg_wr[1] & d2[ 3]),.D(d2[ 2]), .Q(external_timestamp));
FDE_1 i_dclkmode (.C(sclk),.CE(reg_wr[1] & d2[ 5]),.D(d2[ 4]), .Q(dclkmode));
FDE_1 i_pxd14 (.C(sclk),.CE(reg_wr[1] & d2[ 7]),.D(d2[ 6]), .Q(pxd14));
FDE_1 i_latehact_0 (.C(sclk),.CE(reg_wr[1] & d2[10]),.D(d2[ 8]), .Q(latehact[0]));
FDE_1 i_latehact_1 (.C(sclk),.CE(reg_wr[1] & d2[10]),.D(d2[ 9]), .Q(latehact[1]));
FDE_1 i_pclksrc_0 (.C(sclk),.CE(reg_wr[1] & d2[13]),.D(d2[11]), .Q(pclksrc[0]));
FDE_1 i_pclksrc_1 (.C(sclk),.CE(reg_wr[1] & d2[13]),.D(d2[12]), .Q(pclksrc[1]));
FDE_1 i_hfc_sel_0 (.C(sclk),.CE(reg_wr[1] & d2[17]),.D(d2[14]), .Q(hfc_sel[0]));
FDE_1 i_hfc_sel_1 (.C(sclk),.CE(reg_wr[1] & d2[17]),.D(d2[15]), .Q(hfc_sel[1]));
FDE_1 i_hfc_sel_2 (.C(sclk),.CE(reg_wr[1] & d2[17]),.D(d2[16]), .Q(hfc_sel[2]));
FDE_1 i_blockvsync (.C(sclk),.CE(reg_wr[1] & d2[19]),.D(d2[18]), .Q(blockvsync));
FDE_1 i_output_timestamp (.C(sclk),.CE(reg_wr[1] & d2[21]),.D(d2[20]), .Q(output_timestamp));
always @ (negedge sclk) begin
if (reg_wr[2] & d2[8]) compressed_frames[7:0] <= d2[7:0];
end
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/dma_fifo353.v 0000664 0000000 0000000 00000016021 12555570767 0023116 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** dma_fifosync353.v
**
** DMA controller/fifo
**
** Copyright (C) 2002-2007 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
// with long 8-cycle bursts it makes sense to move everything to internal clock domain (no need fro Gray counters)
// uses GCLK buffer (so 2 for 2 DMA channels)
module dma_fifo_sync ( clk, // system clock, 120MHz? (currentle negedge used)
pre_wen, // decoded addresses (valid @ negedge clk)
wd, // {enable update, pio_mode, enable channel}
dreq, // DREQ output to CPU
dack, // DACK input from CPU
// re, // read enable (CE | OE)
oe, // just OE
pioinc, // increment buffer address in PIO mode
d, // [31:0] - data to cpu
we, // write enable (sync to posedge clk)
di, // 16-bit data to write (sync to posedge clk)
enabled, // channel enabled
real_empty
,test1,
test2
); // pessimistic, with several clk delay
input clk;
input pre_wen;
input [2:0] wd; // bit2 - enable update of bits [1:0], bit 0 - enable channel, bit 1 - PIO mode
output dreq;
input dack;
// input re;
input oe;
input pioinc;
output [31:0] d;
input we;
input [15:0] di;
output enabled;
output real_empty;
output [7:0] test1;
output [7:0] test2;
reg wen;
wire en;
reg [9:0] wab; // binary write counter
reg [8:0] rab; // binary read counter
wire rst;
reg [3:0] empties;
wire en0;
wire pio, pio0; //enable pio read mode
reg [2:0] di_d;
assign rst=!en;
assign enabled=en;
assign real_empty=empties[3];
assign test1=rab[7:0];
assign test2=wab[7:0];
wire swclk; // global clock, switched between OE (when DACK active) and extra pulse generated to read first word from FIFO.
reg firstclk; // generated 1-clk_long pulse as a source for swclk
reg written_burst; // 16 of 16-bit words are just written to FIFO
wire mem_re; // memory RE signal (alo increments counters)
reg dreq;
reg [1:0] burst_start_sync; // 1 clk long pulse (clk-sync) after start of the DMA burst
reg [1:0] dack_r; // synchronize to clk, dual to prevent metastability
reg [9:0] infifo; // number of words in FIFO (10 bits, to implement overflow)
reg first_four; // sync to OE
reg [2:0] first_four_r; // sync to clk
reg nempty; // registered fifo_not_empty
reg lessthan2; // registered fifo has less than 2 words
assign mem_re= dreq || !dack_r[1] || (rab[2:0]!=3'b0);
always @ (negedge clk) begin
wen <= pre_wen;
di_d[2:0] <= wd[2:0];
end
FDE_1 i_en0 (.C(clk), .D(di_d[0]), .CE(wen & di_d[2]), .Q(en0));
FD i_en_tig_ (.C(clk), .D(en0), .Q(en));
FDE_1 i_pio0 (.C(clk), .D(di_d[1]), .CE(wen & di_d[2]), .Q(pio0));
FD i_pio_tig_ (.C(clk), .D(pio0), .Q(pio));
BUFG i_swclk (.O(swclk),.I(dack?oe:(!firstclk && !(pio && pioinc))));
always @ (posedge clk) begin
if (rst) wab[9:0] <= 10'b0;
else if ( we) wab[9:0] <= wab[9:0] + 1;
written_burst <= we && (wab[3:0]==4'hf);
nempty <= (infifo[9:0]!=10'h0);
lessthan2 <= (infifo[9:1]== 9'h0);
if (!en) infifo[9:0] <= 10'h0;
else if ( written_burst && !burst_start_sync[0]) infifo[9:0] <= infifo[9:0]+1;
else if (!written_burst && burst_start_sync[0]) infifo[9:0] <= infifo[9:0]-1;
dack_r[1:0] <= {dack_r[0], dack};
if (rst || firstclk) firstclk <= 1'b0;
// else if (!pio && written_burst && !dreq && !dack_r[1]) firstclk <= 1'b1; //dreq & dack_r1[1] overlap
// don't need to add &&!burst_start_sync[1] as burst_start_sync[1] overlaps with dack_r[1]
else if (!pio && nempty && !dreq && !dack_r[1]) firstclk <= 1'b1; //dreq & dack_r1[1] overlap
// if (rst || ((infifo[9:0]==10'h0) && burst_start_sync[1])) dreq <= 1'b0;
// changed to faster (registered) version. burst_start_sync[1] happens just first cycle after infifo[9:0] was decremented
// so we need that a cycle it was >1, not !=0. We can miss increment count (written_burst), but don't bother
// adding condition - not a great loss.
if (rst || (lessthan2 && burst_start_sync[1])) dreq <= 1'b0;
else if (firstclk) dreq <= 1'b1;
burst_start_sync[1:0] <= {burst_start_sync[0],~first_four_r[2] & first_four_r[1]};
first_four_r[2:0] <= {first_four_r[1:0],first_four};
empties[3:0] <= {4{!rst && (infifo[9:0]==10'h0) && !dreq && !dack_r[1]}} & {empties[2:0],1'b1};
end
always @ (posedge rst or posedge swclk) begin
if (rst) rab[8:0] <= 9'h0;
else if (mem_re) rab[8:0] <= rab[8:0] + 1;
if (rst) first_four <= 1'b0;
else if (rab[1:0]==2'h1) first_four <= ~rab[2];
end
RAMB16_S18_S36 i_dmafifobuff (
.DOA(), // Port A 16-bit Data Output - FPN (sensor) side
.DOPA(), // Port A 2-bit Parity Output
.ADDRA(wab[9:0]), // Port A 10-bit Address Input
// .CLKA(!clk), // Port A Clock
.CLKA(clk), // Port A Clock
.DIA(di[15:0]), // Port A 16-bit Data Input
.DIPA(2'b0), // Port A 2-bit parity Input
.ENA(we), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(1'b1), // Port A Write Enable Input
.DOB(d), // Port B 32-bit Data Output - SDRAM side
.DOPB(), // Port B 4-bit Parity Output
.ADDRB(rab[8:0]), // Port B 9-bit Address Input
.CLKB(swclk), // Port B Clock
.DIB(32'b0), // Port B 32-bit Data Input
.DIPB(4'b0), // Port-B 4-bit parity Input
.ENB(mem_re), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(1'b0) // Port B Write Enable Input
);
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/extjtag.v 0000664 0000000 0000000 00000010437 12555570767 0022572 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** extjtag.v
**
** GPIO control
**
** Copyright (C) 2007 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
/*
Control programming of external FPGA on the sensor/sensor multiplexor board
Mulptiplex status signals into a single line
bits:
31:20 - not used
19:16 - 0xb..0xf - no changes
- 0xa - select xfpgadone
- 0x9 - select xfpgatdo
- 0x8 - select senspgmin (default)
- 0x0..0x7 - no changes
15:10 - not used
9: 8 - 3 - set xpgmen,
- 2 - reset xpgmen,
- 0, 1 - no changes to xpgmen
7: 6 - 3 - set xfpgaprog,
- 2 - reset xfpgaprog,
- 0, 1 - no changes to xfpgaprog
5: 4 - 3 - set xfpgatck,
- 2 - reset xfpgatck,
- 0, 1 - no changes to xfpgatck
3: 2 - 3 - set xfpgatms,
- 2 - reset xfpgatms,
- 0, 1 - no changes to xfpgatms
1: 0 - 3 - set xfpgatdi,
- 2 - reset xfpgatdi,
- 0, 1 - no changes to xfpgatdi
*/
module extjtag (sclk, // @negedge
pre_wen, // 1 cycle ahead of write data
di, // [31:0] data in (only some bits are used)
xpgmen, // enable programming mode for an external FPGA
xfpgaprog, // PROG_B to be sent to an external FPGA
xfpgatck, // TCK to be sent to an external FPGA
xfpgatms, // TMS to be sent to an external FPGA
xfpgatdi, // TDI to be sent to an external FPGA
senspgmin, // state of the SENSPGM I/O pin (read)
xfpgadone, // state of the MRST pin ("DONE" pin on an external FPGA)
xfpgatdo, // TDO read from an external FPGA
state); // multiplexed state (one of 3 inputs)
input sclk;
input pre_wen;
input [31:0] di;
output xpgmen; // enable programming mode for an external FPGA
output xfpgaprog; // PROG_B to be sent to an external FPGA
output xfpgatck; // TCK to be sent to an external FPGA
output xfpgatms; // TMS to be sent to an external FPGA
output xfpgatdi;
input senspgmin;
input xfpgadone;
input xfpgatdo; // TDO read from an external FPGA
output state;
// reg wen;
wire wen= pre_wen;
wire [1:0] mux; // select source for state, initilaized to
wire xpgmen;
wire xfpgaprog;
wire xfpgatck;
wire xfpgatms;
wire xfpgatdi;
wire state=mux[1]?(mux[0]?1'b0:xfpgadone):(mux[0]?xfpgatdo:senspgmin);
/*
always @ (negedge sclk) begin
wen <= pre_wen;
end
*/
FDE_1 i_mux_0 (.C(sclk), .CE(wen & di[19]), .D(di[16]), .Q(mux[0]));
FDE_1 i_mux_1 (.C(sclk), .CE(wen & di[19]), .D(di[17]), .Q(mux[1]));
FDE_1 i_xpgmen (.C(sclk), .CE(wen & di[9]), .D(di[8]), .Q(xpgmen));
FDE_1 i_xfpgaprog (.C(sclk), .CE(wen & di[7]), .D(di[6]), .Q(xfpgaprog));
FDE_1 i_xfpgatck (.C(sclk), .CE(wen & di[5]), .D(di[4]), .Q(xfpgatck));
FDE_1 i_xfpgatms (.C(sclk), .CE(wen & di[3]), .D(di[2]), .Q(xfpgatms));
FDE_1 i_xfpgatdi (.C(sclk), .CE(wen & di[1]), .D(di[0]), .Q(xfpgatdi));
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/i2c_writeonly.v 0000664 0000000 0000000 00000037673 12555570767 0023730 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** i2c_writenly.v
**
** i2c (master, write only) controller with FIFO
**
** Copyright (C) 2008 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
// This i2c controller is designed to reduce CPU load while programming sensor over the
// i2c interface. Only write registers operation is implemented,
// registers are read out using direct pin contol by the software - it is needed only
// currently sensor register readout is only needed for debug purposes (that is not true
// for non-sensor boards connected to the sensor port)
//
// Each register is written in a separate i2c access, fetched by the controller from the
// 32-bit wide FIFO, Each long word is sent over i2c starting from the MSB ( slave address+op),
// then 0..3 of the next bytes (3bytes for 16-bit registers like in Micron sensors).
// Bytes are sent starting from the MSB, so to send 8-bit data 0x12 to register 0x34 of slave 0x56
// length should be set to 3 and data word should be 0x56341200
//
// i2C FIFO is split in 8 (only 7 are used) pages, corresponding to frames (separated by start of
// frame sync pulses), each pages being able to hold up to 64 commands (register writes)
//
// If frame sync happens before all the commands for current frame were sent out, they stiil will be sent
// before controller proceeds to the next page ones.
//
// If sensor ir running with very small frames/high FPS and controller tries to send too many commands - it
// is possible the FIFO will be overrun. It is up to the software to avoid such (practically very unlikely)
// conditions
//
// Controller is programmed through 16 locations (currently mapped to 0x50..0x5f):
// 0x0..0x7 write directly to the frame number [2:0] modulo 8, except if you write to the frame
// "just missed" - in that case data will go to the current frame.
// 0x8 - write i2c commands to be sent ASAP
// 0x9 - write i2c commands to be sent after the next frame starts
//
// 0xe - write i2c commands to be sent after the next 6 frames start
// 0xf - control register:
// [14] - reset all FIFO (takes 16 clock pulses), also - stops i2c until run command
// [13:12] - 3 - run i2c, 2 - stop i2c (needed before software i2c), 1,0 - no change to run state
// [11] - if 1, use [10:9] to set command bytes to send after slave address (0..3)
// [10:9] - number of bytes to send, valid if [11] is set
// [8] - set duration of quarter i2c cycle in system clock cycles - nominal value 100 (0x64)
// [7:0] - duration of quater i2c cycle (applied if [8] is set)
module i2c_writeonly (sclk, // @negedge
wen, // sync to address and d[0:15]
wa, // [3:0] 0..7 - absolute data, 8..0x0e relative data, 0x0f - command
di, // [15:0] data in
sync, // frame sync (used to synchronize data), vacts_sclk @negedge sclk
busy, // busy (do not use software i2i)
scl, // i2c SCL
sda, // i2c SDA
scl_en, // switch i2c control to i2c_writeonly (from software direct bit control PIO)
sda_en, // enable SDA output
frame_no); // [2:0] current frame modulo 8
input sclk;
input wen;
input [ 3:0] wa;
input [15:0] di;
input sync;
output busy;
output scl;
output sda;
output scl_en;
output sda_en;
output [2:0] frame_no;
// reg [4:0] wen_d; // [0] - not just fifo, but any PIO writes, [1] and next - filtered for FIFO only
reg [3:0] wen_d; // [0] - not just fifo, but any PIO writes, [1] and next - filtered for FIFO only
reg [3:0] wad;
reg [15:0] di_1;
reg [15:0] di_2;
reg [15:0] di_3;
reg [2:0] wpage0; // FIFO page were ASAP writes go
reg [2:0] wpage7; // unused page, currently being cleared
reg [2:0] page_r; // FIFO page were current write goes (reading)
reg [2:0] wpage_w; // FIFO page were current write goes (reading)
reg wpage0_inc; // increment wpage0 (after frame syn or during reset
reg wpage0_inc_d; // next cycle after wpage0_inc
reg reset_cmd;
reg dly_cmd;
reg bytes_cmd;
reg run_cmd;
reg reset_on; // reset FIFO in progress
reg [1:0] i2c_bytes;
reg [7:0] i2c_dly;
reg i2c_enrun; // enable i2c
reg we_fifo_wp; // enable writing to fifo write pointer memory
reg req_clr; // request for clearing fifo_wp
wire is_ctl= (wad[3:0]==4'hf);
// wire is_rel= ((wad[3]==1) && (wad[2:0]!=3'h7));
wire is_abs= (wad[3]==0);
wire pre_wpage0_inc = (!wen_d[0] && !wen_d[1] && !wpage0_inc) && (req_clr || reset_on) ;
wire [2:0] frame_no=wpage0[2:0];
//fifo write pointers (dual port distributed RAM)
reg [5:0] fifo_wr_pointers [0:7];
wire [5:0] fifo_wr_pointers_outw=fifo_wr_pointers[wpage_w[2:0]];
wire [5:0] fifo_wr_pointers_outr=fifo_wr_pointers[page_r[2:0]];
reg [5:0] fifo_wr_pointers_outw_r;
reg [5:0] fifo_wr_pointers_outr_r;
// command i2c fifo (RAMB16_S9_S18)
reg [9:0] i2c_cmd_wa; // wite address for the current pair of 16-bit data words
// {page[2:0],word[5:0],MSW[0]}
reg i2c_cmd_we; // write enable to blockRAM
reg [1:0] page_r_inc; // increment page_r[2:0]; - signal and delayed version
reg [5:0] rpointer; // FIFO read pointer for current page
reg i2c_start; // initiate i2c register write sequence
reg i2c_run; // i2c sequence is in progress
reg i2c_done; // i2c sequence is over
reg [1:0] bytes_left; // bytes left to send after this one
reg [1:0] byte_number; // byte number to send next (3-2-1-0)
reg [1:0] byte_sending; // byte number currently sending (3-2-1-0)
reg [5:0] i2c_state; // 0x2b..0x28 - sending start, 0x27..0x24 - stop, 0x23..0x4 - data, 0x03..0x00 - ACKN
reg [7:0] dly_cntr; // bit delay down counter
reg scl_hard;
reg sda_hard;
reg sda_en_hard;
reg wen_i2c_soft; // write software-contrlolles SDA, SCL state
reg scl_en_soft; // software i2c control signals (used when i2c controller is disabled)
reg scl_soft;
reg sda_en_soft;
reg sda_soft;
wire scl=i2c_run? scl_hard: scl_soft ;
wire sda=i2c_run? sda_hard: sda_soft ;
wire scl_en=i2c_run? 1'b1: scl_en_soft ;
wire sda_en=i2c_run? sda_en_hard: sda_en_soft ;
wire [7:0] i2c_data;
reg [8:0] i2c_sr;
reg i2c_dly_pre_over;
wire i2c_dly_pre2_over;
reg i2c_dly_over;
wire i2c_startseq_last=(i2c_state[5:0]==6'h28);
wire i2c_stopseq_last= (i2c_state[5:0]==6'h24);
wire i2c_dataseq_last= (i2c_state[5:0]==6'h00);
wire i2c_bit_last = (i2c_state[1:0]==2'h0);
wire i2c_is_ackn = (i2c_state[5:2]==4'h0);
wire i2c_is_start = i2c_state[5] && i2c_state[3];
wire i2c_is_stop = i2c_state[5] && i2c_state[2];
wire i2c_is_data = !i2c_state[5] || (!i2c_state[3] && !i2c_state[2]); // including ackn
// reg i2c_startseq_done; // last cycle of start sequence
reg i2c_dataseq_done; // last cycle of each byte sequence
// reg i2c_dataseq_all_done; // last cycle of the last byte sequence
reg [1:0] i2c_byte_start;
reg i2c_sr_shift;
reg i2c_stop_start;
reg sda_0;
reg scl_0;
reg busy;
reg [2:0] busy_cntr;
assign i2c_dly_pre2_over=(dly_cntr[7:0]==8'h2);
always @ (negedge sclk) begin
// signals related to writing to i2c FIFO
// delayed versions of address, data write strobe
if (wen) wad [ 3:0] <= wa[ 3:0];
if (wen || wen_d[0]) di_1[15:0] <= di[15:0];
di_2[15:0] <= di_1[15:0];
di_3[15:0] <= di_2[15:0];
// wen_d[4:0] <= {wen_d[3:1],wen_d[0] && !is_ctl,wen};
wen_d[3:0] <= {wen_d[2:1],wen_d[0] && !is_ctl,wen};
// software i2c signals
wen_i2c_soft <= wen_d[0] && is_ctl;
if (i2c_run) scl_en_soft <= 1'b0;
else if (wen_i2c_soft & |di_1[1:0]) scl_en_soft <= (di_1[1:0]!=2'h3);
if (i2c_run) scl_soft <= 1'b0;
else if (wen_i2c_soft & |di_1[1:0]) scl_soft <= (di_1[1:0]==2'h2);
if (i2c_run) sda_en_soft <= 1'b0;
else if (wen_i2c_soft & |di_1[3:2]) sda_en_soft <= (di_1[3:2]!=2'h3);
if (i2c_run) sda_soft <= 1'b0;
else if (wen_i2c_soft & |di_1[3:2]) sda_soft <= (di_1[3:2]==2'h2);
// decoded commands
reset_cmd <= wen_d[0] && is_ctl && di_1[14];
run_cmd <= wen_d[0] && is_ctl && di_1[13];
bytes_cmd <= wen_d[0] && is_ctl && di_1[11];
dly_cmd <= wen_d[0] && is_ctl && di_1[ 8];
// setting control parameters
if (bytes_cmd) i2c_bytes[1:0] <= di_2[10:9];
if (dly_cmd) i2c_dly[7:0] <= di_2[ 7:0];
if (reset_cmd || (run_cmd && !di_2[12])) i2c_enrun <= 1'b0;
else if (run_cmd && di_2[12]) i2c_enrun <= 1'b1;
// write pointer memory
wpage0_inc <= pre_wpage0_inc;
wpage0_inc_d <= wpage0_inc;
if (reset_cmd) wpage0[2:0]<=3'h0;
else if (wpage0_inc) wpage0[2:0]<=wpage0[2:0]+1;
if (reset_cmd) wpage7[2:0]<=3'h7;
else if (wpage0_inc) wpage7[2:0]<=wpage0[2:0];
reset_on <= reset_cmd || (reset_on && !(wpage0_inc && ( wpage0[2:0]==3'h7)));
req_clr <= sync || (req_clr && !wpage0_inc);
if (wen_d[0]) wpage_w[2:0] <= is_abs?((wad[2:0]==wpage7[2:0])? wpage0[2:0] : wad[2:0]):(wpage0[2:0]+wad[2:0]);
else if (wpage0_inc) wpage_w[2:0] <= wpage7[2:0];
we_fifo_wp <= wen_d[1] || wpage0_inc;
if (wen_d[1]) fifo_wr_pointers_outw_r[5:0] <= fifo_wr_pointers_outw[5:0];
if (we_fifo_wp) fifo_wr_pointers[wpage_w[2:0]] <= wpage0_inc_d? 6'h0:(fifo_wr_pointers_outw_r[5:0]+1);
fifo_wr_pointers_outr_r[5:0] <= fifo_wr_pointers_outr[5:0]; // just register distri
// command i2c fifo (RAMB16_S9_S18)
if (wen_d[1]) i2c_cmd_wa[9:1] <= {wpage_w[2:0],fifo_wr_pointers_outw[5:0]};
i2c_cmd_wa[0] <= !wen_d[1]; // 0 for the first in a pair, 1 - for the second
i2c_cmd_we <= !reset_cmd && (wen_d[1] || (i2c_cmd_we && !wen_d[3])); //reset_cmd added to keep simulator happy
// signals related to reading from i2c FIFO
if (reset_on) page_r[2:0]<=3'h0;
else if (page_r_inc[0]) page_r[2:0]<=page_r[2:0]+1;
if (reset_cmd || page_r_inc[0]) rpointer[5:0] <= 6'h0;
else if (i2c_done) rpointer[5:0] <= rpointer[5:0] + 1;
i2c_run <= !reset_cmd && (i2c_start || (i2c_run && !i2c_done));
i2c_start <= i2c_enrun && !i2c_run && !i2c_start && (rpointer[5:0]!= fifo_wr_pointers_outr_r[5:0]) && !page_r_inc[1] && !page_r_inc[0];
page_r_inc[1:0] <= {page_r_inc[0], !i2c_run &&
!page_r_inc[0] &&
(rpointer[5:0] == fifo_wr_pointers_outr_r[5:0]) &&
(page_r[2:0]!=wpage0[2:0])};
//i2c sequence generation
if (!i2c_run) bytes_left[1:0] <= i2c_bytes[1:0];
else if (i2c_dataseq_done) bytes_left[1:0] <= bytes_left[1:0] -1;
if (!i2c_run) byte_sending[1:0] <= 2'h3;
else if (i2c_dataseq_done) byte_sending[1:0] <= byte_sending[1:0] + 1;
if (!i2c_run) byte_number[1:0] <= 2'h3;
else if (i2c_byte_start[1])byte_number[1:0] <= byte_number[1:0] - 1;
if (!i2c_run || i2c_dly_over) dly_cntr[7:0] <= i2c_dly[7:0];
else dly_cntr[7:0] <= dly_cntr[7:0] - 1;
// i2c_dly_pre_over <= (dly_cntr[7:0]==8'h2); // period = 3..258
i2c_dly_pre_over <= i2c_dly_pre2_over; // period = 3..258
i2c_dly_over <=i2c_dly_pre_over;
// i2c_startseq_done <= i2c_startseq_last && i2c_dly_pre_over;
i2c_dataseq_done <= i2c_dataseq_last && i2c_dly_pre_over;
// i2c_dataseq_all_done <= i2c_dataseq_last && i2c_dly_pre_over && (bytes_left == 2'h0) ;
i2c_byte_start[1:0] <= {i2c_byte_start[0],
(i2c_startseq_last || (i2c_dataseq_last && (bytes_left[1:0] != 2'h0))) && i2c_dly_pre2_over };
i2c_sr_shift <= i2c_bit_last && !(i2c_dataseq_last) && i2c_dly_pre_over;
i2c_stop_start <= i2c_dataseq_last && (bytes_left[1:0] == 2'h0) && i2c_dly_pre_over ;
i2c_done <= i2c_stopseq_last && i2c_dly_pre_over;
if (i2c_byte_start[1]) i2c_sr[8:0] <= {i2c_data[7:0], 1'b1};
else if (i2c_sr_shift) i2c_sr[8:0] <= {i2c_sr[7:0], 1'b1};
if (!i2c_run) i2c_state[5:0] <= 6'h2a; // start of start seq
else if (i2c_stop_start) i2c_state[5:0] <= 6'h26; // start of stop seq
else if (i2c_byte_start[1]) i2c_state[5:0] <= 6'h23; // start of data seq
else if (i2c_dly_over) i2c_state[5:0] <= i2c_state[5:0] - 1;
// now creating output signals
scl_0 <= (i2c_is_start && (i2c_state[1:0]!=2'h0)) ||
(i2c_is_stop && !i2c_state[1]) ||
(i2c_is_data && (i2c_state[1] ^i2c_state[0])) ||
!i2c_run;
sda_0 <= (i2c_is_start && i2c_state[1]) ||
(i2c_is_stop && (i2c_state[1:0]==2'h0)) ||
(i2c_is_data && i2c_sr[8]) ||
!i2c_run;
sda_hard <= sda_0;
scl_hard <= scl_0;
sda_en_hard <= i2c_run && (!sda_0 || (!i2c_is_ackn && !sda_hard));
if (wen) busy_cntr[2:0] <= 3'h7;
else if (|busy_cntr[2:0]) busy_cntr[2:0] <= busy_cntr[2:0]-1;
busy <= (i2c_enrun && ((rpointer[5:0]!= fifo_wr_pointers_outr_r[5:0]) || (page_r[2:0]!=wpage0[2:0]))) ||
|busy_cntr[2:0] ||
i2c_run ||
reset_on;
end
RAMB16_S9_S18 i_fifo (
.DOA(i2c_data[7:0]), // Port A 8-bit Data Output
.DOPA(), // Port A 1-bit Parity Output
.ADDRA({page_r[2:0],
rpointer[5:0],
byte_number[1:0]}), // Port A 11-bit Address Input
.CLKA(!sclk), // Port A Clock
.DIA(8'h0), // Port A 8-bit Data Input
.DIPA(1'b0), // Port A 1-bit parity Input
.ENA(i2c_byte_start[0]), // Port A RAM Enable Input
.SSRA(1'b0), // Port A Synchronous Set/Reset Input
.WEA(1'b0), // Port A Write Enable Input
.DOB(), // Port B 16-bit Data Output
.DOPB(), // Port B 2-bit Parity Output
.ADDRB(i2c_cmd_wa[9:0]), // Port B 10-bit Address Input
.CLKB(!sclk), // Port B Clock
.DIB(di_3[15:0]), // Port B 16-bit Data Input
.DIPB(2'b0), // Port-B 2-bit parity Input
.ENB(i2c_cmd_we), // PortB RAM Enable Input
.SSRB(1'b0), // Port B Synchronous Set/Reset Input
.WEB(1'b1) // Port B Write Enable Input
);
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/interrupts_vector333.v 0000664 0000000 0000000 00000033123 12555570767 0025153 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** interrupts_vector333.v
**
** Interrupts controller
**
** Copyright (C) 2005-2008 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X333
** X333 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
// will support 16 priority (0 - highest) masked vector interrupts (pos. edge triggered), use 4 locations of address space,
// generate 32-bit data output (16MSBs - before mask, lower 16 bits - masked)
module interrupts_vector(sclk, // @negedge
pre_wen, // 1 cycle ahead of write data
pre_wa, // [1:0] - write address:
// 0 - reset selected interrupt bits
// 1 - disable selected interrupt bits (mask)
// 2 - enable selected interrupt bits
// 3 - write vector number (bits [0:7], [11:8] - interrupt number (0..15)
di, // [15:0] data in
do, // [31:0] data out (bits {15:0} - masked interrupts, [31:0] - same before mask
irq, // interrupt request (active high)
inta, // interrupt acknowledge input (active low) 170ns long
irq_in, // [15:0] input interrupt requests (posedge)
irqv); // [7:0] interrupt vector (valid befor end on inta
input sclk;
input pre_wen;
input [1:0] pre_wa;
input [15:0] di;
output [31:0] do;
output irq;
input inta;
input [15:0] irq_in;
output [7:0] irqv;
wire [15:0] irq_insa;
reg [15:0] irq_insb;
reg [15:0] irq_insc; //single cycle sync interrupt request.
///AF: wire [15:0] irq_rst;
reg rst_rqs, en_rqs, dis_rqs, pre_set_irqv, set_irqv;
reg [ 3:0] irqv_a; // irq vectors table write address
reg [ 7:0] irqv_d; // irq vectors table write data
reg [15:0] rst_rq;
reg [15:0] dis_rq;
// reg [15:0] en_rq;
wire [15:0] en_rq;
wire [15:0] irqm;
reg [ 5:0] inta_s; // inta sync to clock
// reg [15:0] irq_um; // interrupts (before mask)
wire [15:0] irq_um; // interrupts (before mask)
reg [15:0] irq_frz; // frozen masked irq-s (for the duration of the synchronized inta)
wire [15:0] irqp; // one-hot irq (prioritized)
wire [ 3:0] irqn; // encoded vector number;
reg [ 3:0] irqn_r; // registered encoded vector number (not neded to be registered?
wire [15:0] rst_rq_inta; // reset interrupts from inta
reg pre_irq;
reg [15:0] did; // did[15:0] delayed by 1 cycle
wire en_all_rq; // for simulation
assign irq=pre_irq && inta;
assign do[31:0]={irq_um[15:0], irq_frz[15:0]};
assign irqp[ 0] = irq_frz[ 0];
assign irqp[ 1] = irq_frz[ 1] && !irq_frz[ 0];
assign irqp[ 2] = irq_frz[ 2] && !(|irq_frz[ 1:0]);
assign irqp[ 3] = irq_frz[ 3] && !(|irq_frz[ 2:0]);
assign irqp[ 4] = irq_frz[ 4] && !(|irq_frz[ 3:0]);
assign irqp[ 5] = irq_frz[ 5] && !(|irq_frz[ 4:0]);
assign irqp[ 6] = irq_frz[ 6] && !(|irq_frz[ 5:0]);
assign irqp[ 7] = irq_frz[ 7] && !(|irq_frz[ 6:0]);
assign irqp[ 8] = irq_frz[ 8] && !(|irq_frz[ 7:0]);
assign irqp[ 9] = irq_frz[ 9] && !(|irq_frz[ 8:0]);
assign irqp[10] = irq_frz[10] && !(|irq_frz[ 9:0]);
assign irqp[11] = irq_frz[11] && !(|irq_frz[10:0]);
assign irqp[12] = irq_frz[12] && !(|irq_frz[11:0]);
assign irqp[13] = irq_frz[13] && !(|irq_frz[12:0]);
assign irqp[14] = irq_frz[14] && !(|irq_frz[13:0]);
assign irqp[15] = irq_frz[15] && !(|irq_frz[14:0]);
assign irqn[0]= irqp[1] | irqp[3] | irqp[ 5] | irqp[ 7] | irqp[ 9] | irqp[11] | irqp[13] | irqp[15];
assign irqn[1]= irqp[2] | irqp[3] | irqp[ 6] | irqp[ 7] | irqp[10] | irqp[11] | irqp[14] | irqp[15];
assign irqn[2]= irqp[4] | irqp[5] | irqp[ 6] | irqp[ 7] | irqp[12] | irqp[13] | irqp[14] | irqp[15];
assign irqn[3]= irqp[8] | irqp[9] | irqp[10] | irqp[11] | irqp[12] | irqp[13] | irqp[14] | irqp[15];
assign rst_rq_inta[ 0]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h0);
assign rst_rq_inta[ 1]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h1);
assign rst_rq_inta[ 2]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h2);
assign rst_rq_inta[ 3]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h3);
assign rst_rq_inta[ 4]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h4);
assign rst_rq_inta[ 5]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h5);
assign rst_rq_inta[ 6]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h6);
assign rst_rq_inta[ 7]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h7);
assign rst_rq_inta[ 8]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h8);
assign rst_rq_inta[ 9]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'h9);
assign rst_rq_inta[10]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'ha);
assign rst_rq_inta[11]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'hb);
assign rst_rq_inta[12]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'hc);
assign rst_rq_inta[13]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'hd);
assign rst_rq_inta[14]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'he);
assign rst_rq_inta[15]= inta_s[1] && !inta_s[2] && (irqn_r[3:0] == 4'hf);
FDE_1 i_en_all_rq(.C(sclk), .CE(pre_wen), .D(1'b1), .Q(en_all_rq)); // initially disabled - till first write
FDC i_insa_0 (.C(irq_in[ 0]), .CLR(irq_insc[ 0]), .D(1'b1), .Q(irq_insa[ 0]));
FDC i_insa_1 (.C(irq_in[ 1]), .CLR(irq_insc[ 1]), .D(1'b1), .Q(irq_insa[ 1]));
FDC i_insa_2 (.C(irq_in[ 2]), .CLR(irq_insc[ 2]), .D(1'b1), .Q(irq_insa[ 2]));
FDC i_insa_3 (.C(irq_in[ 3]), .CLR(irq_insc[ 3]), .D(1'b1), .Q(irq_insa[ 3]));
FDC i_insa_4 (.C(irq_in[ 4]), .CLR(irq_insc[ 4]), .D(1'b1), .Q(irq_insa[ 4]));
FDC i_insa_5 (.C(irq_in[ 5]), .CLR(irq_insc[ 5]), .D(1'b1), .Q(irq_insa[ 5]));
FDC i_insa_6 (.C(irq_in[ 6]), .CLR(irq_insc[ 6]), .D(1'b1), .Q(irq_insa[ 6]));
FDC i_insa_7 (.C(irq_in[ 7]), .CLR(irq_insc[ 7]), .D(1'b1), .Q(irq_insa[ 7]));
FDC i_insa_8 (.C(irq_in[ 8]), .CLR(irq_insc[ 8]), .D(1'b1), .Q(irq_insa[ 8]));
FDC i_insa_9 (.C(irq_in[ 9]), .CLR(irq_insc[ 9]), .D(1'b1), .Q(irq_insa[ 9]));
FDC i_insa_10 (.C(irq_in[10]), .CLR(irq_insc[10]), .D(1'b1), .Q(irq_insa[10]));
FDC i_insa_11 (.C(irq_in[11]), .CLR(irq_insc[11]), .D(1'b1), .Q(irq_insa[11]));
FDC i_insa_12 (.C(irq_in[12]), .CLR(irq_insc[12]), .D(1'b1), .Q(irq_insa[12]));
FDC i_insa_13 (.C(irq_in[13]), .CLR(irq_insc[13]), .D(1'b1), .Q(irq_insa[13]));
FDC i_insa_14 (.C(irq_in[14]), .CLR(irq_insc[14]), .D(1'b1), .Q(irq_insa[14]));
FDC i_insa_15 (.C(irq_in[15]), .CLR(irq_insc[15]), .D(1'b1), .Q(irq_insa[15]));
FD_1 i_irqm_0 (.C(sclk), .D(en_rq[ 0] || (!dis_rq[ 0] && irqm[ 0])), .Q(irqm[ 0]));
FD_1 i_irqm_1 (.C(sclk), .D(en_rq[ 1] || (!dis_rq[ 1] && irqm[ 1])), .Q(irqm[ 1]));
FD_1 i_irqm_2 (.C(sclk), .D(en_rq[ 2] || (!dis_rq[ 2] && irqm[ 2])), .Q(irqm[ 2]));
FD_1 i_irqm_3 (.C(sclk), .D(en_rq[ 3] || (!dis_rq[ 3] && irqm[ 3])), .Q(irqm[ 3]));
FD_1 i_irqm_4 (.C(sclk), .D(en_rq[ 4] || (!dis_rq[ 4] && irqm[ 4])), .Q(irqm[ 4]));
FD_1 i_irqm_5 (.C(sclk), .D(en_rq[ 5] || (!dis_rq[ 5] && irqm[ 5])), .Q(irqm[ 5]));
FD_1 i_irqm_6 (.C(sclk), .D(en_rq[ 6] || (!dis_rq[ 6] && irqm[ 6])), .Q(irqm[ 6]));
FD_1 i_irqm_7 (.C(sclk), .D(en_rq[ 7] || (!dis_rq[ 7] && irqm[ 7])), .Q(irqm[ 7]));
FD_1 i_irqm_8 (.C(sclk), .D(en_rq[ 8] || (!dis_rq[ 8] && irqm[ 8])), .Q(irqm[ 8]));
FD_1 i_irqm_9 (.C(sclk), .D(en_rq[ 9] || (!dis_rq[ 9] && irqm[ 9])), .Q(irqm[ 9]));
FD_1 i_irqm_10 (.C(sclk), .D(en_rq[10] || (!dis_rq[10] && irqm[10])), .Q(irqm[10]));
FD_1 i_irqm_11 (.C(sclk), .D(en_rq[11] || (!dis_rq[11] && irqm[11])), .Q(irqm[11]));
FD_1 i_irqm_12 (.C(sclk), .D(en_rq[12] || (!dis_rq[12] && irqm[12])), .Q(irqm[12]));
FD_1 i_irqm_13 (.C(sclk), .D(en_rq[13] || (!dis_rq[13] && irqm[13])), .Q(irqm[13]));
FD_1 i_irqm_14 (.C(sclk), .D(en_rq[14] || (!dis_rq[14] && irqm[14])), .Q(irqm[14]));
FD_1 i_irqm_15 (.C(sclk), .D(en_rq[15] || (!dis_rq[15] && irqm[15])), .Q(irqm[15]));
FD_1 i_en_rq_0 (.C(sclk), .D(en_rqs & did[ 0]), .Q(en_rq[ 0]));
FD_1 i_en_rq_1 (.C(sclk), .D(en_rqs & did[ 1]), .Q(en_rq[ 1]));
FD_1 i_en_rq_2 (.C(sclk), .D(en_rqs & did[ 2]), .Q(en_rq[ 2]));
FD_1 i_en_rq_3 (.C(sclk), .D(en_rqs & did[ 3]), .Q(en_rq[ 3]));
FD_1 i_en_rq_4 (.C(sclk), .D(en_rqs & did[ 4]), .Q(en_rq[ 4]));
FD_1 i_en_rq_5 (.C(sclk), .D(en_rqs & did[ 5]), .Q(en_rq[ 5]));
FD_1 i_en_rq_6 (.C(sclk), .D(en_rqs & did[ 6]), .Q(en_rq[ 6]));
FD_1 i_en_rq_7 (.C(sclk), .D(en_rqs & did[ 7]), .Q(en_rq[ 7]));
FD_1 i_en_rq_8 (.C(sclk), .D(en_rqs & did[ 8]), .Q(en_rq[ 8]));
FD_1 i_en_rq_9 (.C(sclk), .D(en_rqs & did[ 9]), .Q(en_rq[ 9]));
FD_1 i_en_rq_10 (.C(sclk), .D(en_rqs & did[10]), .Q(en_rq[10]));
FD_1 i_en_rq_11 (.C(sclk), .D(en_rqs & did[11]), .Q(en_rq[11]));
FD_1 i_en_rq_12 (.C(sclk), .D(en_rqs & did[12]), .Q(en_rq[12]));
FD_1 i_en_rq_13 (.C(sclk), .D(en_rqs & did[13]), .Q(en_rq[13]));
FD_1 i_en_rq_14 (.C(sclk), .D(en_rqs & did[14]), .Q(en_rq[14]));
FD_1 i_en_rq_15 (.C(sclk), .D(en_rqs & did[15]), .Q(en_rq[15]));
FD_1 i_irq_um_0 (.C(sclk), .D(~(rst_rq[ 0]) & (irq_insc[ 0] | irq_um[ 0])), .Q(irq_um[ 0]));
FD_1 i_irq_um_1 (.C(sclk), .D(~(rst_rq[ 1]) & (irq_insc[ 1] | irq_um[ 1])), .Q(irq_um[ 1]));
FD_1 i_irq_um_2 (.C(sclk), .D(~(rst_rq[ 2]) & (irq_insc[ 2] | irq_um[ 2])), .Q(irq_um[ 2]));
FD_1 i_irq_um_3 (.C(sclk), .D(~(rst_rq[ 3]) & (irq_insc[ 3] | irq_um[ 3])), .Q(irq_um[ 3]));
FD_1 i_irq_um_4 (.C(sclk), .D(~(rst_rq[ 4]) & (irq_insc[ 4] | irq_um[ 4])), .Q(irq_um[ 4]));
FD_1 i_irq_um_5 (.C(sclk), .D(~(rst_rq[ 5]) & (irq_insc[ 5] | irq_um[ 5])), .Q(irq_um[ 5]));
FD_1 i_irq_um_6 (.C(sclk), .D(~(rst_rq[ 6]) & (irq_insc[ 6] | irq_um[ 6])), .Q(irq_um[ 6]));
FD_1 i_irq_um_7 (.C(sclk), .D(~(rst_rq[ 7]) & (irq_insc[ 7] | irq_um[ 7])), .Q(irq_um[ 7]));
FD_1 i_irq_um_8 (.C(sclk), .D(~(rst_rq[ 8]) & (irq_insc[ 8] | irq_um[ 8])), .Q(irq_um[ 8]));
FD_1 i_irq_um_9 (.C(sclk), .D(~(rst_rq[ 9]) & (irq_insc[ 9] | irq_um[ 9])), .Q(irq_um[ 9]));
FD_1 i_irq_um_10 (.C(sclk), .D(~(rst_rq[10]) & (irq_insc[10] | irq_um[10])), .Q(irq_um[10]));
FD_1 i_irq_um_11 (.C(sclk), .D(~(rst_rq[11]) & (irq_insc[11] | irq_um[11])), .Q(irq_um[11]));
FD_1 i_irq_um_12 (.C(sclk), .D(~(rst_rq[12]) & (irq_insc[12] | irq_um[12])), .Q(irq_um[12]));
FD_1 i_irq_um_13 (.C(sclk), .D(~(rst_rq[13]) & (irq_insc[13] | irq_um[13])), .Q(irq_um[13]));
FD_1 i_irq_um_14 (.C(sclk), .D(~(rst_rq[14]) & (irq_insc[14] | irq_um[14])), .Q(irq_um[14]));
FD_1 i_irq_um_15 (.C(sclk), .D(~(rst_rq[15]) & (irq_insc[15] | irq_um[15])), .Q(irq_um[15]));
myRAM16X8D_1 i_vecttab (.D(irqv_d[7:0]), .WE(set_irqv), .clk(sclk), .AW(irqv_a[3:0]), .AR(irqn_r[3:0]), .QR(irqv[7:0]), .QW());
always @ (negedge sclk) begin
if (pre_wen) did[15:0] <= di[15:0];
if (en_all_rq) begin
irq_insb[15:0] <= irq_insa[15:0];
irq_insc[15:0] <= irq_insb[15:0] & (~irq_insc[15:0]);
end else begin
irq_insb[15:0] <= 16'h0;
irq_insc[15:0] <= 16'h0;
end
rst_rqs <= pre_wen && (pre_wa[1:0] == 2'h0);
dis_rqs <= pre_wen && (pre_wa[1:0] == 2'h1);
en_rqs <= pre_wen && (pre_wa[1:0] == 2'h2);
pre_set_irqv <= pre_wen && (pre_wa[1:0] == 2'h3);
set_irqv <= pre_set_irqv;
if (pre_set_irqv) irqv_a[3:0] <= did[11:8];
if (pre_set_irqv) irqv_d[7:0] <= did[ 7:0];
rst_rq[15:0] <= ({16{rst_rqs}} & did[15:0]) | rst_rq_inta[15:0];
dis_rq[15:0] <= ({16{dis_rqs}} & did[15:0]);
// en_rq [15:0] <= ({15{ en_rqs}} & did[15:0]);
inta_s[5:0] <= {inta_s[4:0], inta};
if (inta_s[1]) irq_frz[15:0] <= irq_um[15:0] & irqm[15:0];
irqn_r[3:0] <= irqn[3:0]; // will be invalid for a cycle - long combinatorial logic delays
pre_irq <= |irq_frz[15:0] & inta_s[5];
end
endmodule
module myRAM16X8D_1(D,WE,clk,AW,AR,QW,QR);
input [7:0] D;
input WE,clk;
input [3:0] AW;
input [3:0] AR;
output [7:0] QW;
output [7:0] QR;
reg [7:0] ram [0:15];
always @ (negedge clk) if (WE) ram[AW] <= D;
assign QW= ram[AW];
assign QR= ram[AR];
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/ioports353.v 0000664 0000000 0000000 00000143251 12555570767 0023057 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** ioports353.v
**
** I/O pads related circuitry
**
** Copyright (C) 2002-2008 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
module dmapads#(
parameter IOSTANDARD_SYS = "LVCMOS33",
parameter SLEW_SYS_DREQ = "SLOW",
parameter DRIVE_SYS_DREQ = 4,
parameter IBUF_DELAY_SYS_DACK = "0",
parameter IFD_DELAY_SYS_DACK = "0"
) (dreq0,dack0,idreq0,idack0,dreq1,dack1,idreq1,idack1);
output dreq0,dreq1;
input dack0,dack1;
input idreq0,idreq1;
output idack0,idack1;
OBUF #(
.IOSTANDARD(IOSTANDARD_SYS),
.DRIVE(DRIVE_SYS_DREQ),
.SLEW(SLEW_SYS_DREQ))
i_dreq0 (.I(idreq0), .O(dreq0));
IBUF #(
.IOSTANDARD (IOSTANDARD_SYS),
.IBUF_DELAY_VALUE (IBUF_DELAY_SYS_DACK),
.IFD_DELAY_VALUE (IFD_DELAY_SYS_DACK))
i_dack0 (.I(dack0), .O(idack0));
OBUF #(
.IOSTANDARD(IOSTANDARD_SYS),
.DRIVE(DRIVE_SYS_DREQ),
.SLEW(SLEW_SYS_DREQ))
i_dreq1 (.I(idreq1), .O(dreq1));
IBUF #(
.IOSTANDARD (IOSTANDARD_SYS),
.IBUF_DELAY_VALUE (IBUF_DELAY_SYS_DACK),
.IFD_DELAY_VALUE (IFD_DELAY_SYS_DACK))
i_dack1 (.I(dack1), .O(idack1));
endmodule
module i2cpads (sda,scl,sda_o,sda_i,sda_en,scl_o,scl_i,scl_en);
inout sda;
inout scl;
input sda_o;
input sda_en;
output sda_i;
input scl_o;
input scl_en;
output scl_i;
IOBUF i_sda0 (.I(sda_o), .T(!sda_en), .O(sda_i), .IO(sda));
IOBUF i_scl0 (.I(scl_o), .T(!scl_en), .O(scl_i), .IO(scl));
endmodule
module sysinterface #(
parameter IOSTANDARD_SYS = "LVCMOS33",
parameter SLEW_SYS = "SLOW",
parameter DRIVE_SYS = 8,
parameter IBUF_DELAY_SYS_A = "0",
parameter IFD_DELAY_SYS_A = "0",
parameter IBUF_DELAY_SYS_D = "0",
parameter IFD_DELAY_SYS_D = "0",
parameter IBUF_DELAY_SYS_WOE = "0",
parameter IFD_DELAY_SYS_WOE = "0",
parameter IBUF_DELAY_SYS_CE = "0",
parameter IFD_DELAY_SYS_CE = "0") (
clk,
drv_bus, // drive system bus (to write to system memory)
d, // 32 bit D[31:0] data pads
oe, // OE pad
ce, // CE pad (zero wait states)
ce1, // CE1 pad (EW=1)
we, // WE pad
a, // 13 bit A[12:0] pads
iod, // internal 32-bit data out (FPGA->CPU) bus
// as of v. 03533016 idi[31:16] is valid with da_*, twr_* and one cycle after,
// idi[15:0] is multiplexed: withda_*, twr_*it has di[15:0], next cycle = di[31:16]
idi, // internal 32-bit data in, synchronous to clk
ia, // internal 8-bit address bus (fast - directly from I/O pads)
as, // internal 8-bit address bus (synchronized to clk)
am, // multiplexed addr - switching between ia and as
wnr, // write/not read, sync with clk
da_ctl, // WE to control 32-bit register, low 24 bits (1 loc)
da_ctl_h, // enable writing to high 8 bits of the dcr
da_dmamode, // select writing to dma_cntr/dma_raw (1 loc)
da_sensormode, // select writing to sensorpix (1 loc)
da_virttrig, // write virtual trigger threshold
da_sensortrig, // sensor control: bit0 continuous, bit1 - external, bit2 - enable
da_sensortrig_lines,// write number of lines to be transferred in a frame (or aftre trigger)
da_dswe, // select reading/writing to mcontr (16 locations)
da_init_ch3, // write to init cnhannel 3 (will reset address r/w)
da_next_ch3, // advance to the next channel3 page, reset address
da_mem, // read/write to SDRAM buffer, autoincrement address
// in read mode - needs CE1 to autoincrement!
da_lensff, // lens flat field correction parameters (1 location, 8 bit address, 16bit - data)
da_hist, // 0x40..0x47 write/read histogram related data/registers
// 40 - left
// 41 - top
// 42 - width-1
// 43 - height-1
// 44 - hist. data start address (will also read pointed word to output word
da_hist_next, // 45 - read histogram (with CE1 to autoincrement)
da_rtc, // 48 - write microseconds (actual write will happen after writing seconds)
// 49 - write seconds
// 4a - write correction (16 bit, signed
// 4b - nop, just latch the output 32+20 bits to read to CPU). Maybe nop (or 2 writes) are needed between read.
da_timestamp, // 4c - write timesatmp mode (0 - off, 1 - normal frames, 1 photo-finish)
da_sens_dc, // write clock divisor for sensor DCDC converter
da_interrupts, // interrupt control 0x1c..0x1f
da_compressor, // 0x0c - 0x0f - will be farther decoded in the compressor module
da_dcm, // tune SDRAM clock
da_saturation, // write color saturation vaues (currently 10 bits
da_framesync_dly,
da_quantizer_mode, // Quantizer tuning - 0..7 - zero bin, 15:8 - quantizer bias
da_io_pins, // write i/o pins control (for 6 pins to connector J2) - 0x70
da_pio_dmafifo, // increment address of the DMA FIFO(S) (PIO mode should be enabled in the desired channel)
da_xjtag, // write to external (sensor board) JTAG
da_extsync, // control of external sync module 0x78 - 0x7b
da_extio, // external I/O (motor control 0x7c-0x7d)
da_imu, // IMU (imu r/w 0x7e-0x7f)
// da_imu_read, // read any of the IMU data/status (updates memory output reg)
// da_imu_next, // read IMU dataread from pointer, increment address
da_i2c, // i2c_writeonly control (0x50 - 0x5f)
da_irq_smart, // single IRQ control (0x1a)
da_sequencer, // command sequencer (0x60..0x6f)
da_dcr, // write to control registers (0x4e..0x4f), each bit/group with individual enable by data bit
ta, // [10:0] table address - will be valid at twr_xx and one cycle beforfe (@ negedge clk)
twr_quant, // write enable to quantization table (@negedge clk - addr and data valid this cycle and one before)
twr_coring, // coring functions tables (@negedge clk - addr and data valid this cycle and one before)
twr_huff, // write enable to huffman table (@negedge clk - addr and data valid this cycle and one before)
twr_gamma, // write enable to "gamma" table (@negedge clk - addr and data valid this cycle and one before)
twr_focus, // write enable to "focus" table (@negedge clk - addr and data valid this cycle and one before)
dcmrst, // (emergency)async DCM reset Seems SE hangs if the frequency changed on the fly
ioe, // OE after IBUF
seq_rq, // request from the sequencer
seq_ack, // sequencer acknowledge
seq_a, // address from the sequencer
seq_d // data from the sequencer
);
input clk;
input drv_bus;
inout [31:0] d;
input oe;
input ce;
input ce1;
input we;
inout [12:0] a;
input [31:0] iod;
output [31:0] idi;
output [7:0] ia;
output [7:0] as; // output clock-synchronous address
output [7:0] am;
output wnr;
output [11:0] ta;
output twr_quant;
output twr_coring;
output twr_huff;
output twr_gamma;
output twr_focus;
output da_ctl; // WE to control 32-bit register (1 loc) (lower 25 bits)
output da_ctl_h; // WE to control 32-bit register (1 loc) (top 8 bits)
output da_dmamode; // select writing to dma_cntr/dma_raw (1 loc)
output da_sensormode; // select writing to sensorpix (1 loc)
output da_virttrig; // write virtual trigger threshold
output da_sensortrig; // sensor control: bit0 continuous, bit1 - external, bit2 - enable
output da_sensortrig_lines; // write number of lines to be transferred in a frame (or aftre trigger)
output da_dswe; // select reading/writing to mcontr (16 locations)
output da_init_ch3; // write to init cnhannel 3 (will reset address r/w)
output da_next_ch3; // advance to the next channel3 page, reset address
output da_mem; // read/write to SDRAM buffer, autoincrement address
// in read mode - needs CE1 to autoincrement!
output da_lensff; // lens flat field correction parameters (1 location, 8 bit address, 16bit - data)
output da_sens_dc; // write clock divisor for sensor DCDC converter
output da_interrupts; // interrupt mask
output da_compressor; // 0x0c - 0x0f - will be farther decoded in the compressor module
output da_dcm; // tune SDRAM clock
output da_saturation; // write color saturation vaues (currently 10 bits
output da_quantizer_mode; // Quantizer tuning - 0..7 - zero bin, 15:8 - quantizer bias
output da_hist; // write/read histogram related data/registers
output da_hist_next;
output da_framesync_dly;
output da_io_pins; // write i/o pins control (for 6 pins to connector J2) - 0x70
output da_rtc;
output da_timestamp; // 4c - write timesatmp mode (0 - off, 1 - normal frames, 1 photo-finish)
output dcmrst; // async
output da_pio_dmafifo; // increment address of the DMA FIFO(S) (PIO mode should be enabled in the desired channel)
output da_xjtag; // write to external (sensor board) JTAG
output da_extsync; // control of external sync module 0x78 - 0x7b
output da_extio; // external I/O (motor control 0x7c-0x7d)
output da_imu; // IMU
// output da_imu_read; // read any of the IMU data/status (updates memory output reg)
// output da_imu_next; // read IMU data: read from pointer, increment address
output da_i2c; // i2c_writeonly control (0x50 - 0x5f)
output da_irq_smart; // single IRQ control (0x1a)
output da_sequencer; // command sequencer (0x60..0x6f)
output da_dcr; // write to control registers (0x4e..0x4f), each bit/group with individual enable by data bit
output ioe;
input seq_rq; // request from the sequencer
output seq_ack; // sequencer acknowledge
input [ 7:0] seq_a; // address from the sequencer
input [23:0] seq_d; // data from the sequencer
reg dcmrst;
wire cwr;
wire iwe;
reg [31:0] idi;
wire t;
wire ioe;
wire ice;
wire ice1;
wire irnw;
wire [ 7:0] ial; // enabled during oe/we high, held - during low
reg wnr;
wire [31:0] id0; //registered at the end of !cwr
reg [ 7:0] ia0; //registered at the end of !cwr
reg irnw0;//registered at the end of !cwr
reg [ 7:0] as; // output clock-synchronous address
reg da_ctl; // WE to control 32-bit register (1 loc)
reg da_ctl_h; // enable writing to high 8 bits of the dcr
reg da_dmamode; // select writing to dma_cntr/dma_raw (1 loc)
reg da_sensormode; // select writing to sensorpix (1 loc)
reg da_virttrig; // write virtual trigger threshold
reg da_sensortrig; // sensor control: bit0 continuous, bit1 - external, bit2 - enable
reg da_sensortrig_lines; // write number of lines to be transferred in a frame (or aftre trigger)
reg da_dswe; // select reading/writing to mcontr (16 locations)
reg da_init_ch3; // write to init cnhannel 3 (will reset address r/w)
reg da_next_ch3; // advance to the next channel3 page, reset address
reg da_mem; // read/write to SDRAM buffer, autoincrement address
reg da_lensff; // lens flat field correction parameters (1 location, 8 bit address, 16bit - data)
reg da_sens_dc; // write clock divisor for sensor DCDC converter
reg da_interrupts; // interrupt mask
reg da_compressor; // 0x0c - 0x0f - will be farther decoded in the compressor module
reg da_dcm; // tune SDRAM clock phase
reg da_table_a; // write table address (internal)
reg da_saturation; // write color saturation values
reg da_quantizer_mode;// Quantizer tuning - 0..7 - zero bin, 15:8 - quantizer bias
reg da_hist; // write/read histogram related data/registers
reg da_framesync_dly;
reg da_io_pins; // write i/o pins control (for 6 pins to connector J2) - 0x70
reg da_rtc;
reg da_timestamp;
reg da_pio_dmafifo0, da_pio_dmafifo; // increment address of the DMA FIFO(S) (PIO mode should be enabled in the desired channel)
reg da_xjtag; // write to external (sensor board) JTAG
reg da_extsync; // control of external sync module 0x78 - 0x7b
reg da_extio; // external I/O (motor control 0x7c-0x7d)
reg da_imu; // imu control
reg da_i2c; // i2c_writeonly control (0x50 - 0x5f)
reg da_sequencer; // command sequencer (0x60..0x6f)
reg da_dcr; // write to control registers (0x4e..0x4f), each bit/group with individual enable by data bit
reg da_irq_smart; // single IRQ control (0x1a)
reg twr; // write table data (address will be incremented 1 cycle after
reg da_hist_next0, da_hist_next; // reading histogram - ASAP, nosequencer - use sync2
// reg da_imu_read0, da_imu_read; // read any of the IMU data/status (updates memory output reg)
// reg da_imu_next0, da_imu_next; // read IMU dataread from pointer, increment address
reg [11:0] pre_ta; // one cycle ahead of ta
reg [11:0] ta; // table address. valid with twr_* and 1 cycle after
reg twr_quant;
reg twr_coring; // coring functions tables (@negedge clk - addr and data valid this cycle and one before)
reg twr_huff;
reg twr_gamma;
reg twr_focus;
wire [7:0] am;
reg wra; // to select source of as - for 2 cycles during sync write will use as, else - ia;
// inter-clock synchronization
wire sync0; // from end of the cwr low to sync2
wire sync1; // sync0 registered @negedge sclk
wire sync2; // sync1 registered @posedge sclk
wire sync_cwr_start0; // from start of the cwr low to sync_cwr_start2
wire sync_cwr_start1; // sync_cwr_start0 registered @negedge sclk
wire sync_cwr_start2; // sync_cwr_start1 registered @posedge sclk
wire sync_cwr_on; // from sync_cwr_start1 to sync1, registered @posedge sclk
reg [7:0] a_pio_seq_mux; // address, multiplexed between direct/sequencer access (valid @wr_state[0])
reg wnr_seq_mux; // write/not read, multiplexed between direct/sequencer access (valid @wr_state[0])
reg [31:0] d_pio_seq_mux; // data, multiplexed between direct/sequencer access (valid @wr_state[0])
reg seq_ack; // using data from sequencer (first cycle)
// reg [2:0] wr_state; // 1-hot write sequence for both pio and seq.
reg [1:0] wr_state; // 1-hot write sequence for both pio and seq.
// [0] - decoding address,
// [1] - output low 16 (32)
// [2] - output high 16 (8)
assign am[7:0]= wra? as[7:0] : ia[7:0];
IBUF #(
.IOSTANDARD (IOSTANDARD_SYS),
.IBUF_DELAY_VALUE(IBUF_DELAY_SYS_WOE),
.IFD_DELAY_VALUE(IFD_DELAY_SYS_WOE))
i_oe (.I(oe), .O(ioe ));
IBUF #(
.IOSTANDARD (IOSTANDARD_SYS),
.IBUF_DELAY_VALUE(IBUF_DELAY_SYS_CE),
.IFD_DELAY_VALUE(IFD_DELAY_SYS_CE))
i_ce (.I(ce), .O(ice ));
IBUF #(
.IOSTANDARD (IOSTANDARD_SYS),
.IBUF_DELAY_VALUE(IBUF_DELAY_SYS_WOE),
.IFD_DELAY_VALUE(IFD_DELAY_SYS_WOE))
i_ce1 (.I(ce1), .O(ice1));
ipadql #(
.IOSTANDARD (IOSTANDARD_SYS),
.IBUF_DELAY(IBUF_DELAY_SYS_WOE),
.IFD_DELAY(IFD_DELAY_SYS_WOE))
i_we (.g(cwr),.q(iwe),.qr(irnw),.d(we));
// negative pulse - with CE (zero w.s.) - only with WE, with CE1 (EW=1) - both WE and OE
BUFG i_cwr (.I((ice | iwe) & (ice1 | (iwe & ioe))), .O(cwr));
wire [12:0] ao=13'b0;
always @ (negedge clk) begin
// wr_state[2:0] <= {wr_state[1:0], (~wr_state[0] & ~ sync_cwr_on & seq_rq) | sync2};
wr_state[1:0] <= {wr_state[0], (~wr_state[0] & ~ sync_cwr_on & seq_rq) | sync2};
seq_ack <= ~wr_state[0] & ~(sync_cwr_on | sync2) & seq_rq;
if (sync2) a_pio_seq_mux[7:0] <= ia0[7:0];
else a_pio_seq_mux[7:0] <= seq_a[7:0];
wnr_seq_mux <= !sync2 || !irnw0; // sequencer - write only
if (sync2) d_pio_seq_mux[31:0] <= id0[31:0];
else d_pio_seq_mux[31:0] <= {8'b0,seq_d[23:0]};
end
always @ (negedge clk) begin
if (wr_state[0]) as[7:0] <= a_pio_seq_mux[7:0];
if (wr_state[0]) wnr <= wnr_seq_mux;
wra <= wr_state[0] && wnr_seq_mux;
if (wr_state[0]) idi[31:16] <= d_pio_seq_mux[31:16];
if (wr_state[0]) idi[15: 0] <= d_pio_seq_mux[15:0];
else if (wr_state[1]) idi[15: 0] <= idi[31:16];
end
// these signals will be valid after the end of the CPU r/w cycle
always @ (posedge cwr) begin
ia0[7:0] <= ial[7:0];
irnw0 <= irnw;
da_hist_next0 <= irnw && (ial[7:0]==8'h45); // read from 0x45 (ASAP, no sequencer!)
// da_imu_read0 <= irnw && (ial[7:1]==7'h3f); // 0x7e..0x7f, read
// da_imu_next0 <= irnw && (ial[7:0]==8'h7e); // 0x7e, read
dcmrst <= !irnw && (ial[7:0]==8'h1b); // 0x1b async signal to restart DCMs
da_pio_dmafifo0 <= irnw && (ial[7:1]==7'h0); // 0x0..0x01, read
end
always @ (negedge clk) begin
da_hist_next <= sync2 && da_hist_next0; // ASAP, no sequencer!
// da_imu_read <= sync2 && da_imu_read0; // 0x7e..0x7f, read
// da_imu_next <= sync2 && da_imu_next0; // 0x7e, read
da_pio_dmafifo <= sync2 && da_pio_dmafifo0;
ta[11:0] <= pre_ta[11:0];
end
always @ (negedge clk) begin
da_ctl_h <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h00); // 0x00 WE to control 32-bit register (1 loc)
da_dmamode <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h01); // 0x01 select writing to dma_cntr/dma_raw (1 loc)
da_sensormode <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h02); // 0x02 select writing to sensorpix (1 loc)
da_virttrig <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h03); // 0x03 write virtual trigger threshold
da_sensortrig <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h04); // 0x04 select writing to sensorpix (1 loc)
da_sensortrig_lines<= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h05); // 0x05 write number of lines to be transferred in a frame (or aftre trigger)
da_ctl <= wr_state[0] && wnr_seq_mux && ((a_pio_seq_mux[7:0]==8'h06) || (a_pio_seq_mux[7:0]==8'h00)); //0x00, 0x06
da_sens_dc <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h07); // 0x07 write to sensor DCDC converter frequency divider
da_dcm <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h08); // 0x08 tune SDRAM clock phase
da_saturation <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h09); // 0x09 write color saturation values
da_framesync_dly <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h0a); // 0x0a write frame sync interrupt delay (in scan lines)
da_quantizer_mode <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h0b); // 0x0b Quantizer tuning - 0..7 - zero bin, 15:8 - quantizer bias
da_compressor <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:1]==7'h06); // 0x0c..0x0d - will be farther decoded in the compressor module
da_table_a <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h0e); // 0x0e - write tables address
twr <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:0]==8'h0f); // 0x0f - write tables data
da_irq_smart <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h1a); // 0x1a single IRQ control
da_interrupts <= wr_state[0] && (a_pio_seq_mux[7:2]==6'h07); // 0x1c - 0x1f interrup control
da_dswe <= wr_state[0] && (a_pio_seq_mux[7:4]==4'h2 ); // 0x2x select reading/writing to mcontr (16 locations)
da_init_ch3 <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h2c); // 0x2c write to init cnhannel 3 (will reset address r/w)
da_next_ch3 <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h2f); // 0x2f advance to the next channel3 page, reset address
da_mem <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h30); // 0x30 read/write to SDRAM buffer, autoincrement address
da_lensff <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h31); // 0x31 lens flat field correction parameters (1 location, 8 bit address, 16bit - data)
twr_quant <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h0f) && (pre_ta[11: 9] ==3'h0); // 3'h0
twr_huff <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h0f) && (pre_ta[11: 9] ==3'h1); // 3'h1
twr_gamma <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h0f) && (pre_ta[11:10] ==2'h1); // 3'h2..3'h3
twr_focus <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h0f) && (pre_ta[11:10] ==2'h2); // 3'h4..3'h5
twr_coring <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h0f) && (pre_ta[11: 9] ==3'h6); // 3'h6 (3'h7 spare)
if (da_table_a) pre_ta[11:0]<= idi[11:0]; //d_pio_seq_mux[11:0];
else if (twr) pre_ta[11:0]<= pre_ta[11:0]+1;
da_hist <= wr_state[0] && (a_pio_seq_mux[7:3]==5'h08); // 0x40..0x47write/read histogram related data/registers
da_rtc <= wr_state[0] && (a_pio_seq_mux[7:2]==6'h12); // 0x48..0x4b
da_timestamp <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h4c); // 0x4c write timestamp mode
// da_dcr <= wr_state[0] && (a_pio_seq_mux[7:1]==7'h27); // 0x4e - 0x4f write to control registers, each bit/group with individual enable by data bit
// now da_dcr overlaps with 0x4c (timestamp mode), will be decoded in the control_regs module
da_dcr <= wr_state[0] && (a_pio_seq_mux[7:2]==6'h13); // 0x4c - 0x4f write to control registers, each bit/group with individual enable by data bit
da_i2c <= wr_state[0] && (a_pio_seq_mux[7:4]==4'h5); // 0x50 - 0x5f i2c_writeonly control
da_sequencer <= wr_state[0] && (a_pio_seq_mux[7:4]==4'h6); // 0x60 - 0x6f command sequencer
da_io_pins <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h70); // 0x70 write i/o pins control (for 6 pins to connector J2) - 0x70
da_xjtag <= wr_state[0] && (a_pio_seq_mux[7:0]==8'h74); // 0x74 write to external (sensor board) JTAG
da_extsync <= wr_state[0] && (a_pio_seq_mux[7:2]==6'h1e); // 0x78 - 0x7b control of external sync module
// TODO: add "wnr_seq_mux &&" where appropriate, otherwise pulse is generated on read with CE1 ! *****************
da_extio <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:1]==7'h3e); // external I/O (motor control 0x7c-0x7d)
da_imu <= wr_state[0] && wnr_seq_mux && (a_pio_seq_mux[7:1]==7'h3f); // IMU control (0x7e-0x7f)
end
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a0 (.g(cwr),.q(ia[ 0]),.qr(ial[ 0]),.io(a[ 0]),.t(!drv_bus),.d(ao[ 0]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a1 (.g(cwr),.q(ia[ 1]),.qr(ial[ 1]),.io(a[ 1]),.t(!drv_bus),.d(ao[ 1]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a2 (.g(cwr),.q(ia[ 2]),.qr(ial[ 2]),.io(a[ 2]),.t(!drv_bus),.d(ao[ 2]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a3 (.g(cwr),.q(ia[ 3]),.qr(ial[ 3]),.io(a[ 3]),.t(!drv_bus),.d(ao[ 3]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a4 (.g(cwr),.q(ia[ 4]),.qr(ial[ 4]),.io(a[ 4]),.t(!drv_bus),.d(ao[ 4]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a5 (.g(cwr),.q(ia[ 5]),.qr(ial[ 5]),.io(a[ 5]),.t(!drv_bus),.d(ao[ 5]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a6 (.g(cwr),.q(ia[ 6]),.qr(ial[ 6]),.io(a[ 6]),.t(!drv_bus),.d(ao[ 6]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a7 (.g(cwr),.q(ia[ 7]),.qr(ial[ 7]),.io(a[ 7]),.t(!drv_bus),.d(ao[ 7]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a8 (.g(cwr),.q(), .qr(), .io(a[ 8]),.t(!drv_bus),.d(ao[ 8]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a9 (.g(cwr),.q(), .qr(), .io(a[ 9]),.t(!drv_bus),.d(ao[ 9]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a10(.g(cwr),.q(), .qr(), .io(a[10]),.t(!drv_bus),.d(ao[10]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a11(.g(cwr),.q(), .qr(), .io(a[11]),.t(!drv_bus),.d(ao[11]));
bpadql #(.IOSTANDARD (IOSTANDARD_SYS),.SLEW(SLEW_SYS),.DRIVE(DRIVE_SYS),.IBUF_DELAY(IBUF_DELAY_SYS_A),.IFD_DELAY(IFD_DELAY_SYS_A))
i_a12(.g(cwr),.q(), .qr(), .io(a[12]),.t(!drv_bus),.d(ao[12]));
// inter-clock synchronization
FDCE i_sync0 (.Q(sync0), .C(cwr),.CE(1'b1),.CLR(sync2),.D(1'b1));
FD_1 i_sync1 (.Q(sync1), .C(clk),.D(sync0 && ! sync1));
FD i_sync2 (.Q(sync2), .C(clk),.D(sync1));
FDCE_1 i_sync_cwr_start0 (.Q(sync_cwr_start0),.C(cwr),.CE(1'b1),.CLR(sync_cwr_start2),.D(1'b1));
FD_1 i_sync_cwr_start1 (.Q(sync_cwr_start1),.C(clk),.D(sync_cwr_start0 && ! sync_cwr_start1));
FD i_sync_cwr_start2 (.Q(sync_cwr_start2),.C(clk),.D(sync_cwr_start1));
FD i_sync_cwr_on (.Q(sync_cwr_on), .C(clk),.D(sync_cwr_start1 || (sync_cwr_on && !sync1)));
LUT4 #(.INIT(16'hAA80)) i_dataouten ( .I0(1'b1), .I1(ice1), .I2(ice), .I3(ioe), .O(t));
dpads32 #(
.IOSTANDARD (IOSTANDARD_SYS),
.SLEW (SLEW_SYS),
.DRIVE (DRIVE_SYS),
.IBUF_DELAY (IBUF_DELAY_SYS_D),
.IFD_DELAY (IFD_DELAY_SYS_D))
i_dmapads32(.c(cwr),.t(t),.d(iod[31:0]),.q(id0[31:0]),.dq(d[31:0]));
endmodule
module dpads32 #(
parameter IOSTANDARD = "LVCMOS33",
parameter SLEW = "SLOW",
parameter DRIVE = 8,
parameter IBUF_DELAY = "0",
parameter IFD_DELAY = "0"
) (c,t,d,q,dq);
input c,t;
input [31:0] d;
output [31:0] q;
inout [31:0] dq;
wire t0, t1;
// s---ynthesis attribute KEEP_HIERARCHY of i_t0 is true
// s---ynthesis attribute KEEP_HIERARCHY of i_t1 is true
BUF i_t0 (.I(t), .O(t0));
BUF i_t1 (.I(t), .O(t1));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d0 (.c(c),.t(t0),.d(d[ 0]),.q(q[ 0]),.dq(dq[ 0]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d1 (.c(c),.t(t0),.d(d[ 1]),.q(q[ 1]),.dq(dq[ 1]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d2 (.c(c),.t(t0),.d(d[ 2]),.q(q[ 2]),.dq(dq[ 2]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d3 (.c(c),.t(t0),.d(d[ 3]),.q(q[ 3]),.dq(dq[ 3]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d4 (.c(c),.t(t0),.d(d[ 4]),.q(q[ 4]),.dq(dq[ 4]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d5 (.c(c),.t(t0),.d(d[ 5]),.q(q[ 5]),.dq(dq[ 5]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d6 (.c(c),.t(t0),.d(d[ 6]),.q(q[ 6]),.dq(dq[ 6]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d7 (.c(c),.t(t0),.d(d[ 7]),.q(q[ 7]),.dq(dq[ 7]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d8 (.c(c),.t(t0),.d(d[ 8]),.q(q[ 8]),.dq(dq[ 8]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d9 (.c(c),.t(t0),.d(d[ 9]),.q(q[ 9]),.dq(dq[ 9]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d10 (.c(c),.t(t1),.d(d[10]),.q(q[10]),.dq(dq[10]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d11 (.c(c),.t(t1),.d(d[11]),.q(q[11]),.dq(dq[11]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d12 (.c(c),.t(t1),.d(d[12]),.q(q[12]),.dq(dq[12]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d13 (.c(c),.t(t1),.d(d[13]),.q(q[13]),.dq(dq[13]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d14 (.c(c),.t(t1),.d(d[14]),.q(q[14]),.dq(dq[14]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d15 (.c(c),.t(t1),.d(d[15]),.q(q[15]),.dq(dq[15]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d16 (.c(c),.t(t1),.d(d[16]),.q(q[16]),.dq(dq[16]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d17 (.c(c),.t(t0),.d(d[17]),.q(q[17]),.dq(dq[17]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d18 (.c(c),.t(t1),.d(d[18]),.q(q[18]),.dq(dq[18]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d19 (.c(c),.t(t1),.d(d[19]),.q(q[19]),.dq(dq[19]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d20 (.c(c),.t(t1),.d(d[20]),.q(q[20]),.dq(dq[20]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d21 (.c(c),.t(t1),.d(d[21]),.q(q[21]),.dq(dq[21]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d22 (.c(c),.t(t0),.d(d[22]),.q(q[22]),.dq(dq[22]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d23 (.c(c),.t(t1),.d(d[23]),.q(q[23]),.dq(dq[23]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d24 (.c(c),.t(t0),.d(d[24]),.q(q[24]),.dq(dq[24]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d25 (.c(c),.t(t1),.d(d[25]),.q(q[25]),.dq(dq[25]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d26 (.c(c),.t(t0),.d(d[26]),.q(q[26]),.dq(dq[26]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d27 (.c(c),.t(t0),.d(d[27]),.q(q[27]),.dq(dq[27]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d28 (.c(c),.t(t0),.d(d[28]),.q(q[28]),.dq(dq[28]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d29 (.c(c),.t(t0),.d(d[29]),.q(q[29]),.dq(dq[29]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d30 (.c(c),.t(t1),.d(d[30]),.q(q[30]),.dq(dq[30]));
dio1 #(.IOSTANDARD (IOSTANDARD),.SLEW(SLEW),.DRIVE(DRIVE),.IBUF_DELAY(IBUF_DELAY),.IFD_DELAY(IFD_DELAY))
i_d31 (.c(c),.t(t1),.d(d[31]),.q(q[31]),.dq(dq[31]));
endmodule
module sddrio16 #(
parameter IOSTANDARD = "SSTL2_I",
parameter DRIVE = 12,
parameter SLEW = "SLOW"
)(c0,c270,d,t,q,dq); //added an extra FF for the t signal
input c0,c270;
input [31:0] d;
input t;
output [31:0] q;
inout [15:0] dq;
wire [31:0] q;
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq0 (.c0(c0),.c270(c270),.d({d[16],d[ 0]}),.t(t),.q({q[16],q[ 0]}),.dq(dq[ 0]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq1 (.c0(c0),.c270(c270),.d({d[17],d[ 1]}),.t(t),.q({q[17],q[ 1]}),.dq(dq[ 1]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq2 (.c0(c0),.c270(c270),.d({d[18],d[ 2]}),.t(t),.q({q[18],q[ 2]}),.dq(dq[ 2]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq3 (.c0(c0),.c270(c270),.d({d[19],d[ 3]}),.t(t),.q({q[19],q[ 3]}),.dq(dq[ 3]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq4 (.c0(c0),.c270(c270),.d({d[20],d[ 4]}),.t(t),.q({q[20],q[ 4]}),.dq(dq[ 4]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq5 (.c0(c0),.c270(c270),.d({d[21],d[ 5]}),.t(t),.q({q[21],q[ 5]}),.dq(dq[ 5]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq6 (.c0(c0),.c270(c270),.d({d[22],d[ 6]}),.t(t),.q({q[22],q[ 6]}),.dq(dq[ 6]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq7 (.c0(c0),.c270(c270),.d({d[23],d[ 7]}),.t(t),.q({q[23],q[ 7]}),.dq(dq[ 7]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq8 (.c0(c0),.c270(c270),.d({d[24],d[ 8]}),.t(t),.q({q[24],q[ 8]}),.dq(dq[ 8]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq9 (.c0(c0),.c270(c270),.d({d[25],d[ 9]}),.t(t),.q({q[25],q[ 9]}),.dq(dq[ 9]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq10 (.c0(c0),.c270(c270),.d({d[26],d[10]}),.t(t),.q({q[26],q[10]}),.dq(dq[10]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq11 (.c0(c0),.c270(c270),.d({d[27],d[11]}),.t(t),.q({q[27],q[11]}),.dq(dq[11]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq12 (.c0(c0),.c270(c270),.d({d[28],d[12]}),.t(t),.q({q[28],q[12]}),.dq(dq[12]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq13 (.c0(c0),.c270(c270),.d({d[29],d[13]}),.t(t),.q({q[29],q[13]}),.dq(dq[13]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq14 (.c0(c0),.c270(c270),.d({d[30],d[14]}),.t(t),.q({q[30],q[14]}),.dq(dq[14]));
sddrio0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq15 (.c0(c0),.c270(c270),.d({d[31],d[15]}),.t(t),.q({q[31],q[15]}),.dq(dq[15]));
endmodule
// Made for CL=2.5
// all data to write is expected to be sync to posedge of c0 - phase=0,
// data to sdram is clocked at c270 (LSW) and c90 (MSW)
// MSB will be delayed by half-cycle internally
// tristate will be clocked at rising edge of c270
// All data read will be also sync to rising edge of c0 (LSB will be delayed internally)
module sddrio0 #(
parameter IOSTANDARD = "SSTL2_I",
parameter DRIVE = 12,
parameter SLEW = "SLOW"
)(c0,/*c90,*/c270,d,t,q,dq); // made for CL=2.5, LSB first - c0 falling edge is before rising, gets LSB
input c0,/*c90,*/c270;
input [1:0] d;
input t;
output [1:0] q;
inout dq;
wire dr,t0,t1,tr,qp,q00,d1d;
wire [1:0] d0;
FD i_d00 (.C(c0), .D(d[0]), .Q(d0[0])); //regular FF, not IOB
FD i_d01 (.C(c0), .D(d[1]), .Q(d0[1])); //regular FF, not IOB
FD i_d1d (.C(c270),.D(d0[1]),.Q(d1d)); //regular FF, not IOB
FD_1 i_q0 (.C(c0),.D(q00),.Q(q[0])); //regular FF, not IOB
IOBUF #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq (.I(dr), .T(tr),.O(qp), .IO(dq));
FDDRCPE i_dr (.Q(dr),.C0(c270),.C1(!c270),.D0(d0[0]),.D1(d1d),.CE(1'b1),.CLR(1'b0),.PRE(1'b0));
FD_1 #(.INIT(1'b1)) i_t0 (.C(c0), .D(t), .Q(t0));
FD #(.INIT(1'b1)) i_t1 (.C(c0), .D(t0), .Q(t1));
FD #(.INIT(1'b1)) i_tr (.C(c270), .D(t1), .Q(tr));
IDDR2 i_qq(.Q0(q00),.Q1(q[1]),.C0(c0),.C1(!c0),.CE(1'b1), .D(qp), .R(1'b0), .S(1'b0) );
// synthesis attribute IOB of i_dr is "TRUE"
// synthesis attribute IOB of i_tr is "TRUE"
// synthesis attribute NODELAY of i_dq is "TRUE"
endmodule
module dqs2 #(
parameter IOSTANDARD = "SSTL2_I",
parameter DRIVE = 12,
parameter SLEW = "SLOW"
)(c0,/*c90,*/c270,
t, // 1.5 cycles before cmd "write" sent out to the SDRAM, sync to sclk180
UDQS, // UDQS I/O pin
LDQS, // LDQS I/O pin
udqsr90, // data from SDRAM interface pin UDQS strobed at rising sclk90
ldqsr90, // data from SDRAM interface pin LDQS strobed at rising sclk90
udqsr270, // data from SDRAM interface pin UDQS strobed at rising sclk270
ldqsr270 // data from SDRAM interface pin UDQS strobed at rising sclk270
);
input c0,/*c90,*/c270,t;
inout UDQS, LDQS;
output udqsr90,ldqsr90,udqsr270,ldqsr270;
wire t0,t1,tr;
///AF: wire t2;
FD_1 #(.INIT(1'b1)) i_t0 (.C(c0),.D(t),.Q(t0));
FD #(.INIT(1'b1)) i_t1 (.C(c0),.D(t0),.Q(t1));
///AF: FD #(.INIT(1'b1)) i_t2 (.C(c270),.D(t0),.Q(t2));
assign tr= t1;
dqs2_0 #(.IOSTANDARD(IOSTANDARD),
.DRIVE(DRIVE),
.SLEW(SLEW))
i_dqsu(.c0(c0),/*.c90(c90),*/.c270(c270),.t(tr),.q({udqsr270,udqsr90}),.dq(UDQS));
dqs2_0 #(.IOSTANDARD(IOSTANDARD),
.DRIVE(DRIVE),
.SLEW(SLEW))
i_dqsl(.c0(c0),/*.c90(c90),*/.c270(c270),.t(tr),.q({ldqsr270,ldqsr90}),.dq(LDQS));
endmodule
module dqs2_0#(
parameter IOSTANDARD = "SSTL2_I",
parameter DRIVE = 12,
parameter SLEW = "SLOW"
) (c0,/*c90,*/c270,t,q,dq);
input c0,/*c90,*/c270;
input t;
output [1:0] q;
inout dq;
wire qp;
wire virtc0; // sync to c0
IOBUF #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq (.I(virtc0), .T(t),.O(qp), .IO(dq));
// reset DQS when tristated
FDDRCPE i_dr (.Q(virtc0),.C0(c0),.C1(!c0),.D0(1'b1),.D1(1'b0),.CE(1'b1),.CLR(t),.PRE(1'b0));
// as in IFDDRCPE.v
FDCPE_1 #(.INIT(1'b0)) i_q0 (.C(c270), .CE(1'b1),.CLR(1'b0),.D(qp),.PRE(1'b0),.Q(q[0]));
FDCPE i_q1 (.C(c270),.CE(1'b1),.CLR(1'b0),.D(qp),.PRE(1'b0),.Q(q[1]));
// synthesis attribute IOB of i_q0 is "TRUE"
// synthesis attribute IOB of i_q1 is "TRUE"
// synthesis attribute FAST of i_dq is "TRUE"
// synthesis attribute NODELAY of i_dq is "TRUE"
endmodule
//both bits are strobed at rising c270
module sddrdm #(
parameter IOSTANDARD = "SSTL2_I",
parameter DRIVE = 12,
parameter SLEW = "SLOW"
) (c0,c270,d,dq);
input c0,c270;
input [1:0] d;
inout dq; //SuppressThisWarning Veditor UNUSED
sddrdm0 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq (.c0(c0),.c270(c270),.d(d),.dq(dq));
endmodule
module sddrdm0 #(
parameter IOSTANDARD = "SSTL2_I",
parameter DRIVE = 12,
parameter SLEW = "SLOW"
) (c0,c270,d,dq);
input c0,c270;
input [1:0] d;
output dq;
wire dr,d1d;
wire [1:0] d0;
OBUF #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_dq (.I(dr), .O(dq));
// FDDRCPE i_dr (.Q(dr),.C0(c270),.C1(c90),.D0(d0[0]),.D1(d1d),.CE(1'b1),.CLR(1'b0),.PRE(1'b0));
FDDRCPE i_dr (.Q(dr),.C0(c270),.C1(!c270),.D0(d0[0]),.D1(d1d),.CE(1'b1),.CLR(1'b0),.PRE(1'b0));
FD i_d00(.C(c0),.D(d[0]),.Q(d0[0])); //regular FF, not IOB
FD i_d01(.C(c0),.D(d[1]),.Q(d0[1])); //regular FF, not IOB
FD i_d1d(.C(c270),.D(d0[1]),.Q(d1d)); //regular FF, not IOB
// synthesis attribute IOB of i_dr is "TRUE"
// synthesis attribute NODELAY of i_dq is "TRUE"
endmodule
// SDRAM address and ras/cas/we
module sdo15_2#(
parameter IOSTANDARD = "SSTL2_I",
parameter DRIVE = 12,
parameter SLEW = "SLOW"
)(c,d,q); // inputs at rising edge, resyncs to falling edge, all go high at reset
input c;
input [14:0] d;
output [14:0] q;
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q0 (.c(c),.d(d[ 0]),.q(q[ 0]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q1 (.c(c),.d(d[ 1]),.q(q[ 1]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q2 (.c(c),.d(d[ 2]),.q(q[ 2]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q3 (.c(c),.d(d[ 3]),.q(q[ 3]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q4 (.c(c),.d(d[ 4]),.q(q[ 4]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q5 (.c(c),.d(d[ 5]),.q(q[ 5]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q6 (.c(c),.d(d[ 6]),.q(q[ 6]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q7 (.c(c),.d(d[ 7]),.q(q[ 7]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q8 (.c(c),.d(d[ 8]),.q(q[ 8]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q9 (.c(c),.d(d[ 9]),.q(q[ 9]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q10 (.c(c),.d(d[10]),.q(q[10]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q11 (.c(c),.d(d[11]),.q(q[11]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q12 (.c(c),.d(d[12]),.q(q[12]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q13 (.c(c),.d(d[13]),.q(q[13]));
sdo1_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW))
i_q14 (.c(c),.d(d[14]),.q(q[14]));
endmodule
module sdo1_2#(
parameter IOSTANDARD = "SSTL2_I",
parameter DRIVE = 12,
parameter SLEW = "SLOW"
)(c,d,q); // input at rising edge, resyncs to falling
input c;
input d;
output q;
sdo0_2 #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_q (.c(c),.d(d),.q(q));
// s--ynthesis attribute KEEP_HIERARCHY of i_q is "TRUE"
endmodule
module sdo0_2 #(
parameter IOSTANDARD = "SSTL2_I",
parameter DRIVE = 12,
parameter SLEW = "SLOW"
)(c,d,q); // input at rising edge, resyncs to falling, initializes to "1"
input c;
input d;
output q;
wire d0, dr;
OBUF #(.IOSTANDARD(IOSTANDARD), .DRIVE(DRIVE), .SLEW(SLEW)) i_q (.I(dr), .O(q));
FD #(.INIT(1'b1)) i_d0 (.C(c), .D(d), .Q(d0));
//FD_1 i_dr (.C(c), .D(d), .Q(dr));
FD_1 #(.INIT(1'b1)) i_dr (.C(c), .D(d0), .Q(dr));
// synthesis attribute IOB of i_dr is "TRUE"
endmodule
module ipadql#(
parameter IOSTANDARD = "LVCMOS33",
parameter IBUF_DELAY = "0",
parameter IFD_DELAY = "0"
)(g,q,qr,d); //
input g;
output q;
output qr;
input d;
ipadql0 #(
.IOSTANDARD (IOSTANDARD),
.IBUF_DELAY (IBUF_DELAY),
.IFD_DELAY (IFD_DELAY))
i_q (.g(g),.q(q),.qr(qr),.d(d));
// s--ynthesis attribute KEEP_HIERARCHY of i_q is "TRUE"
endmodule
module ipadql0#(
parameter IOSTANDARD = "LVCMOS33",
parameter IBUF_DELAY = "0",
parameter IFD_DELAY = "0"
)(g,q,qr,d);
input g;
output q;
output qr;
input d;
IBUF #(
.IOSTANDARD (IOSTANDARD),
.IBUF_DELAY_VALUE (IBUF_DELAY),
.IFD_DELAY_VALUE (IFD_DELAY))
i_q (.I(d), .O(q));
LD i_qr (.G(g), .D(q), .Q(qr));
// synthesis attribute IOB of i_qr is "TRUE"
// synthesis attribute NODELAY of i_q is "TRUE"
endmodule
module bpadql#(
parameter IOSTANDARD = "LVCMOS33",
parameter SLEW = "SLOW",
parameter DRIVE = 8,
parameter IBUF_DELAY = "0",
parameter IFD_DELAY = "0"
)(g,q,qr,io,t,d); //
input g;
output q;
output qr;
inout io;
input t;
input d;
bpadql0 #(
.IOSTANDARD (IOSTANDARD),
.SLEW (SLEW),
.DRIVE (DRIVE),
.IBUF_DELAY (IBUF_DELAY),
.IFD_DELAY (IFD_DELAY)
)i_q (.g(g),.q(q),.qr(qr),.io(io),.t(t),.d(d));
endmodule
module bpadql0#(
parameter IOSTANDARD = "LVCMOS33",
parameter SLEW = "SLOW",
parameter DRIVE = 8,
parameter IBUF_DELAY = "0",
parameter IFD_DELAY = "0"
)(g,q,qr,io,t,d);
input g;
output q;
output qr;
inout io;
input t;
input d;
IOBUF #(
.IOSTANDARD (IOSTANDARD),
.SLEW (SLEW),
.DRIVE (DRIVE),
.IBUF_DELAY_VALUE (IBUF_DELAY),
.IFD_DELAY_VALUE (IFD_DELAY)
) i_q (.I(d), .T(t),.O(q), .IO(io));
LD i_qr (.G(g), .D(q), .Q(qr));
// synthesis attribute IOB of i_qr is "TRUE"
endmodule
module dio1 #(
parameter IOSTANDARD = "LVCMOS33",
parameter SLEW = "SLOW",
parameter DRIVE = 8,
parameter IBUF_DELAY = "0",
parameter IFD_DELAY = "0"
)(c,t,d,q,dq);
input c;
input t;
input d;
output q;
inout dq;
dio0 #(
.IOSTANDARD (IOSTANDARD),
.SLEW (SLEW),
.DRIVE (DRIVE),
.IBUF_DELAY (IBUF_DELAY),
.IFD_DELAY (IFD_DELAY)
) i_dq (.c(c),.t(t),.d(d),.q(q),.dq(dq));
// s--ynthesis attribute KEEP_HIERARCHY of i_dq is "TRUE"
endmodule
module dio0 #(
parameter IOSTANDARD = "LVCMOS33",
parameter SLEW = "SLOW",
parameter DRIVE = 8,
parameter IBUF_DELAY = "0",
parameter IFD_DELAY = "0"
)(c,t,d,q,dq);
input c;
input t;
input d;
output q;
inout dq;
wire q0;
IOBUF #(
.IOSTANDARD (IOSTANDARD),
.SLEW (SLEW),
.DRIVE (DRIVE),
.IBUF_DELAY_VALUE (IBUF_DELAY),
.IFD_DELAY_VALUE (IFD_DELAY)
) i_dq (.I(d), .T(t),.O(q0), .IO(dq));
FD i_q (.C(c), .D(q0), .Q(q));
// synthesis attribute IOB of i_q is "TRUE"
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/irq_smart.v 0000664 0000000 0000000 00000012415 12555570767 0023123 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** irq_smart.v
**
** making a simgle interrupt that combines frame sync and compressor done
** waiting for the latest of the 2
**
** Copyright (C) 2008-2010 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.wpage0_inc
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
// control bits:
// [1:0] : 3 - enable waiting for frame sync if compressor done comes earlier
// 2 - disable waiting F.S. (should be disabled for single-frame acquisitions where no frame sync will follow the first frame)
// 1, 0 - don't change F.S. waiting
// [3:2] : 3 - wait for DMA FIFO to be transferred to the system before generating interrupt
// 2 - don't wait for the DMA FIFO to be emptied
// 1, 0 - don't change DMA FIFO waiting
// [15] ; reset requests (mostly fro simulation
// NOTE: now if wait_fs is off, IRQ will be on either FS or done (may be twice)
module irq_smart (sclk, // @negedge
wen, // sync to address and d[0:15]
di, // [15:0] data in, only [3:0] are currently used
frame_sync, // frame sync, single pulse @ negedge sclk
is_compressing, // @posedge clk, needs re-sync
compressor_done, // single pulse @ negedge sclk - compressor finished (some data is still in DMA FIFO)
fifo_empty, // DMA FIFO empty (no gaps between compressor_done and !fifo_empty)
irq); // single cycle $ negedge sclk output to be used as IRQ source
input sclk;
input wen;
input [15:0] di;
input frame_sync; // frame sync, single pulse @ negedge sclk
input is_compressing; // @posedge clk, needs re-sync
input compressor_done; // single pulse @ negedge sclk - compressor finished (some data is still in DMA FIFO)
input fifo_empty; // DMA FIFO empty (no gaps between compressor_done and !fifo_empty)
output irq; // single cycle $ negedge sclk output to be used as IRQ source
reg [2:0] is_compressing_s;
reg is_finishing=0; /// no gap with is_compressing_s[2]
reg was_finishing;
// together they provide number of frames currently being processed (0/1/2)
reg wait_frame_sync;
reg wait_fifo;
reg compressor_fifo_done; // single cycle - compressor and and fifo done (next after done if !wait_fifo)
reg done_request = 0;
reg irq;
reg rst;
wire will_postpone_fs;
wire end_postpone_fs;
wire finished;
reg fs_postponed;
wire will_delay_done_irq;
reg delaying_done_irq;
assign will_postpone_fs=wait_frame_sync && (is_compressing_s[2] || is_finishing) ;
assign finished=was_finishing && ! is_finishing;
assign end_postpone_fs=finished || frame_sync;
assign will_delay_done_irq=wait_frame_sync && (finished && !fs_postponed);
always @ (negedge sclk) begin
//control interface
if (wen & di[1]) wait_frame_sync <= di[0];
if (wen & di[3]) wait_fifo <= di[2];
rst <=wen & di[15];
// process frame sync postponed - wait for the compression to finish if it was started during previous frame
fs_postponed <= !rst && ((will_postpone_fs && frame_sync) || (fs_postponed && !end_postpone_fs));
delaying_done_irq <= !rst && (will_delay_done_irq || (delaying_done_irq && !frame_sync));
is_compressing_s[2:0]<={is_compressing_s[1:0],is_compressing} ; // re-sync from posedge xclk to negedge clk
done_request <= !rst && (compressor_done || (done_request && !compressor_fifo_done));
compressor_fifo_done <= done_request && (!wait_fifo || fifo_empty) && !compressor_fifo_done;
is_finishing <= !rst && ((is_compressing_s[2] && !is_compressing_s[1]) ||
(is_finishing && !compressor_fifo_done));
was_finishing <= is_finishing;
irq <= !rst && ((frame_sync && (!will_postpone_fs || delaying_done_irq)) ||
(fs_postponed && end_postpone_fs) || // will include frame_sync if compression did not finish
(!will_delay_done_irq && finished));
end
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/rtc353.v 0000664 0000000 0000000 00000026420 12555570767 0022146 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** rtc353.v
**
** Real time clock, counts seconds (32 bit), microseconds (20 bits)
** allows fine adjustment (0.1 ppm to =/- 0.3%), used in timestamping images.
**
** Copyright (C) 2005-2007 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
module rtc353 (mclk, // system clock (negedge)
pre_we, // 1 cycle ahead of writing data
wa, // [1:0] write address
// 0 - write microseconds (actual write will happen after writing seconds)
// 1 - write seconds
// 2 - write correction (16 bit, signed
// 3 - nop, just latch the output 32+20 bits to read to CPU). Maybe nop (or 2 writes) are needed between read.
wd, // [31:0] data to write, valid 1 cycle after pre_we, wa
musec, // [19:0] usec output (register is latched by writing), 0..999999 (0..0xf423f)
msec, // [31:0] seconds latched counter output
clk12, // 12MHz clock (no PLL, just xtall). will be re-synchronized to mclk to avoid extra GCLK
pclk, // sensor clock (posedge)
platch, // latch counters sync to pclk (up to ~0.5usec delay. Start of first HACT after VACT?
pusec, // [19:0] usec output - sync to sensor clock
psec, // [31:0] seconds counter output
usec, // running usec data out
sec); // running sec data out
// counter is updated each 0.5 (non-compensated) microsecond. Usually counters are incremented each other upd pulse, but an interval
// may be 1 or 3 upd periods (0.5/1.5 usec)
input mclk;
input pre_we;
input [ 1:0] wa;
input [15:0] wd;
output [19:0] musec;
output [31:0] msec;
input clk12;
input pclk;
input platch;
output [19:0] pusec;
output [31:0] psec;
output [19:0] usec;
output [31:0] sec;
reg we_usec;
// reg [ 1:0] we_sec;
reg we_sec;
reg set_cntr;
reg we_corr;
reg [19:0] wusec;
reg [31:0] wsec;
reg [15:0] corr;
reg [19:0] usec;
reg [31:0] sec;
reg [19:0] usec_plus1;
reg [31:0] sec_plus1;
reg [19:0] musec;
reg [31:0] msec;
reg [19:0] pusec;
reg [31:0] psec;
reg [ 2:0] clk12_d; // make a clean 12MHz clock sync to system clock
reg [ 2:0] clk12_s; // make a clean 12MHz clock sync to system clock
reg [ 2:0] cntr6; // divide by 6 (12MHz->2MHz)
reg pend_set_cntr; //ending set_cntr (will be synchronized)
reg [3:0] halfusec;
reg [1:0] inc_usec; // 2 bits - to reduce FO problems
reg [1:0] inc_sec;
reg [23:0] acc;
wire [24:0] next_acc;
reg [2:0] usec_lsb; // usec LSB sampled @posedge pclk, delayed
reg platch_sample; // sample TS until usec LSB does not change (before and after
reg platch_test; // see if need to re_sample;
wire enable_rtc; // for simulation
reg [15:0] wd_r; // delayed data in (low bits)
wire [31:0] wdd={wd[15:0],wd_r[15:0]};
assign next_acc[24:0]= {1'b0,acc[23:0]} + {1'b0,~corr [15], {7{corr [15]}}, corr[15:0]};
always @ (posedge pclk) begin
usec_lsb[2:0] <= {usec_lsb[1:0],usec[0]};
platch_sample <= platch || (platch_test && ((usec_lsb[1]!=usec_lsb[0]) ||(usec_lsb[2]!=usec_lsb[0])));
platch_test<=platch_sample;
if (platch_sample) begin
pusec[19:0] <= usec[19:0];
psec [31:0] <= sec [31:0];
end
end
// FDE_1 i_enable_rtc (.C(mclk),.CE(we_sec[0]),.D(1'b1),.Q(enable_rtc));
FDE_1 i_enable_rtc (.C(mclk),.CE(we_sec),.D(1'b1),.Q(enable_rtc));
always @ (negedge mclk) begin
wd_r[15:0] <= wd[15:0];
clk12_d[2:0] <= {clk12_d[1:0], clk12};
clk12_s[2:0] <= {clk12_s[1] && !clk12_s[0], clk12_s[0], (clk12_d[2:1]==2'h3) || (clk12_s[0] && !(clk12_d[2:1]==2'h0))};
we_usec <= (wa[1:0]==2'h0) && pre_we;
// we_sec[1:0] <= {we_sec[0],(wa[1:0]==2'h1) && pre_we};
we_sec <= (wa[1:0]==2'h1) && pre_we;
// if (we_sec[0]) pend_set_cntr <= 1'b1;
if (we_sec) pend_set_cntr <= 1'b1;
else if (halfusec[3])pend_set_cntr <= 1'b0;
if (!enable_rtc) set_cntr <= 1'b0;
else if (halfusec[3]) set_cntr <= pend_set_cntr;
we_corr <= (wa[1:0]==2'h2) && pre_we;
if (pre_we) begin
musec[19:0] <= usec[19:0];
msec [31:0] <= sec [31:0];
end
if (we_usec) wusec[19:0] <= wdd[19:0];
// if (we_sec[0]) wsec [31:0] <= wdd[31:0];
if (we_sec) wsec [31:0] <= wdd[31:0];
if (we_corr) corr [15:0] <= wdd[15:0];
if (!enable_rtc) cntr6[2:0] <= 3'h5;
else if (clk12_s[2]) cntr6[2:0] <= (cntr6[2:0]==3'h0)?3'h5:(cntr6[2:0] - 1);
halfusec[3:0] <= {halfusec[2:0],clk12_s[2] && (cntr6[2:0]==3'h0)};
if (halfusec[1]) acc[23:0] <= set_cntr?24'h0:next_acc[23:0];
inc_usec[1:0] <= {inc_usec[0],halfusec[1] & next_acc[24]};
inc_sec [1:0] <= {inc_sec[0], halfusec[1] && next_acc[24] && (usec[19:0]==20'hf423f)};
// reducing delay from set_cntr to sec[]. usec[] - don't know how to constraint it really, so adding layer of registers
sec_plus1[31:0] <= sec[31:0] + 1;
usec_plus1[19:0] <= usec[19:0] + 1;
if (set_cntr) usec[19:0] <= wusec[19:0];
else if (inc_sec[1]) usec[19:0] <= 20'h0;
else if (inc_usec[1]) usec[19:0] <= usec_plus1[19:0];
if (set_cntr) sec[31:0] <= wsec[31:0];
else if (inc_sec[1]) sec[31:0] <= sec_plus1[31:0];
end
endmodule
module timestamp353( mclk, // system clock (negedge)
pre_we, // 1 cycle ahead of writing data
wd, // [1:0] data to write, valid 1 cycle after pre_we, wa
pclk, // pixel clock
pxdi, // [15:0] pixel data from sensor
pxdo, // [15:0] data to replace pxdi (next cycle)
vacts, // vertical sync
hacti, // hact input
hacto, // hact output (next cycle)
sec, // [31:0] number of seconds
usec, // [19:0] number of microseconds
tlatch); // latch time - 1-st hact after vact
input mclk;
input pre_we;
input [1:0] wd;
input pclk;
input [15:0] pxdi;
output [15:0] pxdo;
input vacts;
input hacti;
output hacto;
input [31:0] sec;
input [19:0] usec;
output tlatch;
wire ts_active;
reg [15:0] pxdo;
reg hacto;
wire ts_bit;
reg hact_d;
reg vact_pend;
reg odd_line;
// reg [ 3:0] line;
reg [ 2:0] line;
reg ts_line; // line when timestamp is active
reg tlatch;
wire start_ts;
reg pre_start_ts, start_ts_r; // only in normal mode
reg ts_continue;
reg [ 4:0] ts_count;
reg [25:0] ts_data;
reg wr_tsmode;
wire [1:0] tsmode; //[1:0] 0 - off, (pixels/lines below start from 0)
// 1 - 2rd and 3-th lines, from pixel 2 (normal mode, frame not increased)
// 2 - 0 and 1 lines, after pixel data (adds 28 pixels to each line:
// {seconds[31:6],2'b0} MSB first for line 0
// {seconds[5:0],useconds[19:0],2'b0} MSB first for line 1
//delaying ts_data, pxdo by 1 clock
reg [15:0] pxdi_r; // delayed pxdi
reg use_ts; // use timestamp data
reg ts_active_r;
reg ts_line_r;
reg [1:0] wdd;
assign ts_bit=ts_data[25];
assign start_ts = (tsmode[1] && !hacti && hact_d) || start_ts_r;
assign ts_active = ts_continue || start_ts;
FDE_1 i_tsmode_0 (.C(mclk),.CE(wr_tsmode),.D(wdd[0]),.Q(tsmode[0]));
FDE_1 i_tsmode_1 (.C(mclk),.CE(wr_tsmode),.D(wdd[1]),.Q(tsmode[1]));
always @ (negedge mclk) begin
wdd[1:0] <= wd[1:0];
wr_tsmode <= pre_we;
end
always @ (posedge pclk) begin
use_ts <= ts_active || (hact_d && !hacti);
pxdi_r[15:0] <= pxdi[15:0];
if (use_ts) pxdo[15:0] <= {16{ts_bit}};
else if (hact_d) pxdo[15:0] <= pxdi_r[15:0];
hact_d <= hacti;
hacto <= hacti || ts_active;
if (vacts) vact_pend <= 1'b1;
else if (hacti && !hact_d) vact_pend <= 1'b0;
if (hacti && !hact_d) odd_line <= !vact_pend && !odd_line;
// if (hacti && !hact_d) line[3:0] <= vact_pend?4'h1:{line[2:0],1'b0};
if (hacti && !hact_d) line[2:0] <= vact_pend ? 3'h1 : {line[1:0],1'b0};
if (hacti && !hact_d) ts_line <= tsmode[1]? (vact_pend || line[0] ) : (!vact_pend && (line[1] || line[2]));
tlatch <= vact_pend && hacti && !hact_d;
pre_start_ts <= (tsmode[1:0] == 2'h1) &&
hacti && !hact_d && !vact_pend && (line[1] || line[2]);// before line changes
start_ts_r <= pre_start_ts;
if (start_ts) ts_count[4:0] <= tsmode[1]?5'h1a:5'h18;
else if (ts_continue) ts_count[4:0] <= ts_count[4:0] - 1;
if (tsmode[1:0]==2'h0) ts_continue <= 1'b0;
else if (start_ts) ts_continue <= 1'b1;
else if (ts_count[4:0]==5'h0) ts_continue <= 1'b0;
// if (ts_active) ts_data[25:0]<= {ts_data[24:0],1'b0};
// else if (ts_line) ts_data[25:0]<= odd_line?sec[31:6]:{sec[5:0],usec[19:0]};
// else ts_data[25:0]<= 16'h0;
ts_active_r <= ts_active;
ts_line_r <= ts_line;
if (ts_active_r) ts_data[25:0] <= {ts_data[24:0],1'b0};
else if (ts_line_r) ts_data[25:0] <= odd_line?sec[31:6]:{sec[5:0],usec[19:0]};
else ts_data[25:0] <= 26'h0;
end
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/control/twelve_ios.v 0000664 0000000 0000000 00000017146 12555570767 0023310 0 ustar 00root root 0000000 0000000 /*
** -----------------------------------------------------------------------------**
** twelve_ios.v
**
** GPIO control
**
** Copyright (C) 2005-2007 Elphel, Inc
**
** -----------------------------------------------------------------------------**
** This file is part of X353
** X353 is free software - hardware description language (HDL) code.
**
** 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 .
** -----------------------------------------------------------------------------**
**
*/
// update to eliminate need for a shadow register
// each pair of data bits at write cycle control the data and enable in the following way:
// bit 1 bit 0 dibit enable data
// 0 0 0 - no change -
// 0 1 1 1 0
// 1 0 2 1 1
// 1 1 3 0 0
//Unified IO control for the 6 pins that are connected from the FPGA to the inter-board 16-pin connector
// those pins were controlled (in models 303, 313, 323 and earlier 333) by the control register, status was
// read through the status register.
// Now each pin will be controlled by 2 bits (data+enable), total 12 bits that will come from one of 4 sources
// selected by bits [13:12] of the new control word:
// 0 - use bits [11:0] of the control word
// 1 - use channel A (USB)?
// 2 - use channel B (tbd)
// 3 - use channel C (tbd)
// Updating logic
// global enable signals (disabled channel will not compete for per-biot access)
// next 4 enable signals are controlled by bit pairs (0X - don't change, 10 - disable, 11 - enable)
// bit [25:24] - enable software bits (contolled by bits [23:0] (on at powerup)
// bit [27:26] - enable chn. A
// bit [29:28] - enable chn. B
// bit [31:30] - enable chn. C
// Enabled bits will be priority encoded (C - highest, software - lowest)
module twelve_ios (sclk, // @negedge
pre_wen, // 1 cycle ahead of write data
di, // [15:0] data in
io_do, // [5:0] data to I/O pins
io_t, // [5:0] tristate I/O pins
da, // [5:0] data from port A (USB?)
da_en, // [5:0] data enable from port A (USB?)
db, // [5:0] data from port B
db_en, // [5:0] data enable from port B
dc, // [5:0] data from port C
dc_en); // [5:0] data enable from port C
input sclk;
input pre_wen;
input [15:0] di;
output [11:0] io_do;
output [11:0] io_t;
input [11:0] da;
input [11:0] da_en;
input [11:0] db;
input [11:0] db_en;
input [11:0] dc;
input [11:0] dc_en;
// wire [23:0] cr; // control register - reset at powerup
wire [11:0] ds; // "software" data (programmed by lower 24 bits)
wire [11:0] ds_en; // "software" data enable (programmed by lower 24 bits)
wire [ 3:0] ch_en; // channel enable
reg pre_wen_d;
reg cr_wen;
reg [31:0] did; // registered (dealyed by 1 clock) version of di[25:0]
wire [11:0] ds_en_m;
wire [11:0] da_en_m;
wire [11:0] db_en_m;
wire [11:0] dc_en_m;
assign dc_en_m[11:0]= dc_en[11:0] & {12{ch_en[3]}};
assign db_en_m[11:0]= db_en[11:0] & {12{ch_en[2]}} & ~dc_en_m[11:0];
assign da_en_m[11:0]= da_en[11:0] & {12{ch_en[1]}} & ~dc_en_m[11:0] & ~db_en_m[11:0];
assign ds_en_m[11:0]= ds_en[11:0] & {12{ch_en[0]}} & ~dc_en_m[11:0] & ~db_en_m[11:0] & ~da_en_m[11:0];
assign io_do[11:0]=(dc_en_m[11:0] & dc[11:0]) |
(db_en_m[11:0] & db[11:0]) |
(da_en_m[11:0] & da[11:0]) |
(ds_en_m[11:0] & ds[11:0]);
assign io_t[11:0]=~(dc_en_m[11:0] | db_en_m[11:0] | da_en_m[11:0] | ds_en_m[11:0]);
// 0 0 0 - no change -
// 0 1 1 1 0
// 1 0 2 1 1
// 1 1 3 0 0
FDE_1 i_ds_0 (.C(sclk), .CE(cr_wen & (did[ 0] | did[ 1])), .D( ~did[ 0] ), .Q(ds[ 0]));
FDE_1 i_ds_1 (.C(sclk), .CE(cr_wen & (did[ 2] | did[ 3])), .D( ~did[ 2] ), .Q(ds[ 1]));
FDE_1 i_ds_2 (.C(sclk), .CE(cr_wen & (did[ 4] | did[ 5])), .D( ~did[ 4] ), .Q(ds[ 2]));
FDE_1 i_ds_3 (.C(sclk), .CE(cr_wen & (did[ 6] | did[ 7])), .D( ~did[ 6] ), .Q(ds[ 3]));
FDE_1 i_ds_4 (.C(sclk), .CE(cr_wen & (did[ 8] | did[ 9])), .D( ~did[ 8] ), .Q(ds[ 4]));
FDE_1 i_ds_5 (.C(sclk), .CE(cr_wen & (did[10] | did[11])), .D( ~did[10] ), .Q(ds[ 5]));
FDE_1 i_ds_6 (.C(sclk), .CE(cr_wen & (did[12] | did[13])), .D( ~did[12] ), .Q(ds[ 6]));
FDE_1 i_ds_7 (.C(sclk), .CE(cr_wen & (did[14] | did[15])), .D( ~did[14] ), .Q(ds[ 7]));
FDE_1 i_ds_8 (.C(sclk), .CE(cr_wen & (did[16] | did[17])), .D( ~did[16] ), .Q(ds[ 8]));
FDE_1 i_ds_9 (.C(sclk), .CE(cr_wen & (did[18] | did[19])), .D( ~did[18] ), .Q(ds[ 9]));
FDE_1 i_ds_10 (.C(sclk), .CE(cr_wen & (did[20] | did[21])), .D( ~did[20] ), .Q(ds[10]));
FDE_1 i_ds_11 (.C(sclk), .CE(cr_wen & (did[22] | did[23])), .D( ~did[22] ), .Q(ds[11]));
FDE_1 i_ds_en_0 (.C(sclk), .CE(cr_wen & (did[ 0] | did[ 1])), .D(~(did[ 1] & did[ 0])), .Q(ds_en[ 0]));
FDE_1 i_ds_en_1 (.C(sclk), .CE(cr_wen & (did[ 2] | did[ 3])), .D(~(did[ 3] & did[ 2])), .Q(ds_en[ 1]));
FDE_1 i_ds_en_2 (.C(sclk), .CE(cr_wen & (did[ 4] | did[ 5])), .D(~(did[ 5] & did[ 4])), .Q(ds_en[ 2]));
FDE_1 i_ds_en_3 (.C(sclk), .CE(cr_wen & (did[ 6] | did[ 7])), .D(~(did[ 7] & did[ 6])), .Q(ds_en[ 3]));
FDE_1 i_ds_en_4 (.C(sclk), .CE(cr_wen & (did[ 8] | did[ 9])), .D(~(did[ 9] & did[ 8])), .Q(ds_en[ 4]));
FDE_1 i_ds_en_5 (.C(sclk), .CE(cr_wen & (did[10] | did[11])), .D(~(did[11] & did[10])), .Q(ds_en[ 5]));
FDE_1 i_ds_en_6 (.C(sclk), .CE(cr_wen & (did[12] | did[13])), .D(~(did[13] & did[12])), .Q(ds_en[ 6]));
FDE_1 i_ds_en_7 (.C(sclk), .CE(cr_wen & (did[14] | did[15])), .D(~(did[15] & did[14])), .Q(ds_en[ 7]));
FDE_1 i_ds_en_8 (.C(sclk), .CE(cr_wen & (did[16] | did[17])), .D(~(did[17] & did[16])), .Q(ds_en[ 8]));
FDE_1 i_ds_en_9 (.C(sclk), .CE(cr_wen & (did[18] | did[19])), .D(~(did[19] & did[18])), .Q(ds_en[ 9]));
FDE_1 i_ds_en_10 (.C(sclk), .CE(cr_wen & (did[20] | did[21])), .D(~(did[21] & did[20])), .Q(ds_en[10]));
FDE_1 i_ds_en_11 (.C(sclk), .CE(cr_wen & (did[22] | did[23])), .D(~(did[23] & did[22])), .Q(ds_en[11]));
FDE_1 #(.INIT(1'b1)) i_ch_en_0 (.C(sclk), .CE(cr_wen & did[25]), .D(did[24]), .Q(ch_en[ 0]));
FDE_1 #(.INIT(1'b0)) i_ch_en_1 (.C(sclk), .CE(cr_wen & did[27]), .D(did[26]), .Q(ch_en[ 1]));
FDE_1 #(.INIT(1'b0)) i_ch_en_2 (.C(sclk), .CE(cr_wen & did[29]), .D(did[28]), .Q(ch_en[ 2]));
FDE_1 #(.INIT(1'b0)) i_ch_en_3 (.C(sclk), .CE(cr_wen & did[31]), .D(did[30]), .Q(ch_en[ 3]));
always @ (negedge sclk) begin
pre_wen_d <= pre_wen;
cr_wen <=pre_wen_d;
if (pre_wen) did[15: 0] <= di[15:0];
if (pre_wen_d) did[31:16] <= di[15:0];
end
endmodule
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/coring.dat 0000664 0000000 0000000 00000014237 12555570767 0021232 0 ustar 00root root 0000000 0000000 0000 0000 1111 1111 1111 1111 2222 2222
2222 2222 3333 3333 3333 3333 4444 4444
4444 4444 5555 5555 5555 5555 6666 6666
6666 6666 7777 7777 7777 7777 8888 8888
8888 8888 9999 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 1111 1111 1111 1111 2222 2222
2222 2222 3333 3333 3333 3333 4444 4444
4444 4444 5555 5555 5555 5555 6666 6666
6666 6666 7777 7777 7777 7777 8888 8888
8888 8888 9999 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 1000 1111 1111 1111 2221 2222
2222 2222 3332 3333 3333 3333 4444 4444
4444 4444 5555 5555 5555 5555 6666 6666
6666 6666 7777 7777 7777 7777 8888 8888
8888 8888 9999 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 1000 1111 1111 1111 2221 2222
2222 2222 3332 3333 3333 3333 4444 4444
4444 4444 5555 5555 5555 5555 6666 6666
6666 6666 7777 7777 7777 7777 8888 8888
8888 8888 9999 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 1000 1111 1111 2211 2222
2222 2222 3332 3333 3333 3333 4443 4444
4444 4444 5554 5555 5555 5555 6666 6666
6666 6666 7777 7777 7777 7777 8888 8888
8888 8888 9999 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 1000 1111 1111 2211 2222
2222 2222 3332 3333 3333 3333 4443 4444
4444 4444 5554 5555 5555 5555 6666 6666
6666 6666 7777 7777 7777 7777 8888 8888
8888 8888 9999 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 0000 0000 1000 1111 1111
2111 2222 2222 3332 3333 3333 4433 4444
4444 4444 5554 5555 5555 5555 6665 6666
6666 6666 7776 7777 7777 7777 8888 8888
8888 8888 9999 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 0000 0000 1000 1111 1111
2111 2222 2222 3332 3333 3333 4433 4444
4444 4444 5554 5555 5555 5555 6665 6666
6666 6666 7776 7777 7777 7777 8888 8888
8888 8888 9999 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 0000 0000 0000 0000 1100
1111 1111 1111 2222 2222 3222 3333 3333
4444 4444 5444 5555 5555 5555 6665 6666
6666 6666 7776 7777 7777 7777 8887 8888
8888 8888 9998 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 0000 0000 0000 0000 1100
1111 1111 1111 2222 2222 3222 3333 3333
4444 4444 5444 5555 5555 5555 6665 6666
6666 6666 7776 7777 7777 7777 8887 8888
8888 8888 9998 9999 9999 9999 aaaa aaaa
aaaa aaaa bbbb bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 0000 0000 0000 0000 0000
0000 1110 1111 1111 1111 2221 2222 2222
3333 3333 4433 4444 5444 5555 5555 6665
6666 6666 7766 7777 7777 7777 8887 8888
8888 8888 9998 9999 9999 9999 aaa9 aaaa
aaaa aaaa bbba bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 0000 0000 0000 0000 0000
0000 1110 1111 1111 1111 2221 2222 2222
3333 3333 4433 4444 5444 5555 5555 6665
6666 6666 7766 7777 7777 7777 8887 8888
8888 8888 9998 9999 9999 9999 aaa9 aaaa
aaaa aaaa bbba bbbb bbbb bbbb cccc cccc
cccc cccc dddd dddd dddd dddd eeee eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 1111 1111 1111 1111 1111 1111 2222
2222 2222 3332 3333 3333 4444 4444 5555
5555 6666 7666 7777 8877 8888 9998 9999
aa99 aaaa baaa bbbb bbbb bbbb cccb cccc
cccc cccc dddc dddd dddd dddd eeed eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 1111 1111 1111 1111 1111 1111 2222
2222 2222 3332 3333 3333 4444 4444 5555
5555 6666 7666 7777 8877 8888 9998 9999
aa99 aaaa baaa bbbb bbbb bbbb cccb cccc
cccc cccc dddc dddd dddd dddd eeed eeee
eeee eeee ffff ffff ffff ffff ffff ffff
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
1100 1111 1111 1111 1111 2111 2222 3222
3333 5444 6655 9877 cba9 feed ffff ffff
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
1100 1111 1111 1111 1111 2111 2222 3222
3333 5444 6655 9877 cba9 feed ffff ffff
x353-bc46d5537b0dfc03e4bf726fe279dba239910775/ddr/ 0000775 0000000 0000000 00000000000 12555570767 0020021 5 ustar 00root root 0000000 0000000 x353-bc46d5537b0dfc03e4bf726fe279dba239910775/ddr/ddr.v 0000664 0000000 0000000 00000154675 12555570767 0021003 0 ustar 00root root 0000000 0000000 /****************************************************************************************
*
* File Name: ddr.v
* Version: 5.7
* Model: BUS Functional
*
* Dependencies: ddr_parameters.v
*
* Description: Micron SDRAM DDR (Double Data Rate)
*
* Limitation: - Doesn't check for 8K-cycle refresh.
* - Doesn't check power-down entry/exit
* - Doesn't check self-refresh entry/exit.
*
* Note: - Set simulator resolution to "ps" accuracy
* - Set Debug = 0 to disable $display messages
* - Model assume Clk and Clk# crossing at both edge
*
* Disclaimer This software code and all associated documentation, comments or other
* of Warranty: information (collectively "Software") is provided "AS IS" without
* warranty of any kind. MICRON TECHNOLOGY, INC. ("MTI") EXPRESSLY
* DISCLAIMS ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO, NONINFRINGEMENT OF THIRD PARTY RIGHTS, AND ANY IMPLIED WARRANTIES
* OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. MTI DOES NOT
* WARRANT THAT THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE
* OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE.
* FURTHERMORE, MTI DOES NOT MAKE ANY REPRESENTATIONS REGARDING THE USE OR
* THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS,
* ACCURACY, RELIABILITY, OR OTHERWISE. THE ENTIRE RISK ARISING OUT OF USE
* OR PERFORMANCE OF THE SOFTWARE REMAINS WITH YOU. IN NO EVENT SHALL MTI,
* ITS AFFILIATED COMPANIES OR THEIR SUPPLIERS BE LIABLE FOR ANY DIRECT,
* INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES (INCLUDING,
* WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION,
* OR LOSS OF INFORMATION) ARISING OUT OF YOUR USE OF OR INABILITY TO USE
* THE SOFTWARE, EVEN IF MTI HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGES. Because some jurisdictions prohibit the exclusion or
* limitation of liability for consequential or incidental damages, the
* above limitation may not apply to you.
*
* Copyright 2003 Micron Technology, Inc. All rights reserved.
*
* Rev Author Date Changes
* --- ------ ---------- ---------------------------------------
* 2.1 SPH 03/19/2002 - Second Release
* - Fix tWR and several incompatability
* between different simulators
* 3.0 TFK 02/18/2003 - Added tDSS and tDSH timing checks.
* - Added tDQSH and tDQSL timing checks.
* 3.1 CAH 05/28/2003 - update all models to release version 3.1
* (no changes to this model)
* 3.2 JMK 06/16/2003 - updated all DDR400 models to support CAS Latency 3
* 3.3 JMK 09/11/2003 - Added initialization sequence checks.
* 4.0 JMK 12/01/2003 - Grouped parameters into "ddr_parameters.v"
* - Fixed tWTR check
* 4.1 JMK 01/14/2004 - Grouped specify parameters by speed grade
* - Fixed mem_sizes parameter
* 4.2 JMK 03/19/2004 - Fixed pulse width checking on Dqs
* 4.3 JMK 04/27/2004 - Changed BL wire size in tb module
* - Changed Dq_buf size to [15:0]
* 5.0 JMK 06/16/2004 - Added read to write checking.
* - Added read with precharge truncation to write checking.
* - Added associative memory array to reduce memory consumption.
* - Added checking for required DQS edges during write.
* 5.1 JMK 08/16/2004 - Fixed checking for required DQS edges during write.
* - Fixed wdqs_valid window.
* 5.2 JMK 09/24/2004 - Read or Write without activate will be ignored.
* 5.3 JMK 10/27/2004 - Added tMRD checking during Auto Refresh and Activate.
* - Added tRFC checking during Load Mode and Precharge.
* 5.4 JMK 12/13/2004 - The model will not respond to illegal command sequences.
* 5.5 SPH 01/13/2005 - The model will issue a halt on illegal command sequences.
* JMK 02/11/2005 - Changed the display format for numbers to hex.
* 5.6 JMK 04/22/2005 - Fixed Write with auto precharge calculation.
* 5.7 JMK 08/05/2005 - Changed conditions for read with precharge truncation error.
* - Renamed parameters file with .vh extension.
****************************************************************************************/
// DO NOT CHANGE THE TIMESCALE
// MAKE SURE YOUR SIMULATOR USE "PS" RESOLUTION
`timescale 1ns / 1ps
module ddr (Dq, Dqs, Addr, Ba, Clk, Clk_n, Cke, Cs_n, Ras_n, Cas_n, We_n, Dm);
`define sg6
`include "ddr_parameters.v"
// Port Declarations
inout [DQ_BITS - 1 : 0] Dq;
inout [DQS_BITS - 1 : 0] Dqs;
input [ADDR_BITS - 1 : 0] Addr;
input [1 : 0] Ba;
input Clk;
input Clk_n;
input Cke;
input Cs_n;
input Ras_n;
input Cas_n;
input We_n;
input [DM_BITS - 1 : 0] Dm;
// Internal Wires (fixed width)
wire [15 : 0] Dq_in;
wire [1 : 0] Dqs_in;
wire [1 : 0] Dm_in;
assign Dq_in [DQ_BITS - 1 : 0] = Dq;
assign Dqs_in [DQS_BITS - 1 : 0] = Dqs;
assign Dm_in [DM_BITS - 1 : 0] = Dm;
// Data pair
reg [15 : 0] dq_rise;
reg [1 : 0] dm_rise;
reg [15 : 0] dq_fall;
reg [1 : 0] dm_fall;
reg [3 : 0] dm_pair;
reg [15 : 0] Dq_buf;
// Mode Register
reg [ADDR_BITS - 1 : 0] Mode_reg;
// Internal System Clock
reg CkeZ, Sys_clk;
// Internal Dqs initialize
reg Dqs_int;
// Dqs buffer
reg [DQS_BITS - 1 : 0] Dqs_out;
// Dq buffer
reg [DQ_BITS - 1 : 0] Dq_out;
// Read pipeline variables
reg Read_cmnd [0 : 6];
reg [1 : 0] Read_bank [0 : 6];
reg [COL_BITS - 1 : 0] Read_cols [0 : 6];
// Write pipeline variables
reg Write_cmnd [0 : 3];
reg [1 : 0] Write_bank [0 : 3];
reg [COL_BITS - 1 : 0] Write_cols [0 : 3];
// Auto precharge variables
reg Read_precharge [0 : 3];
reg Write_precharge [0 : 3];
integer Count_precharge [0 : 3];
// Manual precharge variables
reg A10_precharge [0 : 6];
reg [1 : 0] Bank_precharge [0 : 6];
reg Cmnd_precharge [0 : 6];
// Burst terminate variables
reg Cmnd_bst [0 : 6];
// Memory Banks
`ifdef FULL_MEM
reg [DQ_BITS - 1 : 0] mem_array [0 : (1<= 2) begin
if (Debug) $display ("%m: at time %t MEMORY: Power Up and Initialization Sequence is complete", $time);
power_up_done = 1;
end else begin
aref_count = 0;
@ (aref_count >= 2) begin
if (Debug) $display ("%m: at time %t MEMORY: Power Up and Initialization Sequence is complete", $time);
power_up_done = 1;
end
end
end
end
end
end
end
// Write Memory
task write_mem;
input [full_mem_bits - 1 : 0] addr;
input [DQ_BITS - 1 : 0] data;
reg [part_mem_bits : 0] i;
begin
`ifdef FULL_MEM
mem_array[addr] = data;
`else
begin : loop
for (i = 0; i < mem_used; i = i + 1) begin
if (addr_array[i] === addr) begin
disable loop;
end
end
end
if (i === mem_used) begin
if (i === (1<= burst_length) begin
Data_in_enable = 1'b0;
Data_out_enable = 1'b0;
read_precharge_truncation = 4'h0;
end
end
endtask
// Manual Precharge Pipeline
task Manual_Precharge_Pipeline;
begin
// A10 Precharge Pipeline
A10_precharge[0] = A10_precharge[1];
A10_precharge[1] = A10_precharge[2];
A10_precharge[2] = A10_precharge[3];
A10_precharge[3] = A10_precharge[4];
A10_precharge[4] = A10_precharge[5];
A10_precharge[5] = A10_precharge[6];
A10_precharge[6] = 1'b0;
// Bank Precharge Pipeline
Bank_precharge[0] = Bank_precharge[1];
Bank_precharge[1] = Bank_precharge[2];
Bank_precharge[2] = Bank_precharge[3];
Bank_precharge[3] = Bank_precharge[4];
Bank_precharge[4] = Bank_precharge[5];
Bank_precharge[5] = Bank_precharge[6];
Bank_precharge[6] = 2'b0;
// Command Precharge Pipeline
Cmnd_precharge[0] = Cmnd_precharge[1];
Cmnd_precharge[1] = Cmnd_precharge[2];
Cmnd_precharge[2] = Cmnd_precharge[3];
Cmnd_precharge[3] = Cmnd_precharge[4];
Cmnd_precharge[4] = Cmnd_precharge[5];
Cmnd_precharge[5] = Cmnd_precharge[6];
Cmnd_precharge[6] = 1'b0;
// Terminate a Read if same bank or all banks
if (Cmnd_precharge[0] === 1'b1) begin
if (Bank_precharge[0] === Bank_addr || A10_precharge[0] === 1'b1) begin
if (Data_out_enable === 1'b1) begin
Data_out_enable = 1'b0;
read_precharge_truncation = 4'hF;
end
end
end
end
endtask
// Burst Terminate Pipeline
task Burst_Terminate_Pipeline;
begin
// Command Precharge Pipeline
Cmnd_bst[0] = Cmnd_bst[1];
Cmnd_bst[1] = Cmnd_bst[2];
Cmnd_bst[2] = Cmnd_bst[3];
Cmnd_bst[3] = Cmnd_bst[4];
Cmnd_bst[4] = Cmnd_bst[5];
Cmnd_bst[5] = Cmnd_bst[6];
Cmnd_bst[6] = 1'b0;
// Terminate a Read regardless of banks
if (Cmnd_bst[0] === 1'b1 && Data_out_enable === 1'b1) begin
Data_out_enable = 1'b0;
end
end
endtask
// Dq and Dqs Drivers
task Dq_Dqs_Drivers;
begin
// read command pipeline
Read_cmnd [0] = Read_cmnd [1];
Read_cmnd [1] = Read_cmnd [2];
Read_cmnd [2] = Read_cmnd [3];
Read_cmnd [3] = Read_cmnd [4];
Read_cmnd [4] = Read_cmnd [5];
Read_cmnd [5] = Read_cmnd [6];
Read_cmnd [6] = 1'b0;
// read bank pipeline
Read_bank [0] = Read_bank [1];
Read_bank [1] = Read_bank [2];
Read_bank [2] = Read_bank [3];
Read_bank [3] = Read_bank [4];
Read_bank [4] = Read_bank [5];
Read_bank [5] = Read_bank [6];
Read_bank [6] = 2'b0;
// read column pipeline
Read_cols [0] = Read_cols [1];
Read_cols [1] = Read_cols [2];
Read_cols [2] = Read_cols [3];
Read_cols [3] = Read_cols [4];
Read_cols [4] = Read_cols [5];
Read_cols [5] = Read_cols [6];
Read_cols [6] = 0;
// Initialize Read command
if (Read_cmnd [0] === 1'b1) begin
Data_out_enable = 1'b1;
Bank_addr = Read_bank [0];
Cols_addr = Read_cols [0];
Cols_brst = Cols_addr [2 : 0];
Burst_counter = 0;
// Row Address Mux
case (Bank_addr)
2'd0 : Rows_addr = B0_row_addr;
2'd1 : Rows_addr = B1_row_addr;
2'd2 : Rows_addr = B2_row_addr;
2'd3 : Rows_addr = B3_row_addr;
default : $display ("At time %t ERROR: Invalid Bank Address", $time);
endcase
end
// Toggle Dqs during Read command
if (Data_out_enable === 1'b1) begin
Dqs_int = 1'b0;
if (Dqs_out === {DQS_BITS{1'b0}}) begin
Dqs_out = {DQS_BITS{1'b1}};
end else if (Dqs_out === {DQS_BITS{1'b1}}) begin
Dqs_out = {DQS_BITS{1'b0}};
end else begin
Dqs_out = {DQS_BITS{1'b0}};
end
end else if (Data_out_enable === 1'b0 && Dqs_int === 1'b0) begin
Dqs_out = {DQS_BITS{1'bz}};
end
// Initialize dqs for Read command
if (Read_cmnd [2] === 1'b1) begin
if (Data_out_enable === 1'b0) begin
Dqs_int = 1'b1;
Dqs_out = {DQS_BITS{1'b0}};
end
end
// Read latch
if (Data_out_enable === 1'b1) begin
// output data
read_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_out);
if (Debug) begin
$display ("At time %t READ : Bank = %x, Row = %x, Col = %x, Data = %x", $time, Bank_addr, Rows_addr, Cols_addr, Dq_out);
end
end else begin
Dq_out = {DQ_BITS{1'bz}};
end
end
endtask
// Write FIFO and DM Mask Logic
task Write_FIFO_DM_Mask_Logic;
begin
// Write command pipeline
Write_cmnd [0] = Write_cmnd [1];
Write_cmnd [1] = Write_cmnd [2];
Write_cmnd [2] = Write_cmnd [3];
Write_cmnd [3] = 1'b0;
// Write command pipeline
Write_bank [0] = Write_bank [1];
Write_bank [1] = Write_bank [2];
Write_bank [2] = Write_bank [3];
Write_bank [3] = 2'b0;
// Write column pipeline
Write_cols [0] = Write_cols [1];
Write_cols [1] = Write_cols [2];
Write_cols [2] = Write_cols [3];
Write_cols [3] = {COL_BITS{1'b0}};
// Initialize Write command
if (Write_cmnd [0] === 1'b1) begin
Data_in_enable = 1'b1;
Bank_addr = Write_bank [0];
Cols_addr = Write_cols [0];
Cols_brst = Cols_addr [2 : 0];
Burst_counter = 0;
// Row address mux
case (Bank_addr)
2'd0 : Rows_addr = B0_row_addr;
2'd1 : Rows_addr = B1_row_addr;
2'd2 : Rows_addr = B2_row_addr;
2'd3 : Rows_addr = B3_row_addr;
default : $display ("At time %t ERROR: Invalid Row Address", $time);
endcase
end
// Write data
if (Data_in_enable === 1'b1) begin
// Data Buffer
read_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_buf);
// write negedge Dqs on posedge Sys_clk
if (Sys_clk) begin
if (!dm_fall[0]) begin
Dq_buf [ 7 : 0] = dq_fall [ 7 : 0];
end
if (!dm_fall[1]) begin
Dq_buf [15 : 8] = dq_fall [15 : 8];
end
if (~&dm_fall) begin
if (Debug) begin
$display ("At time %t WRITE: Bank = %x, Row = %x, Col = %x, Data = %x", $time, Bank_addr, Rows_addr, Cols_addr, Dq_buf[DQ_BITS-1:0]);
end
end
// write posedge Dqs on negedge Sys_clk
end else begin
if (!dm_rise[0]) begin
Dq_buf [ 7 : 0] = dq_rise [ 7 : 0];
end
if (!dm_rise[1]) begin
Dq_buf [15 : 8] = dq_rise [15 : 8];
end
if (~&dm_rise) begin
if (Debug) begin
$display ("At time %t WRITE: Bank = %x, Row = %x, Col = %x, Data = %x", $time, Bank_addr, Rows_addr, Cols_addr, Dq_buf[DQ_BITS-1:0]);
end
end
end
// Write Data
write_mem({Bank_addr, Rows_addr, Cols_addr}, Dq_buf);
// tWR start and tWTR check
if (Sys_clk && &dm_pair === 1'b0) begin
case (Bank_addr)
2'd0 : WR_chk0 = $time;
2'd1 : WR_chk1 = $time;
2'd2 : WR_chk2 = $time;
2'd3 : WR_chk3 = $time;
default : $display ("At time %t ERROR: Invalid Bank Address (tWR)", $time);
endcase
// tWTR check
if (Read_enable === 1'b1) begin
$display ("At time %t ERROR: tWTR violation during Read", $time);
end
end
end
end
endtask
// Auto Precharge Calculation
task Auto_Precharge_Calculation;
begin
// Precharge counter
if (Read_precharge [0] === 1'b1 || Write_precharge [0] === 1'b1) begin
Count_precharge [0] = Count_precharge [0] + 1;
end
if (Read_precharge [1] === 1'b1 || Write_precharge [1] === 1'b1) begin
Count_precharge [1] = Count_precharge [1] + 1;
end
if (Read_precharge [2] === 1'b1 || Write_precharge [2] === 1'b1) begin
Count_precharge [2] = Count_precharge [2] + 1;
end
if (Read_precharge [3] === 1'b1 || Write_precharge [3] === 1'b1) begin
Count_precharge [3] = Count_precharge [3] + 1;
end
// Read with AutoPrecharge Calculation
// The device start internal precharge when:
// 1. Meet tRAS requirement
// 2. BL/2 cycles after command
if ((Read_precharge[0] === 1'b1) && ($time - RAS_chk0 >= tRAS)) begin
if (Count_precharge[0] >= burst_length/2) begin
Pc_b0 = 1'b1;
Act_b0 = 1'b0;
RP_chk0 = $time;
Read_precharge[0] = 1'b0;
end
end
if ((Read_precharge[1] === 1'b1) && ($time - RAS_chk1 >= tRAS)) begin
if (Count_precharge[1] >= burst_length/2) begin
Pc_b1 = 1'b1;
Act_b1 = 1'b0;
RP_chk1 = $time;
Read_precharge[1] = 1'b0;
end
end
if ((Read_precharge[2] === 1'b1) && ($time - RAS_chk2 >= tRAS)) begin
if (Count_precharge[2] >= burst_length/2) begin
Pc_b2 = 1'b1;
Act_b2 = 1'b0;
RP_chk2 = $time;
Read_precharge[2] = 1'b0;
end
end
if ((Read_precharge[3] === 1'b1) && ($time - RAS_chk3 >= tRAS)) begin
if (Count_precharge[3] >= burst_length/2) begin
Pc_b3 = 1'b1;
Act_b3 = 1'b0;
RP_chk3 = $time;
Read_precharge[3] = 1'b0;
end
end
// Write with AutoPrecharge Calculation
// The device start internal precharge when:
// 1. Meet tRAS requirement
// 2. Write Latency PLUS BL/2 cycles PLUS tWR after Write command
if ((Write_precharge[0] === 1'b1) && ($time - RAS_chk0 >= tRAS)) begin
if ((Count_precharge[0] >= burst_length/2+1) && ($time - WR_chk0 >= tWR)) begin
Pc_b0 = 1'b1;
Act_b0 = 1'b0;
RP_chk0 = $time;
Write_precharge[0] = 1'b0;
end
end
if ((Write_precharge[1] === 1'b1) && ($time - RAS_chk1 >= tRAS)) begin
if ((Count_precharge[1] >= burst_length/2+1) && ($time - WR_chk1 >= tWR)) begin
Pc_b1 = 1'b1;
Act_b1 = 1'b0;
RP_chk1 = $time;
Write_precharge[1] = 1'b0;
end
end
if ((Write_precharge[2] === 1'b1) && ($time - RAS_chk2 >= tRAS)) begin
if ((Count_precharge[2] >= burst_length/2+1) && ($time - WR_chk2 >= tWR)) begin
Pc_b2 = 1'b1;
Act_b2 = 1'b0;
RP_chk2 = $time;
Write_precharge[2] = 1'b0;
end
end
if ((Write_precharge[3] === 1'b1) && ($time - RAS_chk3 >= tRAS)) begin
if ((Count_precharge[3] >= burst_length/2+1) && ($time - WR_chk3 >= tWR)) begin
Pc_b3 = 1'b1;
Act_b3 = 1'b0;
RP_chk3 = $time;
Write_precharge[3] = 1'b0;
end
end
end
endtask
// DLL Counter
task DLL_Counter;
begin
if (DLL_reset === 1'b1 && DLL_done === 1'b0) begin
DLL_count = DLL_count + 1;
if (DLL_count >= 200) begin
DLL_done = 1'b1;
end
end
end
endtask
// Control Logic
task Control_Logic;
begin
// Auto Refresh
if (Aref_enable === 1'b1) begin
// Display Debug Message
if (Debug) begin
$display ("At time %t AREF : Auto Refresh", $time);
end
// Precharge to Auto Refresh
if (($time - RP_chk0 < tRP) || ($time - RP_chk1 < tRP) ||
($time - RP_chk2 < tRP) || ($time - RP_chk3 < tRP)) begin
$display ("At time %t ERROR: tRP violation during Auto Refresh", $time);
end
// LMR/EMR to Auto Refresh
if ($time - MRD_chk < tMRD) begin
$display ("At time %t ERROR: tMRD violation during Auto Refresh", $time);
end
// Auto Refresh to Auto Refresh
if ($time - RFC_chk < tRFC) begin
$display ("At time %t ERROR: tRFC violation during Auto Refresh", $time);
end
// Precharge to Auto Refresh
if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin
$display ("At time %t ERROR: All banks must be Precharged before Auto Refresh", $time);
if (!no_halt) $stop (0);
end else begin
aref_count = aref_count + 1;
RFC_chk = $time;
end
end
// Extended Mode Register
if (Ext_mode_enable === 1'b1) begin
if (Debug) begin
$display ("At time %t EMR : Extended Mode Register", $time);
end
// Precharge to LMR/EMR
if (($time - RP_chk0 < tRP) || ($time - RP_chk1 < tRP) ||
($time - RP_chk2 < tRP) || ($time - RP_chk3 < tRP)) begin
$display ("At time %t ERROR: tRP violation during Extended Mode Register", $time);
end
// LMR/EMR to LMR/EMR
if ($time - MRD_chk < tMRD) begin
$display ("At time %t ERROR: tMRD violation during Extended Mode Register", $time);
end
// Auto Refresh to LMR/EMR
if ($time - RFC_chk < tRFC) begin
$display ("At time %t ERROR: tRFC violation during Extended Mode Register", $time);
end
// Precharge to LMR/EMR
if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin
$display ("At time %t ERROR: all banks must be Precharged before Extended Mode Register", $time);
if (!no_halt) $stop (0);
end else begin
if (Addr[0] === 1'b0) begin
DLL_enable = 1'b1;
if (Debug) begin
$display ("At time %t EMR : Enable DLL", $time);
end
end else begin
DLL_enable = 1'b0;
if (Debug) begin
$display ("At time %t EMR : Disable DLL", $time);
end
end
MRD_chk = $time;
end
end
// Load Mode Register
if (Mode_reg_enable === 1'b1) begin
if (Debug) begin
$display ("At time %t LMR : Load Mode Register", $time);
end
// Precharge to LMR/EMR
if (($time - RP_chk0 < tRP) || ($time - RP_chk1 < tRP) ||
($time - RP_chk2 < tRP) || ($time - RP_chk3 < tRP)) begin
$display ("At time %t ERROR: tRP violation during Load Mode Register", $time);
end
// LMR/EMR to LMR/EMR
if ($time - MRD_chk < tMRD) begin
$display ("At time %t ERROR: tMRD violation during Load Mode Register", $time);
end
// Auto Refresh to LMR/EMR
if ($time - RFC_chk < tRFC) begin
$display ("At time %t ERROR: tRFC violation during Load Mode Register", $time);
end
// Precharge to LMR/EMR
if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin
$display ("At time %t ERROR: all banks must be Precharged before Load Mode Register", $time);
end else begin
// Register Mode
Mode_reg = Addr;
// DLL Reset
if (DLL_enable === 1'b1 && Addr [8] === 1'b1) begin
DLL_reset = 1'b1;
DLL_done = 1'b0;
DLL_count = 0;
end else if (DLL_enable === 1'b1 && DLL_reset === 1'b0 && Addr [8] === 1'b0) begin
$display ("At time %t ERROR: DLL is ENABLE: DLL RESET is required.", $time);
end else if (DLL_enable === 1'b0 && Addr [8] === 1'b1) begin
$display ("At time %t ERROR: DLL is DISABLE: DLL RESET will be ignored.", $time);
end
// Burst Length
case (Addr [2 : 0])
3'b001 : $display ("At time %t LMR : Burst Length = 2", $time);
3'b010 : $display ("At time %t LMR : Burst Length = 4", $time);
3'b011 : $display ("At time %t LMR : Burst Length = 8", $time);
default : $display ("At time %t ERROR: Burst Length not supported", $time);
endcase
// CAS Latency
case (Addr [6 : 4])
3'b010 : $display ("At time %t LMR : CAS Latency = 2", $time);
3'b110 : $display ("At time %t LMR : CAS Latency = 2.5", $time);
3'b011 : $display ("At time %t LMR : CAS Latency = 3", $time);
default : $display ("At time %t ERROR: CAS Latency not supported", $time);
endcase
// Record current tMRD time
MRD_chk = $time;
end
end
// Activate Block
if (Active_enable === 1'b1) begin
if (!(power_up_done)) begin
$display ("%m: at time %t ERROR: Power Up and Initialization Sequence not completed before executing Activate command", $time);
end
// Display Debug Message
if (Debug) begin
$display ("At time %t ACT : Bank = %x, Row = %x", $time, Ba, Addr);
end
// Activate to Activate (different bank)
if ((Prev_bank != Ba) && ($time - RRD_chk < tRRD)) begin
$display ("At time %t ERROR: tRRD violation during Activate bank %h", $time, Ba);
end
// LMR/EMR to Activate
if ($time - MRD_chk < tMRD) begin
$display ("At time %t ERROR: tMRD violation during Activate bank %h", $time, Ba);
end
// AutoRefresh to Activate
if ($time - RFC_chk < tRFC) begin
$display ("At time %t ERROR: tRFC violation during Activate bank %h", $time, Ba);
end
// Precharge to Activate
if ((Ba === 2'b00 && Pc_b0 === 1'b0) || (Ba === 2'b01 && Pc_b1 === 1'b0) ||
(Ba === 2'b10 && Pc_b2 === 1'b0) || (Ba === 2'b11 && Pc_b3 === 1'b0)) begin
$display ("At time %t ERROR: Bank = %h is already activated - Command Ignored", $time, Ba);
if (!no_halt) $stop (0);
end else begin
// Activate Bank 0
if (Ba === 2'b00 && Pc_b0 === 1'b1) begin
// Activate to Activate (same bank)
if ($time - RC_chk0 < tRC) begin
$display ("At time %t ERROR: tRC violation during Activate bank %x", $time, Ba);
end
// Precharge to Activate
if ($time - RP_chk0 < tRP) begin
$display ("At time %t ERROR: tRP violation during Activate bank %x", $time, Ba);
end
// Record variables for checking violation
Act_b0 = 1'b1;
Pc_b0 = 1'b0;
B0_row_addr = Addr;
RC_chk0 = $time;
RCD_chk0 = $time;
RAS_chk0 = $time;
RAP_chk0 = $time;
end
// Activate Bank 1
if (Ba === 2'b01 && Pc_b1 === 1'b1) begin
// Activate to Activate (same bank)
if ($time - RC_chk1 < tRC) begin
$display ("At time %t ERROR: tRC violation during Activate bank %x", $time, Ba);
end
// Precharge to Activate
if ($time - RP_chk1 < tRP) begin
$display ("At time %t ERROR: tRP violation during Activate bank %x", $time, Ba);
end
// Record variables for checking violation
Act_b1 = 1'b1;
Pc_b1 = 1'b0;
B1_row_addr = Addr;
RC_chk1 = $time;
RCD_chk1 = $time;
RAS_chk1 = $time;
RAP_chk1 = $time;
end
// Activate Bank 2
if (Ba === 2'b10 && Pc_b2 === 1'b1) begin
// Activate to Activate (same bank)
if ($time - RC_chk2 < tRC) begin
$display ("At time %t ERROR: tRC violation during Activate bank %x", $time, Ba);
end
// Precharge to Activate
if ($time - RP_chk2 < tRP) begin
$display ("At time %t ERROR: tRP violation during Activate bank %x", $time, Ba);
end
// Record variables for checking violation
Act_b2 = 1'b1;
Pc_b2 = 1'b0;
B2_row_addr = Addr;
RC_chk2 = $time;
RCD_chk2 = $time;
RAS_chk2 = $time;
RAP_chk2 = $time;
end
// Activate Bank 3
if (Ba === 2'b11 && Pc_b3 === 1'b1) begin
// Activate to Activate (same bank)
if ($time - RC_chk3 < tRC) begin
$display ("At time %t ERROR: tRC violation during Activate bank %h", $time, Ba);
end
// Precharge to Activate
if ($time - RP_chk3 < tRP) begin
$display ("At time %t ERROR: tRP violation during Activate bank %h", $time, Ba);
end
// Record variables for checking violation
Act_b3 = 1'b1;
Pc_b3 = 1'b0;
B3_row_addr = Addr;
RC_chk3 = $time;
RCD_chk3 = $time;
RAS_chk3 = $time;
RAP_chk3 = $time;
end
// Record variable for checking violation
RRD_chk = $time;
Prev_bank = Ba;
read_precharge_truncation[Ba] = 1'b0;
end
end
// Precharge Block - consider NOP if bank already precharged or in process of precharging
if (Prech_enable === 1'b1) begin
// Display Debug Message
if (Debug) begin
$display ("At time %t PRE : Addr[10] = %b, Bank = %b", $time, Addr[10], Ba);
end
// LMR/EMR to Precharge
if ($time - MRD_chk < tMRD) begin
$display ("At time %t ERROR: tMRD violation during Precharge", $time);
end
// AutoRefresh to Precharge
if ($time - RFC_chk < tRFC) begin
$display ("At time %t ERROR: tRFC violation during Precharge", $time);
end
// Precharge bank 0
if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b00)) && Act_b0 === 1'b1) begin
Act_b0 = 1'b0;
Pc_b0 = 1'b1;
RP_chk0 = $time;
// Activate to Precharge Bank
if ($time - RAS_chk0 < tRAS) begin
$display ("At time %t ERROR: tRAS violation during Precharge", $time);
end
// tWR violation check for Write
if ($time - WR_chk0 < tWR) begin
$display ("At time %t ERROR: tWR violation during Precharge", $time);
end
end
// Precharge bank 1
if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b01)) && Act_b1 === 1'b1) begin
Act_b1 = 1'b0;
Pc_b1 = 1'b1;
RP_chk1 = $time;
// Activate to Precharge Bank 1
if ($time - RAS_chk1 < tRAS) begin
$display ("At time %t ERROR: tRAS violation during Precharge", $time);
end
// tWR violation check for Write
if ($time - WR_chk1 < tWR) begin
$display ("At time %t ERROR: tWR violation during Precharge", $time);
end
end
// Precharge bank 2
if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b10)) && Act_b2 === 1'b1) begin
Act_b2 = 1'b0;
Pc_b2 = 1'b1;
RP_chk2 = $time;
// Activate to Precharge Bank 2
if ($time - RAS_chk2 < tRAS) begin
$display ("At time %t ERROR: tRAS violation during Precharge", $time);
end
// tWR violation check for Write
if ($time - WR_chk2 < tWR) begin
$display ("At time %t ERROR: tWR violation during Precharge", $time);
end
end
// Precharge bank 3
if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b11)) && Act_b3 === 1'b1) begin
Act_b3 = 1'b0;
Pc_b3 = 1'b1;
RP_chk3 = $time;
// Activate to Precharge Bank 3
if ($time - RAS_chk3 < tRAS) begin
$display ("At time %t ERROR: tRAS violation during Precharge", $time);
end
// tWR violation check for Write
if ($time - WR_chk3 < tWR) begin
$display ("At time %t ERROR: tWR violation during Precharge", $time);
end
end
// Prech_count is to make sure we have met part of the initialization sequence
Prech_count = Prech_count + 1;
// Pipeline for READ
A10_precharge [cas_latency_x2] = Addr[10];
Bank_precharge[cas_latency_x2] = Ba;
Cmnd_precharge[cas_latency_x2] = 1'b1;
end
// Burst terminate
if (Burst_term === 1'b1) begin
// Display Debug Message
if (Debug) begin
$display ("At time %t BST : Burst Terminate",$time);
end
if (Data_in_enable === 1'b1) begin
// Illegal to burst terminate a Write
$display ("At time %t ERROR: It's illegal to burst terminate a Write", $time);
if (!no_halt) $stop (0);
end else if (Read_precharge[0] === 1'b1 || Read_precharge[1] === 1'b1 ||
// Illegal to burst terminate a Read with Auto Precharge
Read_precharge[2] === 1'b1 || Read_precharge[3] === 1'b1) begin
$display ("At time %t ERROR: It's illegal to burst terminate a Read with Auto Precharge", $time);
if (!no_halt) $stop (0);
end else begin
// Burst Terminate Command Pipeline for Read
Cmnd_bst[cas_latency_x2] = 1'b1;
end
end
// Read Command
if (Read_enable === 1'b1) begin
if (!(power_up_done)) begin
$display ("%m: at time %t ERROR: Power Up and Initialization Sequence not completed before executing Read Command", $time);
end
// Check for DLL reset before Read
if (DLL_reset === 1 && DLL_done === 0) begin
$display ("%m: at time %t ERROR: You need to wait 200 tCK after DLL Reset Enable to Read, Not %0d clocks.", $time, DLL_count);
end
// Display Debug Message
if (Debug) begin
$display ("At time %t READ : Bank = %x, Col = %x", $time, Ba, {Addr [11], Addr [9 : 0]});
end
// Terminate a Write
if (Data_in_enable === 1'b1) begin
Data_in_enable = 1'b0;
end
// Activate to Read without Auto Precharge
if ((Addr [10] === 1'b0 && Ba === 2'b00 && $time - RCD_chk0 < tRCD) ||
(Addr [10] === 1'b0 && Ba === 2'b01 && $time - RCD_chk1 < tRCD) ||
(Addr [10] === 1'b0 && Ba === 2'b10 && $time - RCD_chk2 < tRCD) ||
(Addr [10] === 1'b0 && Ba === 2'b11 && $time - RCD_chk3 < tRCD)) begin
$display("At time %t ERROR: tRCD violation during Read", $time);
end
// Activate to Read with Auto Precharge
if ((Addr [10] === 1'b1 && Ba === 2'b00 && $time - RAP_chk0 < tRAP) ||
(Addr [10] === 1'b1 && Ba === 2'b01 && $time - RAP_chk1 < tRAP) ||
(Addr [10] === 1'b1 && Ba === 2'b10 && $time - RAP_chk2 < tRAP) ||
(Addr [10] === 1'b1 && Ba === 2'b11 && $time - RAP_chk3 < tRAP)) begin
$display ("At time %t ERROR: tRAP violation during Read", $time);
end
// Interrupt a Read with Auto Precharge (same bank only)
if (Read_precharge [Ba] === 1'b1) begin
$display ("At time %t ERROR: It's illegal to interrupt a Read with Auto Precharge", $time);
if (!no_halt) $stop (0);
// Cancel Auto Precharge
if (Addr[10] === 1'b0) begin
Read_precharge [Ba]= 1'b0;
end
end
// Activate to Read
if ((Ba === 2'b00 && Pc_b0 === 1'b1) || (Ba === 2'b01 && Pc_b1 === 1'b1) ||
(Ba === 2'b10 && Pc_b2 === 1'b1) || (Ba === 2'b11 && Pc_b3 === 1'b1)) begin
$display("At time %t ERROR: Bank is not Activated for Read", $time);
if (!no_halt) $stop (0);
end else begin
// CAS Latency pipeline
Read_cmnd[cas_latency_x2] = 1'b1;
Read_bank[cas_latency_x2] = Ba;
Read_cols[cas_latency_x2] = {Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]};
// Auto Precharge
if (Addr[10] === 1'b1) begin
Read_precharge [Ba]= 1'b1;
Count_precharge [Ba]= 0;
end
end
end
// Write Command
if (Write_enable === 1'b1) begin
if (!(power_up_done)) begin
$display ("%m: at time %t ERROR: Power Up and Initialization Sequence not completed before executing Write Command", $time);
if (!no_halt) $stop (0);
end
// display debug message
if (Debug) begin
$display ("At time %t WRITE: Bank = %h, Col = %h", $time, Ba, {Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]});
end
// Activate to Write
if ((Ba === 2'b00 && $time - RCD_chk0 < tRCD) ||
(Ba === 2'b01 && $time - RCD_chk1 < tRCD) ||
(Ba === 2'b10 && $time - RCD_chk2 < tRCD) ||
(Ba === 2'b11 && $time - RCD_chk3 < tRCD)) begin
$display("At time %t ERROR: tRCD violation during Write to Bank %x", $time, Ba);
end
// Read to Write
if (Read_cmnd[0] || Read_cmnd[1] || Read_cmnd[2] || Read_cmnd[3] ||
Read_cmnd[4] || Read_cmnd[5] || Read_cmnd[6] || (Burst_counter < burst_length)) begin
if (Data_out_enable || read_precharge_truncation) begin
$display("At time %t ERROR: Read to Write violation", $time);
end
end
// Interrupt a Write with Auto Precharge (same bank only)
if (Write_precharge [Ba] === 1'b1) begin
$display ("At time %t ERROR: it's illegal to interrupt a Write with Auto Precharge", $time);
if (!no_halt) $stop (0);
// Cancel Auto Precharge
if (Addr[10] === 1'b0) begin
Write_precharge [Ba]= 1'b0;
end
end
// Activate to Write
if ((Ba === 2'b00 && Pc_b0 === 1'b1) || (Ba === 2'b01 && Pc_b1 === 1'b1) ||
(Ba === 2'b10 && Pc_b2 === 1'b1) || (Ba === 2'b11 && Pc_b3 === 1'b1)) begin
$display("At time %t ERROR: Bank is not Activated for Write", $time);
if (!no_halt) $stop (0);
end else begin
// Pipeline for Write
Write_cmnd [3] = 1'b1;
Write_bank [3] = Ba;
Write_cols [3] = {Addr [ADDR_BITS - 1 : 11], Addr [9 : 0]};
// Auto Precharge
if (Addr[10] === 1'b1) begin
Write_precharge [Ba]= 1'b1;
Count_precharge [Ba]= 0;
end
end
end
end
endtask
task check_neg_dqs;
begin
if (Write_cmnd[2] || Write_cmnd[1] || Data_in_enable) begin
for (i=0; i