Repository: ZipCPU/autofpga Branch: master Commit: fdfd1b633e9c Files: 131 Total size: 1.1 MB Directory structure: gitextract_n54jfvbv/ ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── auto-data/ │ ├── allclocks.txt │ ├── bkram.txt │ ├── buserr.txt │ ├── clkcheck.txt │ ├── clkcounter.txt │ ├── crossbus.txt │ ├── ddr3.txt │ ├── edid.txt │ ├── edidslvscope.txt │ ├── exconsole.txt │ ├── flash.txt │ ├── flashcfg.txt │ ├── global.txt │ ├── gpio.txt │ ├── gps.txt │ ├── hdmi.txt │ ├── i2ccpu.txt │ ├── i2cdma.txt │ ├── i2saudio.txt │ ├── icape.txt │ ├── legalgen.txt │ ├── mdio.txt │ ├── meganet.txt │ ├── nexysv.xdc │ ├── pic.txt │ ├── pwrcount.txt │ ├── rtccount.txt │ ├── rtcdate.txt │ ├── rtcgps.txt │ ├── sdio.txt │ ├── sdspi.txt │ ├── spio.txt │ ├── vadj33.txt │ ├── version.txt │ ├── wboledbw.txt │ ├── wbpmic.txt │ ├── wbscopc.txt │ ├── wbscope.txt │ ├── wbuarbiter.txt │ ├── wbuart.txt │ ├── wbubus.txt │ ├── zipcpu.txt │ └── zipmaster.txt ├── demo-out/ │ ├── board.h │ ├── board.ld │ ├── build.xdc │ ├── iscachable.v │ ├── main.v │ ├── main_tb.cpp │ ├── regdefs.cpp │ ├── regdefs.h │ ├── rtl.make.inc │ ├── testb.h │ └── toplevel.v ├── doc/ │ ├── 20200709-update.dia │ ├── Makefile │ ├── bus.md │ ├── clocks.md │ ├── constraints.md │ ├── double.md │ ├── goals.txt │ ├── icd.txt │ ├── ioports.md │ ├── single.md │ ├── slaves.md │ └── src/ │ └── gpl-3.0.tex └── sw/ ├── .gitignore ├── Makefile ├── ast.cpp ├── ast.h ├── autofpga.cpp ├── automdata.h ├── autopdata.h ├── bitlib.cpp ├── bitlib.h ├── bldboardld.cpp ├── bldboardld.h ├── bldcachable.cpp ├── bldcachable.h ├── bldregdefs.cpp ├── bldregdefs.h ├── bldrtlmake.cpp ├── bldrtlmake.h ├── bldsim.cpp ├── bldsim.h ├── bldtestb.cpp ├── bldtestb.h ├── bus/ │ ├── axi.cpp │ ├── axi.h │ ├── axil.cpp │ ├── axil.h │ ├── wb.cpp │ └── wb.h ├── businfo.cpp ├── businfo.h ├── clockinfo.cpp ├── clockinfo.h ├── expr.l ├── expr.ypp ├── gather.cpp ├── gather.h ├── genbus.cpp ├── genbus.h ├── globals.cpp ├── globals.h ├── ifdefs.cpp ├── ifdefs.h ├── keys.cpp ├── keys.h ├── kveval.cpp ├── kveval.h ├── legalnotice.cpp ├── legalnotice.h ├── mapdhash.cpp ├── mapdhash.h ├── mlist.cpp ├── mlist.h ├── msgs.cpp ├── msgs.h ├── parser.cpp ├── parser.h ├── plist.cpp ├── plist.h ├── predicates.cpp ├── predicates.h ├── subbus.cpp └── subbus.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ legal.txt .svn xilinx obj_dir obj-pc obj-zip *.o *.a *.vcd .swp .*.swp .*.swo svn-commit* *_tb *_tb.dbl *dbg.txt autofpga.dbg *dump.txt *debug.txt tags cpudefs.h 20*-autofpga.tjz core ================================================ FILE: LICENSE ================================================ 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 . ================================================ FILE: Makefile ================================================ ################################################################################ ## ## Filename: Makefile ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: A master project makefile. It tries to build all targets ## within the project, mostly by directing subdirectory makes. ## ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} .PHONY: all all: sw YYMMDD:=`date +%Y%m%d` .PHONY: archive ## {{{ archive: tar --transform s,^,$(YYMMDD)-video/, -chjf $(YYMMDD)-autofpga.tjz sw/ auto-data/ demo-out/ doc/ ## }}} .PHONY: autofpga autofpga: sw .PHONY: sw ## {{{ sw: $(MAKE) --no-print-directory --directory=sw ## }}} .PHONY: clean ## {{{ clean: $(MAKE) --no-print-directory --directory=sw clean ## }}} ================================================ FILE: README.md ================================================ # AutoFPGA - An FPGA Design Automation routine After now having built several FPGA designs, such as the [xulalx25soc](https://github.com/ZipCPU/xulalx25soc), [s6soc](https://github.com/ZipCPU/s6soc), [openarty](https://github.com/ZipCPU/openarty), [zbasic](https://github.com/ZipCPU/zbasic), [icozip](https://github.com/ZipCPU/icozip), and even a Basys-3 design of my own that hasn't been published, I started recognizing that all of these designs have a lot in common. In particular, they all have a set of bus masters, such as the [UART-to-wishbone](https://github.com/ZipCPU/zbasic/blob/master/rtl/wbubus.v) bridge that I use, the [hexbus](https://github.com/ZipCPU/dbgbus) debugging bus that offers a simpler version of the same, or even the [zipcpu](https://github.com/ZipCPU/zipcpu). Many of these designs have also started to use (and reuse) many of the peripherals I've developed, such as the generic [UART](https://github.com/ZipCPU/wbuart), the [QSPI flash controller](https://github.com/ZipCPU/qspiflash), the [SD-card controller](https://github.com/ZipCPU/sdspi), the [block RAM controller](https://github.com/ZipCPU/openarty/blob/master/rtl/memdev.v), the [RMII Ethernet Controller](https://github.com/ZipCPU/openarty/blob/master/rtl/enetpackets.v), the [Real-Time Clock](https://github.com/ZipCPU/rtcclock), the [Real-Time Date](https://github.com/ZipCPU/rtcclock/blob/master/rtl/rtcdate.v), the [Organic LED controller](https://github.com/ZipCPU/openarty/blob/master/rtl/wboled.v), Xilinx's [Internal Configuration Access Port](https://github.com/ZipCPU/wbicapetwo), the [wishbone scope](https://github.com/ZipCPU/wbscope), the [GPS controlled clock](https://github.com/ZipCPU/openarty/blob/master/rtl/gpsclock.v), or even the [PWM Audio Controller](https://github.com/ZipCPU/wbpwmaudio). All of these peripherals have a very similar format when included within a top level design, all of these require a certain amount of care and feeding as part of that top level design, but yet rebuilding that top level design over and over just to repeat this information becomes a pain. Where things were really starting to get annoying is where the C++ information was depending upon Verilog information. A classic example of this is the base address of any bus components. However, if you add clock rate into the mix, you can then also control things such as any default UART configuration, default clock stepping information (for the RTC clock), or even default video clock information--just by knowing the FPGA's clock rate within your C++ environment. Sharing information between Verilog and C++ then became one of the primary reasons for creating AutoFPGA. While peripheral address decoding is typically done in some [main Verilog file](https://github.com/ZipCPU/openarty/blob/master/rtl/main.v), other files depend upon what this peripheral decoding is. These other files include the [host register definition file](https://github.com/ZipCPU/openarty/blob/master/sw/host/regdefs.h) (used for debugging access), the [register naming file](https://github.com/ZipCPU/openarty/blob/master/sw/host/regdefs.cpp), the [software board definition file](https://github.com/ZipCPU/openarty/blob/master/sw/zlib/board.h) used by newlib, the [linker script](https://github.com/ZipCPU/openarty/blob/master/sw/board/board.ld) used by the compiler, and even the [LaTeX specification](https://github.com/ZipCPU/openarty/blob/master/doc/src/spec.tex) for the board. Creating and updating all of these files by hand anytime I create a new board file can get tedious. Further, every time a board is reconfigured, the constraints file, whether [XDC](https://github.com/ZipCPU/openarty/blob/master/arty.xdc) or [UCF](https://github.com/ZipCPU/xulalx25soc/blob/master/xula.ucf) file, needs to be updated to match the current constraints. Solving this multi-language coordination problem is the purpose of AutoFPGA. Unlike many of the other tools out there, such as Xilinx's board design flow, AutoFPGA is not built with the clueless beginner in mind, neither is it built to hide the details of what is going within the project it creates. Instead, AutoFPGA is built with the sole purpose of alleviating any burden on the FPGA designer who otherwise has to create and maintain coherency between multiple design files. That this program facilitates composing and building new designs from existing components ... is just a bonus. # Goal The goal of AutoFPGA is to be able to take a series of bus component configuration files and to compose a design consisting of the various bus components, linked together in logic, having an appropriate bus interconnect and more. From a user's point of view, one would run AutoFPGA with a list of component definition files, given on the command line, and to thus be able to generate (or update?) the various design files discussed above: - [rtl/toplevel.v](demo-out/toplevel.v) - [rtl/main.v](demo-out/main.v) - [rtl/make.inc](demo-out/rtl.make.inc) - [rtl/iscachable.v](demo-out/iscachable.v) -- a function of bus address determining what addresses are cachable and which are not - [sw/host/regdefs.h](demo-out/regdefs.h) - [sw/host/regdefs.cpp](demo-out/regdefs.cpp) - [sw/zlib/board.h](demo-out/board.h) - [sw/zlib/board.ld](demo-out/board.ld) - [build.xdc](demo-out/build.xdc) (Created by modifying an existing XDC file. LPF, PCF, and UCF files are also supported) - [sim/verilated/testb.h](demo-out/testb.h) - [sim/verilated/main_tb.h](demo-out/main_tb.cpp) - doc/src/(component name).tex (Not started yet) Specifically, the parser must determine: - If any of the components used in the project need to be configured, and if so, what the configuration parameters are and how they need to be set. For example, the UART baud rate and RTC and GPS clock steps both need to be set based upon the actual clock speed of the master clock. Placing [a clock module](auto-data/clock.txt) within the design that sets up a clock and declares its rate is the current method for accomplishing this. Designs using more than one clock often have an [allclocks.txt](https://github.com/ZipCPU/openarty/autodata/allclocks.txt) file to define all of the various clocks used within a design. - If peripherals have or create interrupts, those need to be found and determined, and (even better) wired up. - If an AutoFPGA configuration file describes one of the following classes of items, then the file is wired up and connected to create the necessary bus wiring as well. * Bus masters Are automatically connected to a crossbar with full access to all of the slaves on the bus * One-clock Peripherals (interrupt controller, etc.) * Two-clock Peripherals (RTC clock, block RAM, scopes, etc.) * Memory Peripherals o These need a line within the linker script, and they need to define if their memory region, within that linker script, has read, write, or o Generic Peripherals ([flash](auto-data/flash.txt), SDRAM, [MDIO](auto-data/mdio.txt), etc.) - Peripheral files need to be able to describe more than one peripheral. For example, the [GPS peripheral file](auto-data/gps.txt) has a GPS-Clock, a companion test bench, GPS-TB, to measure the performance of the GPS clock, and a serial port ([WBUART](https://github.com/ZipCPU/wbuart32)) to allow us to read from the GPS and to write to it and so configure it. Of course ... this also includes a parameter that must be set (baud rate) based upon the global clock rate. ## Classes Some peripherals might exist at multiple locations within a design. For example, the WBUART serial component can be used to create multiple serial ports within a design. To handle this case, the WBUART configuration file may be subclassed within other component configuration files by defining a key @INCLUDEFILE=[wbuart.txt](auto-data/wbuart.txt). This will provide a set of keys that the current file can then override (inherit from). Unfortunately, this only works if the included file has only one component defined within it. ## Math Some peripherals need to be able to perform basic integer math on a given value to determine an appropriate setting value. These peripherals need access to variables. The classic examples are the baud rate, which depends upon the clock rate, as well as the step size necessary for the RTC and the GPS clocks, both of which also depend upon the master clock rate. Other examples might include determining the size of the address space to assign to a core based upon the memory size of the component and so forth. This feature is currently fully supported using integer math. ## Legacy Updates The original version of AutoFPGA supported only one bus master, one bus type, and an interconnect with a known bug in it. Specifically, the broken interconnect would allow a master to make requests of one peripheral and then another before the first peripheral had responded, while not preventing the requests from returning out of order. Fixing this bug introduced several incompatible changes, therefore there is an AutoFPGA `legacy` git tag defined to get back to the older version. This newer version, however, now supports: - Multiple bus types: [Wishbone (pipelined)](sw/bus/wb.cpp), [AXI-Lite](sw/bus/axil.cpp), and [AXI](sw/bus/axi.cpp) Additional busses may be supported by simply creating a C++ bus component definition class for them. - Full crossbar support, using bus helper files from my [WB2AXIP](https://github.com/ZipCPU/wb2axip) repository. Much to my surprise, the full crossbar support has proved to be simpler, in terms of logic elements used, than the legacy interconnect I had been using. # Status This project now has several designs built around it. These include the [basic AutoFPGA-demo](https://github.com/ZipCPU/autofpga-demo) project, [OpenArty](https://github.com/ZipCPU/openarty), [ArrowZip](https://github.com/ZipCPU/arrowzip) (legacy AutoFPGA only), [AXI DMA test bench](https://github.com/ZipCPU/axidmacheck), [ICOZip](https://github.com/ZipCPU/icozip), [SDR](https://github.com/ZipCPU/sdr) (a gateware defined radio), [ZBasic](https://github.com/ZipCPU/zbasic), [ZipStorm-mx](https://github.com/ZipCPU/zipstormmx) (legacy AutoFGPA only), and [ZipVersa](https://github.com/ZipCPU/zipversa). There's also a rather nice [Nexys Video project](https://github.com/ZipCPU/videozip) that I've used for modifying and delivering to customers, although the current version on github is currently a touch out of date. You can see the autogenerated logic generated for this project in the [demo directory](demo-out/). I've also used AutoFPGA to generate a design for the Cyclone-V on the DE-10 Nano, as well as a design for an [Arty Z7-20](https://github.com/ZipCPU/openz7). In sum: - Simple bus components ... just work. This includes both bus masters and bus slaves. Not only that, the bus simplifier logic also "just works", with the caveat below. Note that the AXI SINGLE simplifier itself hasn't (yet) been built. (It's waiting on a funded need.) For now, the [AXI DOUBLE bus simplifier](https://github.com/ZipCPU/wb2axip/blob/master/rtl/axidouble.v) should work quite well. To use it, just declare a bus slave to be a slave of an AXI type bus, with SLAVE.TYPE set to SINGLE, then follow the rule listed in the [simplifier](https://github.com/ZipCPU/wb2axip/blob/master/rtl/axidouble.v). The same applies to the AXI-lite simplifiers. Wishbone simplifiers, both SINGLE and DOUBLE, are handled by logic inserted into `main.v`, rather than referenced by `main.v`. - Components with logic in the toplevel work nicely as well. - AutoFPGA can now support multiple, dissimilar clock rates. Users just need to specify a clock to generate it. The clock is then made available for configuration files to reference. This includes creating a test bench wrapper for Verilator that will drive a multi-clock simulation. - Addresses get assigned in three groups, and processed in three groups: simple `SINGLE` components having only one address, simple `DOUBLE` components having more addresses but only a single clock delay, and all other components and memories. - Multiple bus support is now included, allowing you to create and attach components through bus adapters. This will allow a request to transition from one component to the next, while also keeping track of what the final addresses are for reference from the top level bus. This makes it possible for the SDRAM to be on one bus, supporting video reads/writes, and for the CPU to be able to access that bus as well--as a sub-bus of the main peripheral/memory bus. - Interrupts get assigned to a named controller, and then C++ header files are updated to reflect the interrupt assignments - A simple integer mathematical expression evaluator exists, allowing simple math expressions and print formats. This makes it possible to set a global clock frequency value, and to then set baud rates and other clock dividers from it. - Only one type of address building is supported. I'd like to be able to support others, but so far this has been sufficient for my first project. o Likewise, the project only supports WB B4/pipelined. No support is provided for WB B3/classic (yet), although creating such support shoud not be difficult at all. - AutoFPGA now builds a [ZipCPU Linker Script](demo-out/board.ld) for the project. This script is highly configurable, and many of my projects contain configurations for multiple linker scripts--depending upon which memories I decide to include in the design, or which ones I want a particular piece of software to use. - The LaTeX specification table building isn't there ... yet. # Sample component files Component files now exist for many of the components I've been using regularly. These include: a [Flash](auto-data/flash.txt) controller, [block RAM](auto-data/bkram.txt), a [UART console](auto-data/wbuart.txt), a very simple [GPIO controller](auto-data/gpio.txt), [RMII ethernet controller](auto-data/enet.txt), [MDIO ethernet control interface](auto-data/mdio.txt), a [GPS UART and PPS-driven internal clock](auto-data/gps.txt), a [Real-Time (GPS driven) Clock](auto-data/rtcgps.txt), a [PS/2 Mouse](auto-data/wbmouse.txt), an [OLED component](auto-data/wboledbw.txt), and more. Many of these component cores exist and have their own repositories elsewhere. For example, the wishbone UART core may be found [here](https://github.com/ZipCPU/wbuart32), and you can find a [MIG-based, Wishbone controlled SDRAM component here](https://github.com/ZipCPU/openarty/blob/master/autodata/sdram.txt). You can also find a AXI examples, such as [AXI S2MM stream-to-memory data mover](https://github.com/ZipCPU/axidmacheck/blob/master/autodata/axis2mm.txt), an [AXI MM2S memory-to-stream data mover](https://github.com/ZipCPU/axidmacheck/blob/master/autodata/axis2mm.txt), or an [AXM block RAM component](https://github.com/ZipCPU/axidmacheck/blob/master/autodata/axiram.txt) in the [AXI DMA test repository](https://github.com/ZipCPU/axidmacheck). Building the cores themselves is not a part of this project, but rather figuring out how to compose multiple cores into a top level design from both cores and component descriptions. # The ZipCPU blog Several articles have now been written to date about AutoFPGA on the ZipCPU blog. These includes: 1. [A brief introduction to AutoFPGA](https://zipcpu.com/zipcpu/2017/10/05/autofpga-intro.html) 2. [Using AutoFPGA to connect simple registers to a debugging bus](https://zipcpu.com/zipcpu/2017/10/06/autofpga-dataword.html) This article is really out of date, in that it describes only the legacy mode (one master, one bus type, etc.) 3. [AutoFPGA's linker script support gets an update](https://zipcpu.com/zipcpu/2018/12/22/autofpga-ld.html) 4. [Technology debt and AutoFPGA, the bill just came due](https://zipcpu.com/zipcpu/2019/08/22/tech-debt.html) 5. [Understanding AutoFPGA's address assignment algorithm](https://zipcpu.com/zipcpu/2019/09/03/address-assignment.html) # Getting Started The current best reference for AutoFPGA is the [icd.txt](doc/icd.txt) file, which describes all of the various tags AutoFPGA understands and how they can be used. I've also started working on an [intermediate design](https://zipcpu.com/tutorial/intermediate.html) tutorial based around AutoFPGA, so you might find that a useful place to start as well. # License AutoFPGA is designed for release under the GPLv3 license. The AutoFPGA generated code is yours, and free to be relicensed as you see fit. # Commercial Applications Should you find the GPLv3 license insufficient for your needs, other licenses can be purchased from Gisselquist Technology, LLC. Given that the AutoFPGA generated code is not encumbered by any license requirements, I really don't expect any such requests. Likewise, please contact us should you wish to guide, direct, or otherwise fund the development of this project. You can contact me at my user name, dgisselq, at the wonderful ieee.org host. ================================================ FILE: auto-data/allclocks.txt ================================================ ################################################################################ ## ## Filename: auto-data/allclocks.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Describe how to create the clocks necessary for the design ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2015-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=iclock @ACCESS=ALLCLOCKS_PRESENT @CLOCK.NAME=clk @CLOCK.WIRE=i_clk @CLOCK.FREQUENCY=100000000 @CLOCK.TOP=i_clk @BDEFS.DEFN= #define CLOCK_FREQUENCY_HZ @$(CLOCK.FREQUENCY) #define CLKFREQHZ @$(CLOCK.FREQUENCY) @REGDEFS.H.DEFNS= #define CLKFREQHZ @$(CLOCK.FREQUENCY) # # @PREFIX=masterclk @TOP.DEFNS= // Clock/reset definitions // {{{ wire s_clk_200mhz, s_clk_200mhz_unbuffered, sysclk_locked, sysclk_feedback, sysclk_feedback_buffered, s_clk_250mhz, s_clk_250_unbuffered, s_clk_125mhz, s_clk_125_unbuffered, s_clk_125d, s_clk_125d_unbuffered, s_clksync, s_clksync_unbuffered, s_clk_400mhz, s_clk_400mhz_unbuffered, // Pixclk * 10 s_clk_80mhz_unbuffered, // 80MHz netclk_locked, netclk_feedback, netclk_feedback_buffered; wire i_clk_buffered; wire clocks_locked; wire dly_ctrl_ready; reg [3:0] sysclk_stable, syncd_stable; reg [4:0] pll_reset_sreg; reg pll_reset; // }}} @TOP.PORTLIST= @TOP.IODECL= @TOP.MAIN= // PLL generated clocks s_clk_125mhz @TOP.INSERT= // Buffer the incoming clock BUFG @$(PREFIX)clkbufi(.I(i_clk), .O(i_clk_buffered)); // pll_reset initial { pll_reset, pll_reset_sreg } = -1; always @(posedge i_clk_buffered) { pll_reset, pll_reset_sreg } <= { pll_reset_sreg, 1'b0 }; //////////////////////////////////////////////////////////////////////// // // PLL #1: 100MHz, 200MHz, 400MHz, and 80MHz // {{{ //////////////////////////////////////////////////////////////////////// // // // But ... the delay controller requires a 200 MHz reference clock, // the generic clock generator requires a 400MHz clock and a clock // synchronized to it PLLE2_BASE #( // {{{ .CLKFBOUT_MULT(8), .CLKFBOUT_PHASE(0.0), .CLKIN1_PERIOD(10), .CLKOUT0_DIVIDE(4), // 200 MHz .CLKOUT1_DIVIDE(2), // 400 MHz .CLKOUT2_DIVIDE(8), // 100 MHz .CLKOUT3_DIVIDE(10) // 80 MHz // }}} ) gen_sysclk( // {{{ .CLKIN1(i_clk_buffered), .CLKOUT0(s_clk_200mhz_unbuffered), .CLKOUT1(s_clk_400mhz_unbuffered), .CLKOUT2(s_clksync_unbuffered), .CLKOUT3(s_clk_80mhz_unbuffered), // .CLKOUT4(), // .CLKOUT5(), .PWRDWN(1'b0), .RST(pll_reset), .CLKFBOUT(sysclk_feedback), .CLKFBIN(sysclk_feedback_buffered), .LOCKED(sysclk_locked) // }}} ); BUFG sysbuf( .I(s_clk_200mhz_unbuffered),.O(s_clk_200mhz)); BUFG clksync_buf(.I(s_clksync_unbuffered), .O(s_clksync)); BUFG clk4x_buf( .I(s_clk_400mhz_unbuffered),.O(s_clk_400mhz)); BUFG sys_feedback(.I(sysclk_feedback),.O(sysclk_feedback_buffered)); // }}} //////////////////////////////////////////////////////////////////////// // // PLL #2: 125MHz, 250MHz // {{{ //////////////////////////////////////////////////////////////////////// // // // The ethernet MAC requires a 125MHz clock // We can't trust the RX 125MHz clock for this, since there's a // possibility the RX 125MHz clock might arrive at a different rate. // PLLE2_BASE #( // {{{ .CLKFBOUT_MULT(10), .CLKFBOUT_PHASE(0.0), .CLKIN1_PERIOD(10), .CLKOUT0_DIVIDE(8), // 125 MHz .CLKOUT0_PHASE(0), .CLKOUT1_DIVIDE(4), // 250 MHz .CLKOUT1_PHASE(0) // }}} ) gen_netclk( // {{{ .CLKIN1(i_clk_buffered), .CLKOUT0(s_clk_125_unbuffered), .CLKOUT1(s_clk_250_unbuffered), // .CLKOUT2(), // .CLKOUT3(), // .CLKOUT4(), // .CLKOUT5(), .PWRDWN(1'b0), .RST(pll_reset), .CLKFBOUT(netclk_feedback), .CLKFBIN(netclk_feedback_buffered), .LOCKED(netclk_locked) // }}} ); BUFG netbuf(.I(s_clk_125_unbuffered), .O(s_clk_125mhz)); BUFG netbf5(.I(s_clk_250_unbuffered), .O(s_clk_250mhz)); BUFG netfb(.I(netclk_feedback), .O(netclk_feedback_buffered)); assign clocks_locked = (netclk_locked && sysclk_locked && dly_ctrl_ready); // }}} //////////////////////////////////////////////////////////////////////// // // reg [3:0] sysclk_stable; // {{{ initial sysclk_stable = 0; always @(posedge i_clk_buffered or negedge clocks_locked) if (!clocks_locked) sysclk_stable <= 0; else sysclk_stable <= { sysclk_stable[2:0], 1'b1 }; initial syncd_stable = 0; always @(posedge i_clk_buffered) if (!sysclk_stable[3]) syncd_stable <= 0; else syncd_stable <= { syncd_stable[2:0], 1'b1 }; // }}} //////////////////////////////////////////////////////////////////////// // // IDELAYCTRL IDELAYCTRL u_delay_control ( .REFCLK(s_clk_200mhz), .RST(!sysclk_locked), .RDY(dly_ctrl_ready) ); @MAIN.PORTLIST= // Extra clocks i_clk_125mhz @MAIN.IODECL= // Extra clocks // Verilator lint_off UNUSED input wire i_clk_125mhz; // Verilator lint_on UNUSED @MAIN.DEFNS= wire i_net_tx_clk; @MAIN.INSERT= assign i_net_tx_clk = i_clk_125mhz; @CLOCK.WIRE=i_clk_125mhz @CLOCK.NAME=clk_125mhz @CLOCK.FREQUENCY=125000000 @CLOCK.TOP= @MAIN.IODECL= input wire i_net_tx_clk; @XDC.INSERT= set_false_path -from [get_cells -hier -filter {NAME=~ pll_reset*}] -to [get_cells -hier -filter {NAME=~ net*/reset_pipe*}] set_false_path -from [get_cells -hier -filter {NAME=~ pll_reset*}] -to [get_cells -hier -filter {NAME=~ net*/sync_reset*}] ================================================ FILE: auto-data/bkram.txt ================================================ ################################################################################ ## ## Filename: auto-data/bkram.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To define the interface to a generic block RAM device for the ## purposes of autofpga. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=bkram @DEVID=BKRAM @$LGMEMSZ=20 @LGMEMSZ.FORMAT=%d @$NADDR=(1<<(@$(THIS.LGMEMSZ)))/(@$(SLAVE.BUS.WIDTH)/8) @$NBYTES=(1<<(@$THIS.LGMEMSZ)) @NBYTES.FORMAT=0x%08x @ACCESS=@$(DEVID)_ACCESS @SLAVE.TYPE=MEMORY @SLAVE.BUS=wbwide @MAIN.INSERT= memdev #( .LGMEMSZ(@$(THIS.LGMEMSZ)), .DW(@$(SLAVE.BUS.WIDTH)), .EXTRACLOCK(1) ) u_@$(PREFIX) ( .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), .i_reset(@$(SLAVE.BUS.CLOCK.RESET)), @$(SLAVE.ANSIPORTLIST) ); @REGS.N=1 @REGS.0= 0 R_@$(DEVID) RAM @REGDEFS.H.DEFNS= #define @$(DEVID)BASE @$[0x%08x](REGBASE) #define @$(DEVID)LEN @$NBYTES @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @MEM.NAME= @$(PREFIX) @BDEF.OSVAL=extern char _@$(MEM.NAME)[@$NBYTES]; @LD.PERM= wx @LD.NAME= @$(MEM.NAME) @RTL.MAKE.GROUP= @$(DEVID) @RTL.MAKE.SUBD= @RTL.MAKE.FILES= memdev.v @$NADDRHX = @$NADDR @NADDRHX.FORMAT= 0x%x @SIM.INCLUDE= #include "byteswap.h" @SIM.DEFINES= #ifndef VVAR #ifdef ROOT_VERILATOR #include "Vmain___024root.h" #define VVAR(A) rootp->main__DOT_ ## A #elif defined(NEW_VERILATOR) #define VVAR(A) main__DOT_ ## A #else #define VVAR(A) v__DOT_ ## A #endif #endif #define block_ram rootp->main__DOT__u_@$(PREFIX)__DOT__mem.m_storage @$BUSBYTES=@$(SLAVE.BUS.WIDTH)/8 @SLAVE.ORDER=1 @SIM.LOAD= start = start & (-4); wlen = (wlen+3)&(-4); // Need to byte swap data to get it into the memory if (@$(SLAVE.BUS.WIDTH) == 32) { char *bswapd = new char[len+8]; memcpy(bswapd, &buf[offset], wlen); byteswapbuf(len>>2, (uint32_t *)bswapd); memcpy(&m_core->block_ram[start], bswapd, wlen); delete[] bswapd; } else { for(unsigned jk=0; jkblock_ram[word_addr]; cp = (char *)wp; subword_addr = start+jk; subword_addr = ~subword_addr; subword_addr &= @$(SLAVE.BUS.WIDTH)/8-1; // subword_addr = @$(SLAVE.BUS.WIDTH)/8-subword_addr; cp[subword_addr] = buf[offset+jk]; } } ================================================ FILE: auto-data/buserr.txt ================================================ ################################################################################ ## ## Filename: auto-data/buserr.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Provide a readable memory location containing the address of the ## last bus error. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=buserr @NADDR=1 @SLAVE.TYPE=SINGLE @SLAVE.BUS=wb32 @SINGLE.INPUT= r_bus_err @CLOCK.NAME=clk @$RWID=(@$(zip.MASTER.BUS.AWID) > @$(wbu.MASTER.BUS.AWID)) ? @$(zip.MASTER.BUS.AWID) : @$(wbu.MASTER.BUS.AWID) @MAIN.DEFNS= reg [@$(RWID)-1:0] r_@$(PREFIX)_addr; @MAIN.INSERT= always @(posedge @$(CLOCK.WIRE)) if (@$(zip.MASTER.PREFIX)_err) begin r_@$(PREFIX)_addr <= 0; r_@$(PREFIX)_addr[@$(zip.MASTER.BUS.AWID)-1:0] <= @$(zip.MASTER.PREFIX)_addr[@$(zip.MASTER.BUS.AWID)-1:0]; end else if (@$(wbu.MASTER.PREFIX)_err) begin r_@$(PREFIX)_addr <= 0; r_@$(PREFIX)_addr[@$(wbu.MASTER.BUS.AWID)-1:0] <= @$(wbu.MASTER.PREFIX)_addr[@$(wbu.MASTER.BUS.AWID)-1:0]; end assign @$(SLAVE.PREFIX)_stall= 1'b0; assign @$(SLAVE.PREFIX)_ack = @$(SLAVE.PREFIX)_stb; assign @$(SLAVE.PREFIX)_idata = { {(30-@$(RWID)){1'b0}}, r_@$(PREFIX)_addr, 2'b00 }; @REGS.N=1 @REGS.0= 0 R_BUSERR BUSERR @BDEF.IONAME=io_buserr @BDEF.IOTYPE=unsigned @BDEF.OSDEF=_BOARD_HAS_BUSERR @BDEF.OSVAL=static volatile @$THIS.BDEF.IOTYPE *const _buserr = ((@$THIS.BDEF.IOTYPE *)@$[0x%08x](REGBASE)); ================================================ FILE: auto-data/clkcheck.txt ================================================ ################################################################################ ## ## Filename: auto-data/clkcheck.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To describe the clkcounter's interface for autofpga to work ## with. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=rtc_pps @MAIN.DEFNS= // Verilator lint_off UNUSED reg @$(PREFIX); reg [26:0] @$(PREFIX)_counter; // Verilator lint_on UNUSED @MAIN.INSERT= initial @$(PREFIX) = 1'b0; initial @$(PREFIX)_counter = 0; always @(posedge i_clk) if (@$(PREFIX)_counter > 0) begin @$(PREFIX)_counter <= @$(PREFIX)_counter - 1; @$(PREFIX) <= 1'b0; end else begin @$(PREFIX)_counter <= 27'd100_000_000 - 1; @$(PREFIX) <= 1'b1; end @PREFIX=rxeth0ck @DEVID=RXETH0CK @INCLUDEFILE=clkcounter.txt @TSTCLOCK=i_eth0_rx_clk @DEPENDS=MEGANET_ACCESS ## @PREFIX=txclk @DEVID=TXCLK @INCLUDEFILE=clkcounter.txt @DEPENDS=ALLCLOCKS_PRESENT @TSTCLOCK=i_net_tx_clk ## @PREFIX=adcclk @DEVID=ADCCLK @INCLUDEFILE=clkcounter.txt @DEPENDS=ALLCLOCKS_PRESENT @TSTCLOCK=i_clk_200mhz ## ## @PREFIX=pixclk ## @DEVID=PIXCLK ## @INCLUDEFILE=clkcounter.txt ## @DEPENDS=ALLCLOCKS_PRESENT ## @TSTCLOCK=i_pixclk ## ## @PREFIX=audioclk ## @DEVID=AUDIOCLK ## @INCLUDE=clkcounter.txt ## @TSTCLOCK=i_pixclk ================================================ FILE: auto-data/clkcounter.txt ================================================ ################################################################################ ## ## Filename: auto-data/clkcounter.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: The clkcounter peripheral counts the number of a given clocks ## ticks per second as defined by a second clock. This particular ## file tells us how to connect the clkcounter to the rest of the design ## using AutoFPGA. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=sysclk @DEVID=SYSCLK @ACCESS=@$(DEVID) @NADDR= 1 @SLAVE.TYPE= SINGLE @SLAVE.BUS=wb32 @TSTCLOCK=i_clk # @SINGLE.INPUTS= ck_pps @MAIN.DEFNS= reg r_@$(PREFIX)_ack; @MAIN.INSERT= clkcounter #( .CLOCKFREQ_HZ(0) // We'll count PPS externally ) clk@$(PREFIX)ctr( .i_sys_clk(i_clk), .i_tst_clk(@$(TSTCLOCK)), .i_sys_pps(rtc_pps), .o_sys_counts(@$(SLAVE.PREFIX)_idata) ); initial r_@$(PREFIX)_ack = 0; always @(posedge i_clk) r_@$(PREFIX)_ack <= !i_reset && @$(SLAVE.PREFIX)_stb; assign @$(SLAVE.PREFIX)_ack = r_@$(PREFIX)_ack; assign @$(SLAVE.PREFIX)_stall = 1'b0; @REGS.NOTE = // SYSCLK Clock Counter (measures clock speed) @REGS.N = 1 @REGS.0 = 0 R_@$(DEVID) @$(DEVID) @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE= unsigned @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); @XDC.INSERT= set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *clk@$(PREFIX)ctr/avgs*}] -to [ get_cells -hier -filter {NAME =~*clk@$(PREFIX)ctr/q_v*}] 8.0 ================================================ FILE: auto-data/crossbus.txt ================================================ ################################################################################ ## ## Filename: auto-data/crossbus.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Provides access to the smaller 32-bit bus from the 512-bit bus. ## Accesses are limited to a single controller only, but perhaps ## this is okay since I don't expect anything but the CPU and the debugging ## port to control the 32-bit bus. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=crossbus @SLAVE.TYPE=BUS @SLAVE.BUS=wbwide @SLAVE.ANSPREFIX=w @SLAVE.ORDER=0 @ERROR.WIRE=@$(SLAVE.PREFIX)_err ## @$SLAVE.AWID=@$(MASTER.AWID) >> (@$(SLAVE.BUS_WIDTH)-@$(MASTER.BUS.WIDTH)) @MASTER.TYPE=SUBBUS @MASTER.BUS=wb32 @OPT_LITTLE_ENDIAN=1'b0 @OPT_LOWLOGIC=1'b0 @MAIN.INSERT= wbdown #( // {{{ // Slave bus address width: @$(SLAVE.BUS.AWID) // Slave address width : @$(SLAVE.AWID) // Master address width : @$(MASTER.BUS.AWID) .ADDRESS_WIDTH(@$(SLAVE.AWID)+$clog2(@$(SLAVE.BUS.WIDTH)/8)), .WIDE_DW(@$(SLAVE.BUS.WIDTH)), .SMALL_DW(@$(MASTER.BUS.WIDTH)), .OPT_LITTLE_ENDIAN(@$(OPT_LITTLE_ENDIAN)), .OPT_LOWLOGIC(@$(OPT_LOWLOGIC)) // }}} ) u_@$(PREFIX) ( // {{{ .i_clk(@$(MASTER.BUS.CLOCK.WIRE)), .i_reset(@$(MASTER.BUS.CLOCK.RESET)), // Slave/incoming // {{{ .i_wcyc( @$(SLAVE.PREFIX)_cyc), .i_wstb( @$(SLAVE.PREFIX)_stb), .i_wwe( @$(SLAVE.PREFIX)_we), .i_waddr( @$(SLAVE.PREFIX)_addr[@$(SLAVE.AWID)-1:0]), .i_wdata( @$(SLAVE.PREFIX)_data), .i_wsel( @$(SLAVE.PREFIX)_sel), .o_wstall(@$(SLAVE.PREFIX)_stall), .o_wack( @$(SLAVE.PREFIX)_ack), .o_wdata( @$(SLAVE.PREFIX)_idata), .o_werr( @$(SLAVE.PREFIX)_err), // }}} // Master/down-range/outgoing // {{{ .o_scyc( @$(MASTER.PREFIX)_cyc), .o_sstb( @$(MASTER.PREFIX)_stb), .o_swe( @$(MASTER.PREFIX)_we), .o_saddr( @$(MASTER.PREFIX)_addr[@$(MASTER.BUS.AWID)-1:0]), .o_sdata( @$(MASTER.PREFIX)_data), .o_ssel( @$(MASTER.PREFIX)_sel), .i_sstall(@$(MASTER.PREFIX)_stall), .i_sack( @$(MASTER.PREFIX)_ack), .i_sdata( @$(MASTER.PREFIX)_idata), .i_serr( @$(MASTER.PREFIX)_err) // }}} // }}} ); ================================================ FILE: auto-data/ddr3.txt ================================================ ################################################################################ ## ## Filename: auto-data/ddr3.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To describe how to connect an open source DDR3 controller to ## the design, via the Wishbone bus. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} # Wishbone 1 @PREFIX=ddr3 @DEVID=SDRAM @ACCESS=@$(DEVID)_ACCESS ## LGMEMSZ is the size of the SDRAM in bytes. For a 1GB DDR3 RAM: 30 => 1GB @$LGMEMSZ=30 @LGMEMSZ.FORMAT=%d @$NADDR=(1<< @$(LGMEMSZ))/(@$(SLAVE.BUS.WIDTH)/8) @$NBYTES=(1<<(@$LGMEMSZ)) @NBYTES.FORMAT=0x%08x @$MADDR= @$(REGBASE) @MADDR.FORMAT=0x%08x @$NLANES=@$(SLAVE.BUS.WIDTH)/64 @SLAVE.TYPE=MEMORY @SLAVE.BUS=wbwide @SLAVE.ORDER=100 @BUS=wbwide @LD.PERM=wx @LD.NAME=sdram # @REGS.N=1 @REGS.0= 0 R_@$(DEVID) @$(DEVID) @REGDEFS.H.DEFNS= #define @$(DEVID)BASE @$[0x%08x](REGBASE) #define @$(DEVID)LEN @$(NBYTES) @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=extern char _@$(PREFIX)[@$NBYTES]; @TOP.PORTLIST= // DDR3 I/O port wires o_ddr3_reset_n, o_ddr3_cke, o_ddr3_clk_p, o_ddr3_clk_n, o_ddr3_vsel, o_ddr3_cs_n, o_ddr3_ras_n, o_ddr3_cas_n, o_ddr3_we_n, o_ddr3_ba, o_ddr3_a, o_ddr3_odt, o_ddr3_dm, io_ddr3_dqs_p, io_ddr3_dqs_n, io_ddr3_dq @TOP.PARAM= localparam real @$(DEVID)CONTROLLER_CLK_PERIOD = 10_000, //ps, clock period of the controller interface DDR3_CLK_PERIOD = 2_500; //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD) localparam @$(DEVID)ROW_BITS = 14, // width of row address @$(DEVID)COL_BITS = 10, // width of column address @$(DEVID)BA_BITS = 3, // width of bank address @$(DEVID)DQ_BITS = 8, // Size of one octet @$(DEVID)BYTE_LANES = @$(NLANES), //8 lanes of DQ @$(DEVID)AUX_WIDTH = 4, //width of aux line (must be >= 4) @$(DEVID)SERDES_RATIO = $rtoi(@$(DEVID)CONTROLLER_CLK_PERIOD/DDR3_CLK_PERIOD), //4 is the width of a single ddr3 command {cs_n, ras_n, cas_n, we_n} plus 3 (ck_en, odt, reset_n) plus bank bits plus row bits @$(DEVID)CMD_LEN = 4 + 3 + @$(DEVID)BA_BITS + @$(DEVID)ROW_BITS; @TOP.IODECL= // I/O declarations for the DDR3 SDRAM // {{{ output wire o_ddr3_reset_n; output wire [0:0] o_ddr3_cke; output wire [0:0] o_ddr3_clk_p, o_ddr3_clk_n; output wire [0:0] o_ddr3_cs_n; // o_ddr3_s_n[1] is set to 0 since controller only support single rank output wire o_ddr3_vsel; output wire [0:0] o_ddr3_ras_n, o_ddr3_cas_n, o_ddr3_we_n; output wire [@$(DEVID)BA_BITS-1:0] o_ddr3_ba; output wire [14:0] o_ddr3_a; //set to max of 16 bits, but only ROW_BITS bits are relevant output wire [0:0] o_ddr3_odt; output wire [@$(DEVID)BYTE_LANES-1:0] o_ddr3_dm; inout wire [(@$(DEVID)DQ_BITS*@$(DEVID)BYTE_LANES)/8-1:0] io_ddr3_dqs_p, io_ddr3_dqs_n; inout wire [(@$(DEVID)DQ_BITS*@$(DEVID)BYTE_LANES)-1:0] io_ddr3_dq; // }}} @TOP.DEFNS= wire s_clk, s_reset; reg [2:0] clk_reset_pipe; // Wires connected to PHY interface of DDR3 controller // {{{ genvar @$(PREFIX)gen_index; wire [@$(DEVID)DQ_BITS*@$(DEVID)BYTE_LANES*8-1:0] @$(PREFIX)_iserdes_data; wire [@$(DEVID)BYTE_LANES*8-1:0] @$(PREFIX)_iserdes_dqs, @$(PREFIX)_iserdes_bitslip_reference; wire [@$(DEVID)CMD_LEN*@$(DEVID)SERDES_RATIO-1:0] @$(PREFIX)_cmd; wire [@$(DEVID)DQ_BITS*@$(DEVID)BYTE_LANES*8-1:0] @$(PREFIX)_data; wire [(@$(DEVID)DQ_BITS*@$(DEVID)BYTE_LANES*8)/8-1:0] @$(PREFIX)_dm; wire [4:0] @$(PREFIX)_odelay_data_cntvaluein, @$(PREFIX)_odelay_dqs_cntvaluein, @$(PREFIX)_idelay_data_cntvaluein, @$(PREFIX)_idelay_dqs_cntvaluein; wire [@$(DEVID)BYTE_LANES-1:0] @$(PREFIX)_odelay_data_ld, @$(PREFIX)_odelay_dqs_ld, @$(PREFIX)_idelay_data_ld, @$(PREFIX)_idelay_dqs_ld, @$(PREFIX)_bitslip, @$(PREFIX)_debug_read_dqs_p, @$(PREFIX)_debug_read_dqs_n; wire @$(PREFIX)_idelayctrl_rdy, @$(PREFIX)_dqs_tri_control, @$(PREFIX)_dq_tri_control, @$(PREFIX)_toggle_dqs, @$(PREFIX)_write_leveling_calib, @$(PREFIX)_reset; wire @$(PREFIX)_debug_clk_p, @$(PREFIX)_debug_clk_n; // }}} @TOP.MAIN= // DDR3 Controller-PHY Interface @$(PREFIX)_iserdes_data, @$(PREFIX)_iserdes_dqs, @$(PREFIX)_iserdes_bitslip_reference, @$(PREFIX)_idelayctrl_rdy, @$(PREFIX)_cmd, @$(PREFIX)_dqs_tri_control, @$(PREFIX)_dq_tri_control, @$(PREFIX)_toggle_dqs, @$(PREFIX)_data, @$(PREFIX)_dm, @$(PREFIX)_odelay_data_cntvaluein, @$(PREFIX)_odelay_dqs_cntvaluein, @$(PREFIX)_idelay_data_cntvaluein, @$(PREFIX)_idelay_dqs_cntvaluein, @$(PREFIX)_odelay_data_ld, @$(PREFIX)_odelay_dqs_ld, @$(PREFIX)_idelay_data_ld, @$(PREFIX)_idelay_dqs_ld, @$(PREFIX)_bitslip, @$(PREFIX)_write_leveling_calib, @$(PREFIX)_reset @TOP.INSERT= assign s_clk = s_clksync; assign o_ddr3_vsel = 1'bz; always @(posedge s_clk or negedge clocks_locked) if (!clocks_locked) clk_reset_pipe <= 3'h7; else clk_reset_pipe <= { clk_reset_pipe[1:0], 1'b0 }; assign s_reset = clk_reset_pipe[2]; // DDR3 PHY Instantiation ddr3_phy #( // {{{ .ROW_BITS(@$(DEVID)ROW_BITS), //width of row address .BA_BITS(@$(DEVID)BA_BITS), //width of bank address .DQ_BITS(@$(DEVID)DQ_BITS), //width of DQ .LANES(@$(DEVID)BYTE_LANES), //8 lanes of DQ .CONTROLLER_CLK_PERIOD(@$(DEVID)CONTROLLER_CLK_PERIOD), //ns, period of clock input to this DDR3 controller module .DDR3_CLK_PERIOD(DDR3_CLK_PERIOD), //ns, period of clock input to DDR3 RAM device .ODELAY_SUPPORTED(1) // }}} ) ddr3_phy_inst ( // {{{ // clock and reset .i_controller_clk(s_clksync), .i_ddr3_clk(s_clk_400mhz), .i_ref_clk(s_clk_200mhz), .i_ddr3_clk_90(0), //required only when ODELAY_SUPPORTED is zero .i_rst_n(!s_reset), // Controller Interface .i_controller_reset(@$(PREFIX)_reset), .i_controller_cmd(@$(PREFIX)_cmd), .i_controller_dqs_tri_control(@$(PREFIX)_dqs_tri_control), .i_controller_dq_tri_control(@$(PREFIX)_dq_tri_control), .i_controller_toggle_dqs(@$(PREFIX)_toggle_dqs), .i_controller_data(@$(PREFIX)_data), .i_controller_dm(@$(PREFIX)_dm), .i_controller_odelay_data_cntvaluein(@$(PREFIX)_odelay_data_cntvaluein), .i_controller_odelay_dqs_cntvaluein(@$(PREFIX)_odelay_dqs_cntvaluein), .i_controller_idelay_data_cntvaluein(@$(PREFIX)_idelay_data_cntvaluein), .i_controller_idelay_dqs_cntvaluein(@$(PREFIX)_idelay_dqs_cntvaluein), .i_controller_odelay_data_ld(@$(PREFIX)_odelay_data_ld), .i_controller_odelay_dqs_ld(@$(PREFIX)_odelay_dqs_ld), .i_controller_idelay_data_ld(@$(PREFIX)_idelay_data_ld), .i_controller_idelay_dqs_ld(@$(PREFIX)_idelay_dqs_ld), .i_controller_bitslip(@$(PREFIX)_bitslip), .i_controller_write_leveling_calib(@$(PREFIX)_write_leveling_calib), .o_controller_iserdes_data(@$(PREFIX)_iserdes_data), .o_controller_iserdes_dqs(@$(PREFIX)_iserdes_dqs), .o_controller_iserdes_bitslip_reference(@$(PREFIX)_iserdes_bitslip_reference), .o_controller_idelayctrl_rdy(@$(PREFIX)_idelayctrl_rdy), // DDR3 I/O Interface .o_ddr3_clk_p(o_ddr3_clk_p), .o_ddr3_clk_n(o_ddr3_clk_n), .o_ddr3_reset_n(o_ddr3_reset_n), .o_ddr3_cke(o_ddr3_cke[0]), // CKE .o_ddr3_cs_n(o_ddr3_cs_n[0]), // chip select signal (controls rank 1 only) .o_ddr3_ras_n(o_ddr3_ras_n), // RAS# .o_ddr3_cas_n(o_ddr3_cas_n), // CAS# .o_ddr3_we_n(o_ddr3_we_n), // WE# .o_ddr3_addr(o_ddr3_a[@$(DEVID)ROW_BITS-1:0]), .o_ddr3_ba_addr(o_ddr3_ba), .io_ddr3_dq(io_ddr3_dq), .io_ddr3_dqs(io_ddr3_dqs_p), .io_ddr3_dqs_n(io_ddr3_dqs_n), .o_ddr3_dm(o_ddr3_dm), .o_ddr3_odt(o_ddr3_odt[0]), // on-die termination // DEBUG PHY .o_ddr3_debug_read_dqs_p(@$(PREFIX)_debug_read_dqs_p), .o_ddr3_debug_read_dqs_n(@$(PREFIX)_debug_read_dqs_n) // }}} ); generate for(@$(PREFIX)gen_index = @$(DEVID)ROW_BITS; @$(PREFIX)gen_index < 15; @$(PREFIX)gen_index = @$(PREFIX)gen_index + 1) begin : GEN_UNUSED_@$(DEVID)_ASSIGN assign o_ddr3_a[@$(PREFIX)gen_index] = 0; end endgenerate @MAIN.PORTLIST= // DDR3 Controller Interface i_@$(PREFIX)_iserdes_data, i_@$(PREFIX)_iserdes_dqs, i_@$(PREFIX)_iserdes_bitslip_reference, i_@$(PREFIX)_idelayctrl_rdy, o_@$(PREFIX)_cmd, o_@$(PREFIX)_dqs_tri_control, o_@$(PREFIX)_dq_tri_control, o_@$(PREFIX)_toggle_dqs, o_@$(PREFIX)_data, o_@$(PREFIX)_dm, o_@$(PREFIX)_odelay_data_cntvaluein, o_@$(PREFIX)_odelay_dqs_cntvaluein, o_@$(PREFIX)_idelay_data_cntvaluein, o_@$(PREFIX)_idelay_dqs_cntvaluein, o_@$(PREFIX)_odelay_data_ld, o_@$(PREFIX)_odelay_dqs_ld, o_@$(PREFIX)_idelay_data_ld, o_@$(PREFIX)_idelay_dqs_ld, o_@$(PREFIX)_bitslip, o_@$(PREFIX)_leveling_calib, o_@$(PREFIX)_reset @MAIN.PARAM=@$(TOP.PARAM) @MAIN.IODECL= // DDR3 Controller I/O declarations // {{{ input wire [@$(DEVID)DQ_BITS*@$(DEVID)BYTE_LANES*8-1:0] i_@$(PREFIX)_iserdes_data; input wire [@$(DEVID)BYTE_LANES*8-1:0] i_@$(PREFIX)_iserdes_dqs; input wire [@$(DEVID)BYTE_LANES*8-1:0] i_@$(PREFIX)_iserdes_bitslip_reference; input wire i_@$(PREFIX)_idelayctrl_rdy; output wire [@$(DEVID)CMD_LEN*@$(DEVID)SERDES_RATIO-1:0] o_@$(PREFIX)_cmd; output wire o_@$(PREFIX)_dqs_tri_control, o_@$(PREFIX)_dq_tri_control; output wire o_@$(PREFIX)_toggle_dqs; output wire [@$(DEVID)DQ_BITS*@$(DEVID)BYTE_LANES*8-1:0] o_@$(PREFIX)_data; output wire [(@$(DEVID)DQ_BITS*@$(DEVID)BYTE_LANES*8)/8-1:0] o_@$(PREFIX)_dm; output wire [4:0] o_@$(PREFIX)_odelay_data_cntvaluein, o_@$(PREFIX)_odelay_dqs_cntvaluein; output wire [4:0] o_@$(PREFIX)_idelay_data_cntvaluein, o_@$(PREFIX)_idelay_dqs_cntvaluein; output wire [@$(DEVID)BYTE_LANES-1:0] o_@$(PREFIX)_odelay_data_ld, o_@$(PREFIX)_odelay_dqs_ld; output wire [@$(DEVID)BYTE_LANES-1:0] o_@$(PREFIX)_idelay_data_ld, o_@$(PREFIX)_idelay_dqs_ld; output wire [@$(DEVID)BYTE_LANES-1:0] o_@$(PREFIX)_bitslip; output wire o_@$(PREFIX)_leveling_calib; output wire o_@$(PREFIX)_reset; // }}} @MAIN.DEFNS= // Verilator lint_off UNUSED wire [@$(DEVID)AUX_WIDTH-1:0] @$(PREFIX)_aux_out; wire [31:0] @$(PREFIX)_debug; // Verilator lint_on UNUSED @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // DDR3 Controller instantiation // {{{ ddr3_controller #( // {{{ .CONTROLLER_CLK_PERIOD(@$(DEVID)CONTROLLER_CLK_PERIOD), //ps, clock period of the controller interface .DDR3_CLK_PERIOD(DDR3_CLK_PERIOD), //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD) .ROW_BITS(@$(DEVID)ROW_BITS), //width of row address .COL_BITS(@$(DEVID)COL_BITS), //width of column address .BA_BITS(@$(DEVID)BA_BITS), //width of bank address .DQ_BITS(@$(DEVID)DQ_BITS), //width of DQ .LANES(@$(DEVID)BYTE_LANES), // byte lanes .AUX_WIDTH(@$(DEVID)AUX_WIDTH), //width of aux line (must be >= 4) .WB2_ADDR_BITS(7), //width of 2nd wishbone address bus .WB2_DATA_BITS(32), //width of 2nd wishbone data bus .MICRON_SIM(0), //simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW) .ODELAY_SUPPORTED(1), //set to 1 when ODELAYE2 is supported .SECOND_WISHBONE(1) //set to 1 if 2nd wishbone is needed // }}} ) u_@$(PREFIX) ( // {{{ .i_controller_clk(i_clk), //i_controller_clk has period of CONTROLLER_CLK_PERIOD .i_rst_n(!i_reset), //200MHz input clock // Wishbone 1 (Controller) @$(SLAVE.ANSIPORTLIST), .i_aux(0), .o_aux(@$(PREFIX)_aux_out), // Leaving this empty would've caused a Verilator warning // Wishbone 2 (PHY) @$(ddr3_phy.SLAVE.ANSIPORTLIST), // // PHY interface .i_phy_iserdes_data(i_@$(PREFIX)_iserdes_data), .i_phy_iserdes_dqs(i_@$(PREFIX)_iserdes_dqs), .i_phy_iserdes_bitslip_reference(i_@$(PREFIX)_iserdes_bitslip_reference), .i_phy_idelayctrl_rdy(i_@$(PREFIX)_idelayctrl_rdy), .o_phy_cmd(o_@$(PREFIX)_cmd), .o_phy_dqs_tri_control(o_@$(PREFIX)_dqs_tri_control), .o_phy_dq_tri_control(o_@$(PREFIX)_dq_tri_control), .o_phy_toggle_dqs(o_@$(PREFIX)_toggle_dqs), .o_phy_data(o_@$(PREFIX)_data), .o_phy_dm(o_@$(PREFIX)_dm), .o_phy_odelay_data_cntvaluein(o_@$(PREFIX)_odelay_data_cntvaluein), .o_phy_odelay_dqs_cntvaluein(o_@$(PREFIX)_odelay_dqs_cntvaluein), .o_phy_idelay_data_cntvaluein(o_@$(PREFIX)_idelay_data_cntvaluein), .o_phy_idelay_dqs_cntvaluein(o_@$(PREFIX)_idelay_dqs_cntvaluein), .o_phy_odelay_data_ld(o_@$(PREFIX)_odelay_data_ld), .o_phy_odelay_dqs_ld(o_@$(PREFIX)_odelay_dqs_ld), .o_phy_idelay_data_ld(o_@$(PREFIX)_idelay_data_ld), .o_phy_idelay_dqs_ld(o_@$(PREFIX)_idelay_dqs_ld), .o_phy_bitslip(o_@$(PREFIX)_bitslip), .o_phy_write_leveling_calib(o_@$(PREFIX)_leveling_calib), .o_phy_reset(o_@$(PREFIX)_reset), // Debug port .o_debug1(@$(PREFIX)_debug), // Verilator lint_off PINCONNECTEMPTY .o_debug2(), .o_debug3() // Verilator lint_on PINCONNECTEMPTY // }}} ); // }}} ## ## @PREFIX=ddr3_phy @DEVID=DDR3_PHY @ACCESS=@$(DEVID)_ACCESS @$NADDR=128 @SLAVE.TYPE=OTHER @SLAVE.BUS=wb32 @SLAVE.ANSPREFIX=wb2_ # @REGS.N=7 @REGS.0= 0 R_@$(DEVID) @$(DEVID) DPHYSTAT0 @REGS.1=1 R_@$(DEVID)STAT1 @$(DEVID)STAT1 DPHYSTAT1 @REGS.2=2 R_@$(DEVID)STAT2 @$(DEVID)STAT2 DPHYSTAT2 @REGS.3=3 R_@$(DEVID)STAT3 @$(DEVID)STAT3 DPHYSTAT3 @REGS.4=4 R_@$(DEVID)CTRLSTAT @$(DEVID)CTRLSTAT DCTRLSTAT @REGS.5=17 R_@$(DEVID)RESET @$(DEVID)RESET DCTRLRESET @REGS.6=19 R_@$(DEVID)DBGSEL @$(DEVID)DBGSEL DCTRLDBG @BDEF.DEFN= ## Define the structure of your PHY controller here. How are the bits all ## layout out? What register names do you have? That should all go here. typedef struct @$(DEVID)_S { unsigned ph_something; } @$(DEVID); @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=@$(DEVID) @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); @RTL.MAKE.GROUP=DDR3 @RTL.MAKE.SUBD=ddr3 @RTL.MAKE.FILES= ddr3_controller.v ddr3_phy.v ================================================ FILE: auto-data/edid.txt ================================================ ################################################################################ ## ## Filename: auto-data/edid.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Extended Display Identification Data. This peripheral is ## responsible for the ability to both read EDID from the ## downstream display, for forwarding it to the upstream (receive) ## display generator, and for making things available for the CPU to ## read. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2015-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=edid @DEVID=EDID @ACCESS=@$(DEVID)_ACCESS @INCLUDEFILE=i2ccpu.txt @IOSDA=io_hdmitx_sda @IOSCL=io_hdmitx_scl @INTERRUPT=edid_int @INT.I2C.WIRE= @INT.I2C.PIC= @INT.EDID.WIRE=@$(INTERRUPT) @INT.EDID.PIC=syspic @BDEF.DEFN= @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE= I2CCPU @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // The EDID I2C Controller // {{{ wbi2ccpu #( .ADDRESS_WIDTH(@$(MASTER.BUS.AWID)), .DATA_WIDTH(@$(MASTER.BUS.WIDTH)), .AXIS_ID_WIDTH(@$(IDW)) ) u_@$(PREFIX) ( // {{{ .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), .i_reset(@$(SLAVE.BUS.CLOCK.RESET)), @$(SLAVE.ANSIPORTLIST), @$(MASTER.ANSIPORTLIST), .i_i2c_sda(i_@$(PREFIX)_sda), .i_i2c_scl(i_@$(PREFIX)_scl), .o_i2c_sda(o_@$(PREFIX)_sda), .o_i2c_scl(o_@$(PREFIX)_scl), .M_AXIS_TVALID(@$(PREFIX)_valid), .M_AXIS_TREADY(@$(PREFIX)_ready), .M_AXIS_TDATA(@$(PREFIX)_data), .M_AXIS_TLAST(@$(PREFIX)_last), .M_AXIS_TID(@$(PREFIX)_id), .i_sync_signal(rtc_pps), // .o_interrupt(@$(INTERRUPT)), .o_debug(@$(PREFIX)_debug) // }}} ); // }}} ## ################################################################################ ################################################################################ ################################################################################ ## @PREFIX=edidslv @DEVID=EDIDRX @NADDR=64 @SLAVE.BUS=wb32 @SLAVE.TYPE=DOUBLE @STREAM=edid @IOSDA=io_hdmirx_sda @IOSCL=io_hdmirx_scl @TOP.PORTLIST= // EDID RX definitions @$(IOSCL), @$(IOSDA) @TOP.IODECL= // EDID RX definitions inout wire @$(IOSCL), @$(IOSDA); @TOP.DEFNS= wire w_@$(PREFIX)_scl, w_@$(PREFIX)_sda; @TOP.INSERT= assign @$(IOSCL) = w_@$(PREFIX)_scl ? 1'bz : 1'b0; assign @$(IOSDA) = w_@$(PREFIX)_sda ? 1'bz : 1'b0; @TOP.MAIN= // EDID RX definitions @$(IOSCL), @$(IOSDA), w_@$(PREFIX)_scl, w_@$(PREFIX)_sda @MAIN.PORTLIST= // EDID RX definitions i_@$(PREFIX)_scl, i_@$(PREFIX)_sda, o_@$(PREFIX)_scl, o_@$(PREFIX)_sda @MAIN.IODECL= // EDID RX definitions input wire i_@$(PREFIX)_scl, i_@$(PREFIX)_sda; output wire o_@$(PREFIX)_scl, o_@$(PREFIX)_sda; @MAIN.DEFNS= // Verilator lint_off UNUSED wire [31:0] @$(PREFIX)_dbg; // Verilator lint_on UNUSED @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // @$(DEVID) // {{{ wbi2cslave #( .AXIS_SUPPORT(1'b1), .SLAVE_ADDRESS(7'h50) ) u_@$(PREFIX) ( .i_clk(i_clk), .i_reset(i_reset), @$(SLAVE.ANSIPORTLIST), .s_valid(@$(STREAM)_valid), .s_ready(@$(STREAM)_ready), .s_data(@$(STREAM)_data), .s_last(@$(STREAM)_last), .i_i2c_scl(i_@$(PREFIX)_scl), .i_i2c_sda(i_@$(PREFIX)_sda), .o_i2c_scl(o_@$(PREFIX)_scl), .o_i2c_sda(o_@$(PREFIX)_sda), .o_dbg(@$(PREFIX)_dbg) ); // }}} @REGS.N=1 @REGS.0=0 R_EDIDRX EDIDRX @RTL.MAKE.FILES=wbi2cslave.v @RTL.MAKE.GROUP=I2CSLV @RTL.MAKE.SUBD=wbi2c @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=char @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); ================================================ FILE: auto-data/edidslvscope.txt ================================================ ################################################################################ ## ## Filename: auto-data/edidslvscope.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Describes how to connect the EDID/I2C debugging port to a ## (compressed) wishbone scope, then to be connected to the bus ## by autofpga. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=edidslvscope @DEVID=EDIDSLVSCOPE @TARGET=edidslv @TRIGGER=edidslv_dbg[31] @DEBUG=edidslv_dbg[30:0] @LOG_CAPTURE_SIZE=13 @INCLUDEFILE=wbscopc.txt @INT.EDIDSLVSCOPE.PIC=altpic @INT.EDIDSLVSCOPE.WIRE=@$(PREFIX)_int @$DEFHOLDOFF=0 @MAIN.DEFNS= ================================================ FILE: auto-data/exconsole.txt ================================================ ################################################################################ ## ## Filename: auto-data/exconsole.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Provide access to both a debugging bus and a console port for ## the CPU. The debugging bus will be given 7-bit transfer codes ## with the high bit set, the console the same codes but with bit 8 clear. ## ## This particular version of the console uses the exbus debugging bus. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=wbu @DEVID=DBGBUS @ACCESS=EXBUS_MASTER @MASTER.BUS=wbu @MASTER.TYPE=HOST @MASTER.PREFIX=@$(PREFIX) @BUS.NAME=wbu @BUS.CLOCK=clk @BUS.WIDTH=32 @BUS.TYPE=wb @BUS.OPT_DBLBUFFER=1 @$BAUDRATE=1000000 @OFF_TIL_ACCESS=1'b0 @CLOCK.NAME=clk @CLOCK.RESET=i_reset @$SETUP=(@$(CLOCK.FREQUENCY) + @$(BAUDRATE)/2) / @$BAUDRATE @SETUP.FORMAT=24'h%x @$BUS_ADDRESS_WIDTH=@$(MASTER.BUS.AWID) @MAIN.PORTLIST= // UART/host to wishbone interface i_@$(PREFIX)_uart_rx, o_@$(PREFIX)_uart_tx @MAIN.IODECL= input wire i_@$(PREFIX)_uart_rx; output wire o_@$(PREFIX)_uart_tx; @MAIN.PARAM= //////////////////////////////////////////////////////////////////////// // // EXBUS parameters // {{{ // Baudrate : @$[%9d](BAUDRATE) // Clock : @$[%9d](CLOCK.FREQUENCY) localparam [23:0] BUSUART = @$SETUP; // @$[%9d](BAUDRATE) baud localparam @$(DEVID)BITS = $clog2(BUSUART); // }}} @MAIN.DEFNS= //////////////////////////////////////////////////////////////////////// // // EXBUS: USB-UART interface declarations // {{{ // wire [7:0] @$(PREFIX)_rx_data, @$(PREFIX)_tx_data; wire @$(PREFIX)_rx_stb; wire @$(PREFIX)_tx_stb, @$(PREFIX)_tx_busy; // Verilator lint_off UNUSED wire [0:0] ex_reset; wire [1:0] ex_gpio; // Verilator lint_on UNUSED // }}} @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // EXBUS: USB-UART driven bus master and console // {{{ // The Host USB interface, to be used by the WB-UART bus rxuartlite #( // {{{ .TIMER_BITS(@$(DEVID)BITS), .CLOCKS_PER_BAUD(BUSUART[@$(DEVID)BITS-1:0]) // }}} ) rcv( // {{{ .i_clk( @$(CLOCK.WIRE)), .i_uart_rx(i_@$(PREFIX)_uart_rx), .o_wr( @$(PREFIX)_rx_stb), .o_data( @$(PREFIX)_rx_data) // }}} ); txuartlite #( // {{{ .TIMING_BITS(@$(DEVID)BITS[4:0]), .CLOCKS_PER_BAUD(BUSUART[@$(DEVID)BITS-1:0]) // }}} ) txv( // {{{ .i_clk( @$(CLOCK.WIRE)), .i_wr( @$(PREFIX)_tx_stb), .i_data( @$(PREFIX)_tx_data), .o_uart_tx(o_@$(PREFIX)_uart_tx), .o_busy( @$(PREFIX)_tx_busy) // }}} ); `ifndef BUSPIC_ACCESS wire w_bus_int; assign w_bus_int = 1'b0; `endif // Verilator lint_off UNUSED wire [29:0] @$(MASTER.PREFIX)_tmp_addr; // Verilator lint_on UNUSED exbuswb #( // {{{ // .LGWATCHDOG(@$(DEVID)WATCHDOG) .ADDRESS_WIDTH(@$(BUS_ADDRESS_WIDTH)) // }}} ) u_exbus( // {{{ .i_clk(@$(CLOCK.WIRE)), .i_reset(@$(CLOCK.RESET)), .o_reset(ex_reset), .i_rx_stb(@$(PREFIX)_rx_stb), .i_rx_byte(@$(PREFIX)_rx_data), .o_tx_stb(@$(PREFIX)_tx_stb), .o_tx_byte(@$(PREFIX)_tx_data), .i_tx_busy(@$(PREFIX)_tx_busy), // .i_gpio(2'b00), .o_gpio(ex_gpio), // .i_console_stb(w_console_tx_stb), .i_console_byte(w_console_tx_data), .o_console_busy(w_console_busy), .o_console_stb(w_console_rx_stb), .o_console_byte(w_console_rx_data), // .o_wb_cyc(@$(MASTER.PREFIX)_cyc), .o_wb_stb(@$(MASTER.PREFIX)_stb), .o_wb_we(@$(MASTER.PREFIX)_we), .o_wb_addr(@$(MASTER.PREFIX)_addr), .o_wb_data(@$(MASTER.PREFIX)_data), .o_wb_sel(@$(MASTER.PREFIX)_sel), .i_wb_stall(@$(MASTER.PREFIX)_stall), .i_wb_ack(@$(MASTER.PREFIX)_ack), .i_wb_data(@$(MASTER.PREFIX)_idata), .i_wb_err(@$(MASTER.PREFIX)_err), .i_interrupt(w_bus_int) // }}} ); // }}} @REGDEFS.H.DEFNS= #define BAUDRATE @$[%d](BAUDRATE) @RTL.MAKE.GROUP= EXBUS @RTL.MAKE.SUBD=exbus @RTL.MAKE.FILES= exbuswb.v excompress.v exdecompress.v exdeword.v exidle.v exmkword.v exwb.v exfifo.v @SIM.INCLUDE= #include "dbluartsim.h" @SIM.CLOCK=@$(CLOCK.NAME) @SIM.DEFNS= DBLUARTSIM *m_@$(PREFIX); @SIM.INIT= m_@$(PREFIX) = new DBLUARTSIM(); m_@$(PREFIX)->setup(@$[%d](SETUP)); @SIM.TICK= m_core->i_@$(PREFIX)_uart_rx = (*m_@$(PREFIX))(m_core->o_@$(PREFIX)_uart_tx); ================================================ FILE: auto-data/flash.txt ================================================ ################################################################################ ## ## Filename: auto-data/flash.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Describes the flash in our new data format. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=flash @DEVID=FLASH @ACCESS=@$(DEVID)_ACCESS @$LGFLASHSZ=24 @$NADDR=(1<<(@$LGFLASHSZ-2)) @$NBYTES=(1<<@$LGFLASHSZ) @NBYTES.FORMAT=0x%08x @SLAVE.TYPE=MEMORY @SLAVE.BUS=wbflash @BUS.NAME=wbflash @BUS.WIDTH=32 @BUS.TYPE=wb @BUS.CLOCK=clk @BUS.NULLSZ=0x100 @NDUMMY=6 @RDDELAY=2 @STARTUP_SCRIPT="spansion.hex" @TOP.PORTLIST= // Top level Quad-SPI I/O ports o_@$(PREFIX)_cs_n, io_@$(PREFIX)_dat @TOP.IODECL= // Quad SPI flash output wire o_@$(PREFIX)_cs_n; inout wire [3:0] io_@$(PREFIX)_dat; @TOP.DEFNS= wire w_@$(PREFIX)_sck, w_@$(PREFIX)_cs_n; wire [1:0] @$(PREFIX)_bmod; wire [3:0] @$(PREFIX)_dat; @TOP.MAIN= // Quad SPI flash w_@$(PREFIX)_cs_n, w_@$(PREFIX)_sck, @$(PREFIX)_dat, io_@$(PREFIX)_dat, @$(PREFIX)_bmod @TOP.INSERT= //////////////////////////////////////////////////////////////////////// // // QSPI Flash IO pin handling // {{{ // // Wires for setting up the QSPI flash wishbone peripheral // // // QSPI)BMOD, Quad SPI bus mode, Bus modes are: // 0? Normal serial mode, one bit in one bit out // 10 Quad SPI mode, going out // 11 Quad SPI mode coming from the device (read mode) xqflex #( .OPT_CLOCK(1'b0), .OPT_PHASE(1'b1) ) u_xqflex ( .i_clk(s_clk), .i_cs_n(w_@$(PREFIX)_cs_n), .i_sck(w_@$(PREFIX)_sck), .i_dat(o_@$(PREFIX)_dat), .o_dat(i_@$(PREFIX)_dat), .i_bmod(@$(PREFIX)_bmod), // .o_cs_n(o_@$(PREFIX)_cs_n), .o_sck(o_@$(PREFIX)_sck), .io_dat(io_@$(PREFIX)_dat) ); // The following primitive is necessary in many designs order to gain // access to the o_@$(PREFIX)_sck pin. It's not necessary on the Arty, // simply because they provide two pins that can drive the QSPI // clock pin. wire [3:0] su_nc; // Startup primitive, no connect STARTUPE2 #( // {{{ // Leave PROG_USR false to avoid activating the program // event security feature. Notes state that such a feature // requires encrypted bitstreams. .PROG_USR("FALSE"), // Sets the configuration clock frequency (in ns) for // simulation. .SIM_CCLK_FREQ(0.0) // }}} ) STARTUPE2_inst ( // {{{ // CFGCLK, 1'b output: Configuration main clock output -- no // connect .CFGCLK(su_nc[0]), // CFGMCLK, 1'b output: Configuration internal oscillator clock // output .CFGMCLK(su_nc[1]), // EOS, 1'b output: Active high output indicating the End Of // Startup. .EOS(su_nc[2]), // PREQ, 1'b output: PROGRAM request to fabric output // Only enabled if PROG_USR is set. This lets the fabric // know that a request has been made (either JTAG or pin // pulled low) to program the device .PREQ(su_nc[3]), // CLK, 1'b input: User start-up clock input .CLK(1'b0), // GSR, 1'b input: Global Set/Reset input .GSR(1'b0), // GTS, 1'b input: Global 3-state input .GTS(1'b0), // KEYCLEARB, 1'b input: Clear AES Decrypter Key input from // BBRAM .KEYCLEARB(1'b0), // PACK, 1-bit input: PROGRAM acknowledge input // This pin is only enabled if PROG_USR is set. This // allows the FPGA to acknowledge a request for reprogram // to allow the FPGA to get itself into a reprogrammable // state first. .PACK(1'b0), // USRCLKO, 1-bit input: User CCLK input -- This is why I am // using this module at all. .USRCCLKO(o_@$(PREFIX)_sck), // USRCCLKTS, 1'b input: User CCLK 3-state enable input // An active high here places the clock into a high // impedence state. Since we wish to use the clock as an // active output always, we drive this pin low. .USRCCLKTS(1'b0), // USRDONEO, 1'b input: User DONE pin output control // Set this to "high" to make sure that the DONE LED pin // is high. .USRDONEO(1'b1), // USRDONETS, 1'b input: User DONE 3-state enable output // This enables the FPGA DONE pin to be active. Setting // this active high sets the DONE pin to high impedence, // setting it low allows the output of this pin to be as // stated above. .USRDONETS(1'b1) // }}} ); // }}} @MAIN.PORTLIST= // The Universal QSPI Flash o_@$(PREFIX)_cs_n, o_@$(PREFIX)_sck, o_@$(PREFIX)_dat, i_@$(PREFIX)_dat, o_@$(PREFIX)_mod @MAIN.IODECL= // The Universal QSPI flash output wire o_@$(PREFIX)_cs_n, o_@$(PREFIX)_sck; output wire [3:0] o_@$(PREFIX)_dat; input wire [3:0] i_@$(PREFIX)_dat; output wire [1:0] o_@$(PREFIX)_mod; @MAIN.DEFNS= // Definitions for the @$(PREFIX) debug port // Verilator lint_off UNUSED wire @$(PREFIX)_dbg_trigger; wire [31:0] @$(PREFIX)_debug; // Verilator lint_on UNUSED @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // Flash controller // {{{ qflexpress #( // {{{ .LGFLASHSZ(@$LGFLASHSZ), .OPT_CLKDIV(1), .OPT_ENDIANSWAP(0), .NDUMMY(@$(NDUMMY)), .RDDELAY(@$(RDDELAY)), .OPT_STARTUP_FILE(@$(STARTUP_SCRIPT)), `ifdef FLASHCFG_ACCESS .OPT_CFG(1'b1) `else .OPT_CFG(1'b0) `endif // }}} ) u_@$(PREFIX) ( // {{{ .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), .i_reset(@$(SLAVE.BUS.CLOCK.RESET)), // Primary memory reading inputs @$(SLAVE.ANSIPORTLIST), // Configuration bus ports @$(flashcfg.SLAVE.ANSIPORTLIST), .o_qspi_sck(o_@$(PREFIX)_sck), .o_qspi_cs_n(o_@$(PREFIX)_cs_n), .o_qspi_mod(o_@$(PREFIX)_mod), .o_qspi_dat(o_@$(PREFIX)_dat), .i_qspi_dat(i_@$(PREFIX)_dat), .o_dbg_trigger(flash_dbg_trigger), .o_debug(flash_debug) // }}} ); // }}} @MAIN.ALT= assign o_@$(PREFIX)_sck = 1'b1; assign o_@$(PREFIX)_cs_n = 1'b1; assign o_@$(PREFIX)_mod = 2'b01; assign o_@$(PREFIX)_dat = 4'b1111; // Verilator lint_off UNUSED wire @$(PREFIX)_unused = &{ 1'b0, i_@$(PREFIX)_dat }; // Verilator lint_on UNUSED @MEM.NAME= flash @MEM.ACCESS = rx @REGS.N= 1 @REGDEFS.H.DEFNS= #define @$(DEVID)BASE @$[0x%08x](REGBASE) #define @$(DEVID)LEN @$NBYTES #define @$(DEVID)LGLEN @$LGFLASHSZ // #define FLASH_RDDELAY @$(RDDELAY) #define FLASH_NDUMMY @$(NDUMMY) // @REGS.0= 0 R_@$(DEVID) @$(DEVID) @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=extern int _@$(PREFIX)[1]; @LD.PERM= rx @LD.NAME= @$(PREFIX) @SIM.CLOCK=clk @SIM.INCLUDE= #include "flashsim.h" @SIM.DEFNS= #ifdef @$(ACCESS) FLASHSIM *m_@$(MEM.NAME); #endif // @$(ACCESS) @SIM.INIT= #ifdef @$(ACCESS) m_@$(MEM.NAME) = new FLASHSIM(FLASHLGLEN, false, @$RDDELAY, @$NDUMMY); #endif // @$(ACCESS) @SIM.TICK= #ifdef @$(ACCESS) m_core->i_@$(PREFIX)_dat = m_@$(MEM.NAME)->simtick( m_core->o_@$(PREFIX)_cs_n, m_core->o_@$(PREFIX)_sck, m_core->o_@$(PREFIX)_dat, m_core->o_@$(PREFIX)_mod); #endif // @$(ACCESS) @SIM.LOAD= m_@$(MEM.NAME)->load(start, &buf[offset], wlen); @PREFIX=crossflash @INCLUDEFILE=crossbus.txt @MASTER.BUS=wbflash ================================================ FILE: auto-data/flashcfg.txt ================================================ ################################################################################ ## ## Filename: auto-data/flashcfg.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Describes the configuration interface of the flash in our new ## data format. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=flashcfg @NADDR=1 @DEVID=FLASHCFG @ACCESS=@$(DEVID)_ACCESS @DEPENDS= FLASH_ACCESS ## Although this is really a SLAVE.TYPE=SINGLE interface, it receives its ## acknowledgements from the flash above. SLAVE.TYPE=SINGLE will create ## acknowledgements in the interconnect, resulting in bus errors. As a result, ## this must be a SLAVE.TYPE=OTHER ## @SLAVE.TYPE=OTHER @SLAVE.BUS=wb32 @SLAVE.ANSPREFIX=cfg_ @MAIN.INSERT= // The Flash control interface is defined by the flash instantiation // hence we don't need to do anything to define it here. @REGS.NOTE= // FLASH erase/program configuration registers @REGS.N= 1 @REGS.0= 0 R_@$(DEVID) @$(DEVID) QSPIC @REGDEFS.H.INSERT= // Flash control constants #define QSPI_FLASH // This core and hardware support a Quad SPI flash #define SZPAGEB 256 #define PGLENB 256 #define SZPAGEW 64 #define PGLENW 64 #define NPAGES 256 #define SECTORSZB (NPAGES * SZPAGEB) // In bytes, not words!! #define SECTORSZW (NPAGES * SZPAGEW) // In words #define NSECTORS 64 #define SECTOROF(A) ((A) & (-1<<16)) #define SUBSECTOROF(A) ((A) & (-1<<12)) #define PAGEOF(A) ((A) & (-1<<8)) @BDEF.IONAME= _@$(PREFIX) @BDEF.OSDEF= _BOARD_HAS_@$(DEVID) @BDEF.IOTYPE=unsigned @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) * const @$(BDEF.IONAME) = ((@$BDEF.IOTYPE *)(@$[0x%08x](REGBASE))); ## @RTL.MAKE.GROUP= FLASH @RTL.MAKE.SUBD= @RTL.MAKE.FILES= qflexpress.v ================================================ FILE: auto-data/global.txt ================================================ ################################################################################ ## ## Filename: auto-data/global.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Capture any global configuration parameters ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2015-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @LEGAL=../auto-data/legalgen.txt @PROJECT=AutoFPGA, a utility for composing FPGA designs from peripherals # # @KEYS.TRIMLIST is a list of all string keys that need to be trimmed (have # spaces removed from either side) before being used # @KEYS.INTLIST is a list of all things that need to be converted to integers @KEYS.INTLIST= BUS_ADDRESS_WIDTH NADDR NPIC NSCOPES PIC.MAX REGS.N ID @DEFAULT.BUS=wbwide @$RESET_ADDRESS=@$flash.REGBASE+(@$flash.NADDR) @RESET_ADDRESS.FORMAT=32'h%08x @REGISTER.BUS=wbu @VERILATOR_PREFIX=v @REGDEFS.H.INSERT= typedef struct { unsigned m_addr; const char *m_name; } REGNAME; extern const REGNAME *bregs; extern const int NREGS; // #define NREGS (sizeof(bregs)/sizeof(bregs[0])) extern unsigned addrdecode(const char *v); extern const char *addrname(const unsigned v); @REGDEFS.CPP.INCLUDE= #include #include #include #include @REGDEFS.CPP.INSERT= #define RAW_NREGS (sizeof(raw_bregs)/sizeof(bregs[0])) const REGNAME *bregs = raw_bregs; const int NREGS = RAW_NREGS; unsigned addrdecode(const char *v) { if (isalpha(v[0])) { for(int i=0; i for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=gpio @DEVID=GPIO @NADDR=1 @ACCESS=@$(DEVID)_ACCESS @SLAVE.TYPE=SINGLE @SLAVE.BUS=wb32 @NUMOUTPUT=10 @NUMINPUT=8 @INT.GPIO.WIRE=gpio_int @INT.GPIO.PIC=syspic @TOP.PORTLIST= // @$(DEVID) ports o_hdmirx_hpa, // Hotplug assert o_hdmirx_txen, i_hdmitx_hpd_n, // Hotplug detect o_sd_reset, i_gps_3df, o_oled_reset_n, o_oled_panel_en, o_oled_logic_en @TOP.IODECL= // @$(DEVID) ports output wire o_hdmirx_hpa; output wire o_hdmirx_txen; input wire i_hdmitx_hpd_n; // Hotplug detect output wire o_sd_reset; input wire i_gps_3df; output wire o_oled_reset_n, o_oled_panel_en, o_oled_logic_en; @TOP.DEFNS= // @$(DEVID) declarations. The two wire busses are just virtual lists // of input (or output) ports. wire [@$(NUMINPUT)-1:0] i_@$(PREFIX); // Verilator lint_off UNUSED // Two of our outputs, o_trace and o_halt, will be unused at the top // level. wire [@$(NUMOUTPUT)-1:0] o_@$(PREFIX); // Verilator lint_on UNUSED @TOP.MAIN= // @$(DEVID) wires i_@$(PREFIX), o_@$(PREFIX) @TOP.INSERT= //////////////////////////////////////////////////////////////////////// // // GPIO adjustments // {{{ assign i_@$(PREFIX) = { 8'h0, pxrx_locked, sysclk_locked, `ifdef GPSTRK_ACCESS i_gps_3df, `else 1'b0, `endif !i_hdmitx_hpd_n, // Hotplug detect !i_sd_cd_n, 1'b0, i_hdmitx_cec, i_hdmirx_cec }; assign o_hdmirx_txen = o_gpio[2]; assign o_hdmirx_hpa = o_gpio[3]; // Hotplug assert assign o_sd_reset = !w_sdio_hwreset_n; assign o_oled_reset_n = !o_gpio[5]; assign o_oled_panel_en = o_gpio[6]; assign o_oled_logic_en = o_gpio[7]; // These two pins are only used in simulation, and only within the // MAIN RTL component. // assign o_trace = o_gpio[8]; // assign o_halt = o_gpio[9]; // }}} @MAIN.PORTLIST= // @$(DEVID) ports `ifdef VERILATOR o_trace, o_halt, `endif i_@$(PREFIX), o_@$(PREFIX) @MAIN.IODECL= localparam NGPI = @$(NUMINPUT), NGPO=@$(NUMOUTPUT); // @$(DEVID) ports `ifdef VERILATOR output wire o_trace; output wire o_halt; `endif input [(NGPI-1):0] i_@$(PREFIX); output wire [(NGPO-1):0] o_@$(PREFIX); @MAIN.DEFNS= wire sd_reset; @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // @$(DEVID) // {{{ // This interface should allow us to control up to 16 @$(DEVID) inputs, // and another 16 @$(DEVID) outputs. The interrupt trips when any of // the inputs changes. (Sorry, which input isn't (yet) selectable.) // localparam [NGPO-1:0] INITIAL_@$(DEVID) = @$(NUMOUTPUT)'h13; wbgpio #( .NIN(NGPI), .NOUT(NGPO), .DEFAULT(INITIAL_@$(DEVID)) ) u_@$(PREFIX) ( // {{{ .i_clk(i_clk), @$(SLAVE.ANSIPORTLIST), .i_gpio(i_@$(PREFIX)), .o_gpio(o_@$(PREFIX)), .o_int(@$(PREFIX)_int) // }}} ); `ifdef SDIO_ACCESS // This bit is used by the SDSPI controller, not the SDIO controller. assign sd_reset = !o_sdio_hwreset_n; `else assign sd_reset = o_@$(PREFIX)[3]; `endif `ifdef VERILATOR wire verilator_halt; assign o_trace = o_@$(PREFIX)[8]; assign verilator_halt = o_@$(PREFIX)[9]; assign o_halt = verilator_halt; always @(posedge verilator_halt) $finish; `endif // }}} @REGS.N=1 @REGS.0= 0 R_@$(DEVID) @$(DEVID) GPI GPO @BDEF.DEFN= // // @$(DEVID) input wires // #define GPIO_HDMIRX_CEC 0x000010000 #define GPIO_HDMITX_CEC 0x000020000 #define GPIO_SD_DETECTED 0x000080000 #define GPIO_HDMITX_DETECT 0x000100000 #define GPIO_GPS_3DF 0x000200000 #define GPIO_SYSCLK_LOCKED 0x000400000 #define GPIO_VIDCLK_LOCKED 0x000800000 // // @$(DEVID) output wires // #define @$(DEVID)_SET(WIRE) (((WIRE)<<16)|(WIRE)) #define @$(DEVID)_CLR(WIRE) ((WIRE)<<16) // #define GPIO_HDMIRX_CEC_SET 0x000010001 #define GPIO_HDMIRX_CEC_CLR 0x000010000 #define GPIO_HDMITX_CEC_SET 0x000020002 #define GPIO_HDMITX_CEC_CLR 0x000020000 // #define GPIO_HDMIRX_TXEN 0x000000004 #define GPIO_HDMIRX_HPA 0x000000008 #define GPIO_SD_RESET 0x000000010 #define GPIO_OLED_RESET 0x000000020 #define GPIO_OLED_PANELEN 0x000000040 #define GPIO_OLED_LOGICEN 0x000000080 #define GPIO_TRACE 0x000000100 #define GPIO_TESTHALT 0x000000200 // #define GPIO_EDID_SCL_SET GPIO_SET(GPIO_EDID_SCL) #define GPIO_EDID_SCL_CLR GPIO_CLR(GPIO_EDID_SCL) #define GPIO_EDID_SDA_SET GPIO_SET(GPIO_EDID_SDA) #define GPIO_EDID_SDA_CLR GPIO_CLR(GPIO_EDID_SDA) #define GPIO_HDMIRX_HPA_SET GPIO_SET(GPIO_HDMIRX_HPA) #define GPIO_HDMIRX_HPA_CLR GPIO_CLR(GPIO_HDMIRX_HPA) #define GPIO_SD_RESET_SET GPIO_SET(GPIO_SD_RESET) #define GPIO_SD_RESET_CLR GPIO_CLR(GPIO_SD_RESET) #define GPIO_HDMIRX_TXEN_SET GPIO_SET(GPIO_HDMIRX_TXEN) #define GPIO_HDMIRX_TXEN_CLR GPIO_CLR(GPIO_HDMIRX_TXEN) #define OLED_RESET GPIO_SET(GPIO_OLED_RESET) #define OLED_RUN GPIO_CLR(GPIO_OLED_RESET) #define OLED_PANELEN GPIO_SET(GPIO_OLED_PANELEN) #define OLED_PANELDIS GPIO_CLR(GPIO_OLED_PANELEN) #define OLED_LOGICEN GPIO_SET(GPIO_OLED_LOGICEN) #define OLED_LOGICDIS GPIO_CLR(GPIO_OLED_LOGICEN) #define GPIO_TRACE_SET GPIO_SET(GPIO_TRACE) #define GPIO_TRACE_CLR GPIO_CLR(GPIO_TRACE) #define GPIO_HALT_SET GPIO_SET(GPIO_TESTHALT) #define GPIO_HALT_CLR GPIO_CLR(GPIO_TESTHALT) @BDEF.IONAME= i_@$(PREFIX) @BDEF.IOTYPE= unsigned @BDEF.OSDEF= _BOARD_HAS_@$(DEVID) @BDEF.OSVAL= static volatile @$(BDEF.IOTYPE) *const _@$(PREFIX) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); @RTL.MAKE.FILES=wbgpio.v @RTL.MAKE.GROUP=@$(DEVID) ================================================ FILE: auto-data/gps.txt ================================================ ################################################################################ ## ## Filename: auto-data/gps.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: This file describes the three interfaces created by the GPS: ## 1) a GPS-locked clock, 2) a "testbench" which is used to ## measure the performance of the GPS-locked lock, and 3) a wishbone ## controlled UART which can be used to read from the UART stream coming ## from the GPS. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @$GPSPORT_OFFSET=2 @PREFIX=gck @DEVID=GPSTRK @ACCESS=@$(DEVID)_ACCESS @NADDR=4 @SLAVE.TYPE=DOUBLE @SLAVE.BUS=wb32 @CLOCK.NAME=clk @$CLKFREQHZ=@$(CLOCK.FREQUENCY) @$GPS_STEP_EXPONENT=10 @$GPS_STEP=((((1<<60)/@$CLKFREQHZ)>>(@$.GPS_STEP_EXPONENT-4))&0x0fffffff)|((@$.GPS_STEP_EXPONENT&0x0f)<<28) @GPS_STEP.FORMAT=32'h%08x @MAIN.PORTLIST= // The GPS 1PPS signal port i_gps_pps @MAIN.PARAM= localparam [31:0] GPSCLOCK_DEFAULT_STEP = @$.GPS_STEP; @MAIN.IODECL= //The GPS Clock input wire i_gps_pps; @MAIN.DEFNS= wire ck_pps; wire gps_pps, gps_led, gps_locked, gps_tracking; wire [63:0] gps_now, gps_err, gps_step; wire [1:0] gps_dbg_tick; @MAIN.INSERT= // Verilator lint_off UNUSED wire [1:0] ck_dbg; // Verilator lint_on UNUSED gpsclock #( .DEFAULT_STEP(GPSCLOCK_DEFAULT_STEP) ) ppsck ( .i_clk(i_clk), .i_rst(1'b0), .i_pps(gps_pps), .o_pps(ck_pps), .o_led(gps_led), @$(SLAVE.ANSIPORTLIST), .o_tracking(gps_tracking), .o_count(gps_now), .o_step(gps_step), .o_err(gps_err), .o_locked(gps_locked), .o_dbg(ck_dbg) ); assign @$(PREFIX)_pps = ck_pps; @MAIN.ALT= reg r_ck_pps; reg [63:0] r_gps_now; reg [31:0] r_gps_prior; wire [47:0] pre_step; assign pre_step = { 16'h00, (({GPSCLOCK_DEFAULT_STEP[27:0],20'h00}) >>GPSCLOCK_DEFAULT_STEP[31:28]) }; initial { r_ck_pps, r_gps_prior } = 33'h0; always @(posedge i_clk) { r_ck_pps, r_gps_prior[31:0] } <= r_gps_prior + pre_step[31:0]; initial r_gps_now = 64'h0; always @(posedge i_clk) begin r_gps_now[63:32] <= r_gps_now[63:32]+(r_ck_pps ? 32'h1:32'h0); r_gps_now[31:0] <= r_gps_prior; end assign ck_pps = r_ck_pps; assign gps_now = r_gps_now; assign gps_err = 64'h0; assign gps_step = pre_step; assign gps_led = 1'b0; assign gps_locked = 1'b0; @INT.PPS.WIRE=@$(PREFIX)_pps @INT.PPS.PIC=syspic @REGS.NOTE= // GPS clock tracker, control loop settings registers @REGS.N=4 @REGS.0= 0 R_GPS_ALPHA ALPHA @REGS.1= 1 R_GPS_BETA BETA @REGS.2= 2 R_GPS_GAMMA GAMMA @REGS.3= 3 R_GPS_STEP STEP @BDEF.DEFN= typedef struct GPSTRACKER_S { unsigned g_alpha, g_beta, g_gamma, g_step; } GPSTRACKER; @BDEF.INSERT= #define SYSINT_PPS SYSINT(@$(INT.PPS.syspic.ID)) @BDEF.IONAME=_gps @BDEF.IOTYPE= GPSTRACKER @BDEF.OSVAL= static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$BDEF.IOTYPE *)@$[0x%08x](REGBASE)); ## ## ## @PREFIX=gtb @NADDR=8 @DEPENDS=GPSTRK_ACCESS @SLAVE.TYPE=DOUBLE @SLAVE.BUS=wb32 @CLOCK.NAME=clk @MAIN.DEFNS= wire tb_pps; @MAIN.INSERT= // Generate a PPS signal independent of the GPS--useful for testing gpsclock_tb #( .CLOCK_FREQUENCY_HZ(@$(CLOCK.FREQUENCY)) ) ppstb( .i_clk(i_clk), .i_lcl_pps(ck_pps), .o_pps(tb_pps), @$(SLAVE.ANSIPORTLIST), .i_err(gps_err), .i_count(gps_now), .i_step(gps_step) ); assign gps_pps = tb_pps; @MAIN.ALT= assign gps_pps = i_gps_pps; @REGS.NOTE= // GPS clock test bench registers, for measuring the clock trackers performance @REGS.N=8 @REGS.0= 0 R_GPSTB_FREQ GPSFREQ @REGS.1= 1 R_GPSTB_JUMP GPSJUMP @REGS.2= 2 R_GPSTB_ERRHI ERRHI @REGS.3= 3 R_GPSTB_ERRLO ERRLO @REGS.4= 4 R_GPSTB_COUNTHI CNTHI @REGS.5= 5 R_GPSTB_COUNTLO CNTLO @REGS.6= 6 R_GPSTB_STEPHI STEPHI @REGS.7= 7 R_GPSTB_STEPLO STEPLO @BDEF.DEFN= typedef struct GPSTB_S { unsigned tb_maxcount, tb_jump; unsigned long tb_err, tb_count, tb_step; } GPSTB; @BDEF.IONAME=_gpstb @BDEF.IOTYPE=GPSTB @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); # # # @PREFIX=gpsu @INCLUDEFILE=wbuart.txt @$BAUDRATE=9600 @CLOCK.NAME=clk @$UARTSETUP=@$(CLOCK.FREQUENCY)/@$(BAUDRATE) @ACCESS=GPSUART_ACCESS @INT.INTLIST= GPSRX GPSTX GPSRXF GPSTXF @INT.GPSRX.WIRE= gpsurx_int @INT.GPSTX.WIRE= gpsutx_int @INT.GPSRXF.WIRE= gpsurxf_int @INT.GPSTXF.WIRE= gpsutxf_int @INT.GPSRX.PIC= altpic @INT.GPSTX.PIC= altpic @INT.GPSRXF.PIC= altpic @INT.GPSTXF.PIC= altpic # Clear the other inherited wires, as we don't need them any more. @INT.UARTRX.WIRE= @INT.UARTTX.WIRE= @INT.UARTRXF.WIRE= @INT.UARTTXF.WIRE= @INT.UARTRX.PIC= @INT.UARTTX.PIC= @INT.UARTRXF.PIC= @INT.UARTTXF.PIC= @BDEF.INSERT= #define SYSINT_GPSRXF ALTINT(@$(INT.GPSRXF.syspic.ID)) #define SYSINT_GPSTXF ALTINT(@$(INT.GPSTXF.altpic.ID)) #define SYSINT_GPSRX ALTINT(@$(INT.GPSRX.altpic.ID)) #define SYSINT_GPSTX ALTINT(@$(INT.GPSTX.altpic.ID)) @TOP.PORTLIST= // The GPS-UART i_@$(PREFIX)_rx, o_@$(PREFIX)_tx @MAIN.PORTLIST= // The GPS-UART i_@$(PREFIX)_rx, o_@$(PREFIX)_tx @MAIN.IODECL= input wire i_@$(PREFIX)_rx; output wire o_@$(PREFIX)_tx; @MAIN.DEFNS= wire w_@$(PREFIX)_cts_n, w_@$(PREFIX)_rts_n; assign w_@$(PREFIX)_cts_n=1'b1; @RTS=w_@$(PREFIX)_rts_n @CTS=w_@$(PREFIX)_cts_n @REGS.NOTE= // GPS UART registers, similar to WBUART @REGS.N=4 @REGS.0= 0 R_GPSU_SETUP GPSSETUP @REGS.1= 1 R_GPSU_FIFO GPSFIFO @REGS.2= 2 R_GPSU_UARTRX GPSRX @REGS.3= 3 R_GPSU_UARTTX GPSTX @BDEF.IONAME=_@$(PREFIX) @BDEF.OSDEF=_BOARD_HAS_GPS_UART @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)(@$[0x%08x](REGBASE))); @$SIM.PORTOFFSET=@/GPSPORT_OFFSET @SIM.INIT= #ifdef @$(ACCESS) m_@$(PREFIX) = new UARTSIM(FPGAPORT+@$(SIM.PORTOFFSET)); m_@$(PREFIX)->setup(@$[0x%08x](UARTSETUP)); #endif // @$(ACCESS) # @RTL.MAKE.GROUP=GPS @RTL.MAKE.FILES=gpsclock_tb.v gpsclock.v bigadd.v bigsub.v bigsmpy.v ================================================ FILE: auto-data/hdmi.txt ================================================ ################################################################################ ## ## Filename: auto-data/hdmi.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To direct the build of the autofpga automatically generated ## files. The various configuration files are the *.txt files ## found in this directory. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=hdmi @DEVID=VIDPIPE @ACCESS=@$(DEVID)_ACCESS @NADDR=1024 @SLAVE.BUS=wb32 @SLAVE.TYPE=OTHER @MASTER.BUS=wbwide @MASTER.TYPE=DMA @MASTER.ANSPREFIX=dma_ @INT.VIDFRAME.WIRE=@$(PREFIX)_int @INT.VIDFRAME.PIC=syspic @TOP.PORTLIST= i_hdmirx_clk_p, i_hdmirx_clk_n, i_hdmirx_p, i_hdmirx_n, o_hdmitx_clk_p, o_hdmitx_clk_n, o_hdmitx_p, o_hdmitx_n @TOP.IODECL= input wire i_hdmirx_clk_p, i_hdmirx_clk_n; input wire [2:0] i_hdmirx_p, i_hdmirx_n; output wire o_hdmitx_clk_p, o_hdmitx_clk_n; output wire [2:0] o_hdmitx_p, o_hdmitx_n; @TOP.DEFNS= wire [9:0] hdmirx_red, hdmirx_grn, hdmirx_blu; wire [9:0] hdmitx_red, hdmitx_grn, hdmitx_blu; wire [1:0] w_pxclk_cksel; wire hdmirx_clk, hdmi_ck, hdmi_serdes_clk; wire pxrx_locked, pix_reset_n, hdmirx_reset_n; wire [15-1:0] set_hdmi_delay, actual_hdmi_delay; @TOP.INSERT= //////////////////////////////////////////////////////////////////////// // // HDMI // {{{ // Ingest the HDMI data lines // {{{ xhdmiin u_hdmirx_red( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(hdmirx_reset_n), .i_delay(set_hdmi_delay[14:10]), .o_delay(actual_hdmi_delay[14:10]), .i_hs_wire({ i_hdmirx_p[2], i_hdmirx_n[2] }), .o_word(hdmirx_red) ); xhdmiin u_hdmirx_grn( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(hdmirx_reset_n), .i_delay(set_hdmi_delay[9:5]), .o_delay(actual_hdmi_delay[9:5]), .i_hs_wire({ i_hdmirx_p[1], i_hdmirx_n[1] }), .o_word(hdmirx_grn) ); xhdmiin u_hdmirx_blu( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(hdmirx_reset_n), .i_delay(set_hdmi_delay[4:0]), .o_delay(actual_hdmi_delay[4:0]), .i_hs_wire({ i_hdmirx_p[0], i_hdmirx_n[0] }), .o_word(hdmirx_blu) ); // }}} // Output the HDMI TX data lines // {{{ xhdmiout u_hdmitx_clk( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(pix_reset_n), .i_en(1'b1), .i_word(10'b11111_00000), .o_port({ o_hdmitx_clk_p, o_hdmitx_clk_n }) ); xhdmiout u_hdmitx_red( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(pix_reset_n), .i_en(1'b1), .i_word(hdmitx_red), .o_port({ o_hdmitx_p[2], o_hdmitx_n[2] }) ); xhdmiout u_hdmitx_grn( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(pix_reset_n), .i_en(1'b1), .i_word(hdmitx_grn), .o_port({ o_hdmitx_p[1], o_hdmitx_n[1] }) ); xhdmiout u_hdmitx_blu( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(pix_reset_n), .i_en(1'b1), .i_word(hdmitx_blu), .o_port({ o_hdmitx_p[0], o_hdmitx_n[0] }) ); // }}} // }}} @TOP.MAIN= // HDMI control ports hdmirx_clk, hdmi_ck, // Depending on s_siclk hdmirx_red, hdmirx_grn, hdmirx_blu, hdmitx_red, hdmitx_grn, hdmitx_blu, set_hdmi_delay, actual_hdmi_delay, pix_reset_n, pxrx_locked, hdmirx_reset_n, w_pxclk_cksel @MAIN.PORTLIST= // HDMI control ports `ifndef VERILATOR i_hdmiclk, `endif i_pixclk, i_hdmi_red, i_hdmi_grn, i_hdmi_blu, o_hdmi_red, o_hdmi_grn, o_hdmi_blu, o_hdmi_iodelay, i_hdmi_iodelay, o_pix_reset_n, i_pxpll_locked, o_hdmirx_reset_n, o_pxclk_cksel @MAIN.IODECL= // @$(PREFIX) declarations // {{{ `ifndef VERILATOR input wire i_hdmiclk; `endif input wire i_pixclk; input wire [9:0] i_hdmi_red, i_hdmi_grn, i_hdmi_blu; output wire [9:0] o_hdmi_red, o_hdmi_grn, o_hdmi_blu; output wire [14:0] o_hdmi_iodelay; input wire [14:0] i_hdmi_iodelay; output wire o_pix_reset_n, o_hdmirx_reset_n; input wire i_pxpll_locked; output wire [1:0] o_pxclk_cksel; // }}} @MAIN.DEFNS= // Verilator lint_off UNUSED `ifdef VERILATOR wire i_hdmiclk; `endif wire hdmidbg_ce, hdmidbg_trigger; wire [31:0] hdmiclr_debug; // Verilator lint_on UNUSED @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // HDMI Video processing pipeline // {{{ `ifdef VERILATOR assign i_hdmiclk = i_pixclk; `endif vidpipe #( .AW(@$(MASTER.BUS.AWID)), .DW(@$(MASTER.BUS.WIDTH)) ) u_@$(PREFIX) ( .i_clk(i_clk), .i_reset(i_reset), @$(SLAVE.ANSIPORTLIST), .i_hdmiclk(i_hdmiclk), .i_altclk(i_pixclk), .i_pixclk(i_pixclk), .i_hdmi_red(i_hdmi_red), .i_hdmi_grn(i_hdmi_grn), .i_hdmi_blu(i_hdmi_blu), @$(MASTER.ANSIPORTLIST), .o_hdmi_red(o_hdmi_red), .o_hdmi_grn(o_hdmi_grn), .o_hdmi_blu(o_hdmi_blu), .o_pix_reset_n(o_pix_reset_n), .i_pxpll_locked(i_pxpll_locked), .o_hdmirx_reset_n(o_hdmirx_reset_n), .o_pxclk_sel(o_pxclk_cksel), .o_iodelay(o_hdmi_iodelay), .i_iodelay(i_hdmi_iodelay), .o_interrupt(@$(INT.VIDFRAME.WIRE)), // .o_dbg_ce(hdmidbg_ce), .o_dbg_trigger(hdmidbg_trigger), .o_pixdebug(hdmiclr_debug) ); // }}} @REGS.NOTE=// HDMI video processing pipe registers @REGS.N=23 @REGS.0= 0 R_@$(DEVID) @$(DEVID) VIDCTRL @REGS.1= 1 R_HDMIFREQ HDMIFREQ @REGS.2= 2 R_SIFREQ SIFREQ @REGS.3= 3 R_PXFREQ PXFREQ @REGS.4= 4 R_INSIZE INSIZE @REGS.5= 5 R_INPORCH INPORCH @REGS.6= 6 R_INSYNC INSYNC @REGS.7= 7 R_INRAW INRAW @REGS.8= 8 R_HDMISIZE HDMISIZE @REGS.9= 9 R_HDMIPORCH HDMIPORCH @REGS.10= 10 R_HDMISYNC HDMISYNC @REGS.11= 11 R_HDMIRAW HDMIRAW @REGS.12= 12 R_OVADDR OVADDR @REGS.13= 13 R_OVSIZE OVSIZE @REGS.14= 14 R_OVOFFSET OVOFFSET @REGS.15= 15 R_FPS FPS @REGS.16= 16 R_CAPTURE VCAPTURE @REGS.17= 17 R_CAPBASE VCAPBASE @REGS.18= 18 R_CAPWORDS VCAPWORDS @REGS.19= 19 R_CAPPOSN VCAPPOSN @REGS.20= 20 R_CAPSIZE VCAPSIZE @REGS.21= 24 R_SYNCWORD VSYNCWORD @REGS.22=512 R_CMAP CMAP @BDEF.INCLUDE= #include @BDEF.DEFN= #ifndef @$(DEVID)_H #define @$(DEVID)_H #define VIDPIPE_RESET 0x000001 #define VIDPIPE_RXPLLCK 0x000002 #define VIDPIPE_LOCALCK 0x000000 #define VIDPIPE_RXCLOCK 0x000020 #define VIDPIPE_LCLSRC 0x000000 #define VIDPIPE_RXSRC 0x000040 #define VIDPIPE_RXSYNCD 0x010000 #define VIDPIPE_OVLYERR 0x020000 #define VIDCMAP_BW 0x000000 #define VIDCMAP_2GRAY 0x000100 #define VIDCMAP_4CMAP 0x000200 #define VIDCMAP_8CMAP 0x000300 #define VIDCMAP_8CLR 0x000400 #define VIDCMAP_16CLR 0x000500 #define VIDCMAP_24CLR 0x000600 #define VIDCMAP_32CLR 0x000700 typedef struct __attribute__((packed)) VIDMODE_S { uint16_t m_height, m_width; uint16_t m_vporch, m_hporch; uint16_t m_vsync, m_hsync; uint16_t m_raw_height, m_raw_width; } VIDMODE; typedef struct __attribute__((packed)) @$(DEVID)_S { uint32_t v_control, v_hdmifreq, v_sifreq, v_pxfreq; VIDMODE v_in, v_src; const char *v_overlay; uint16_t v_ovheight, v_ovwidth; uint16_t v_ovypos, v_ovhpos; unsigned v_fps; uint32_t v_capture; const char *v_capbase; uint32_t v_capwords, v_capposn, v_capsize; unsigned v_ovwords; unsigned v_unused2[2]; unsigned v_syncword; uint32_t v_unused[512-25]; uint32_t v_clrmap[256]; } @$(DEVID); #endif // @$(DEVID)_H @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=@$(DEVID) @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); @RTL.MAKE.GROUP=HDMI @RTL.MAKE.SUBD=video @RTL.MAKE.FILES= axishdmi.v axisvoverlay.v hdmi2vga.v hdmibitsync.v hdmipixelsync.v sync2stream.v synccount.v tfrstb.v tmdsdecode.v tmdsencode.v vid_empty.v vid_mux.v vidpipe.v vidstream2pix.v vid_wbframebuf.v vid_crop.v xhdmiin_deserdes.v xhdmiin.v xhdmiout.v xpxclk.v @CLOCK.NAME=pixclk @CLOCK.WIRE=i_pixclk @CLOCK.FREQUENCY=40000000 @SIM.CLOCK=pixclk @SIM.INCLUDE= #include "hdmisource.h" #include "hdmisim.h" @SIM.DEFNS= #ifdef @$(ACCESS) HDMISOURCE *m_hdmirx; HDMIWIN *m_hdmitx; #endif // @$(ACCESS) @SIM.INIT= #ifdef @$(ACCESS) m_hdmirx = NULL; m_hdmitx = NULL; if (gbl_use_gui) { m_hdmirx = new HDMISOURCE(800, 600); m_hdmitx = new HDMIWIN(800, 600); } #endif // @$(ACCESS) @SIM.METHODS= void connect_idler(void) { Glib::signal_idle().connect( sigc::mem_fun((*this),&MAINTB::on_tick)); } bool on_tick(void) { for(int i=0; i<15; i++) tick(); return true; } @SIM.TICK= #ifdef @$(ACCESS) // Simulate both an external HDMI source and monitor if (gbl_use_gui) { int r, g, b; // HDMI input received by the design (*m_hdmirx)(b, g, r); m_core->i_hdmi_blu = b; m_core->i_hdmi_grn = g; m_core->i_hdmi_red = r; m_core->i_pxpll_locked = 1; // HDMI output, transmitted from the design (*m_hdmitx)(m_core->o_hdmi_blu, m_core->o_hdmi_grn, m_core->o_hdmi_red); } #endif // @$(ACCESS) @XDC.INSERT= ## ## Can't (officially) go any faster than 119.05 MHz ## Yes, I know I've seen this board hit the 145 MHz required by 1080p, but Vivado's timing analyzer ## says we can't go that fast. create_clock -period 10.8 -name PXCLK -waveform { 0.0 5.4 } -add [get_ports i_hdmirx_clk_p ] ## XCLKSW ## {{{ ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~u_xpxclk/CLOCK_SWITCH.u_prepx/r_sel*}] -to [get_cells -hier -filter {NAME=~ u_xpxclk/CLOCK_SWITCH.u_prepx/u_bufg*}] 7.0 # set_case_analysis 1 [get_nets -hier -filter {NAME=~ w_pxclk_cksel[1]*}] ## }}} ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset_sys*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset_u*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset_sys*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset_pipe*}] 6.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/genhdmi/pix_reset*}] 6.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/hdmi_reset_sys*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/hdmi_reset_pipe*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/hdmi_reset_sys*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/hdmi_reset*}] 6.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/hdmi_reset*}] -to [get_cells -hier -filter {NAME=~ u_hdmirx_*/reset_pipe*}] 10.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/hdmi_reset*}] -to [get_cells -hier -filter {NAME=~ u_hdmirx_*/the_deserdes/reset_pipe*}] 10.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ u_hdmitx_*/reset_pipe*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ u_hdmitx_*/sync_reset_n*}] 6.0 ## ## RXVIDXCLK ## {{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/GEN_REGISTERED_READ.o_rd_empty*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/mem*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/GEN_REGISTERED_READ.o_rd_data*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/rd_addr*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/rgray*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/rd_wgray*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/wgray_cross*}] 6.0 # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_overlay/primary_skid/LOGIC.r_valid*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/rd_addr*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_overlay/primary_skid/LOGIC.r_valid*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/rgray*}] 6.0 # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_overlay/primary_skid/LOGIC.r_valid*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/GEN_REGISTERED_READ.o_rd_data*}] 6.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/wgray*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/wgray_cross*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/mem*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/GEN_REGISTERED_READ.o_rd_data*}] 6.0 # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/rd_addr*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_rxvidxclk/GEN_REGISTERED_READ.o_rd_data*}] 6.0 ## ## }}} ## u_new_frame ## {{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_new_frame/a_req*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_new_frame/a_ack*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_new_frame/a_pipe*}] 6.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_new_frame/a_pipe*}] 6.0 ## }}} ## ## WB2PIX ## {{{ ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_wb2pix/a_data*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_wb2pix/o_b_data*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_wb2pix/a_req*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_wb2pix/b_pipe*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_wb2pix/b_last*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_wb2pix/a_pipe*}] 6.0 ## }}} ## PIX2WB ## {{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/o_b_data*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/a_ack*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/a_pipe*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/a_req*}] 6.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/a_data*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/o_b_data*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/a_req*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/b_pipe*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/b_last*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.u_pix2wb/a_pipe*}] 6.0 ## }}} ## ## u_framebuf/GEN_ASYNC_FIFO.pxfifo ## {{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/wgray_cross*}] 6.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset_sys*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] 6.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/rgray*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/rgray_cross*}] 7.0 # # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/rd_addr*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/rgray*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/rd_wgray*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.r_pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/GEN_REGISTERED_READ.o_rd_empty*}] 7.0 # # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/wgray*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/wgray_cross*}] 7.0 # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/mem*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/GEN_REGISTERED_READ.o_rd_data*}] 7.0 ## # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/mem*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_framebuf/GEN_ASYNC_FIFO.pxfifo/GEN_REGISTERED_READ.o_rd_data*}] 7.0 ## }}} ## H2SYS ## {{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2sys/a_data*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2sys/o_b_data*}] 10.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2sys/b_last*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2sys/a_pipe*}] 10.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2sys/a_req*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2sys/b_pipe*}] 10.0 ## }}} ## H2PIX ## {{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2pix/b_pipe*}] 6.7 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2pix/b_req*}] 6.7 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2pix/b_last*}] 6.7 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2pix/a_data*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2pix/o_b_data*}] 6.7 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2pix/b_last*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2pix/a_pipe*}] 6.7 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2pix/a_req*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_h2pix/b_pipe*}] 6.7 ## }}} ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_hdmi2vga/bitsync/*sync/pixloc/REQUIRE_QUALITY.o_val*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pre_wb_data*}] 10.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_hdmi2vga/bitsync/*sync/sync_valid*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pre_wb_data*}] 10.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_HDMIIN_TO_AXIVID.u_hdmi2vga/bitsync/all_locked*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pre_wb_data*}] 10.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_new_frame/b_last*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_new_frame/a_pipe*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_new_frame/a_req*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_new_frame/b_pipe*}] 7.0 ## ## PX2SYS ## {{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_hdmi/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_hdmi/u_px2sys/a_req*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_hdmi/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_hdmi/u_px2sys/a_ack*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_hdmi/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_hdmi/u_px2sys/a_pipe*}] 7.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_hdmi/u_px2sys/b_last*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_hdmi/u_px2sys/a_pipe*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_px2sys/a_req*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_px2sys/b_pipe*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_px2sys/a_data*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_px2sys/o_b_data*}] 7.0 ## }}} ## ## SYS2PX ##{{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/b_req*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/b_last*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/pix_reset*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/b_pipe*}] 7.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/a_data*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/o_b_data*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/b_last*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/a_pipe*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/a_req*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/b_pipe*}] 7.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/o_b_data*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/genhdmi/vpos*}] 7.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_sys2px/o_b_data*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/genhdmi/hpos*}] 7.0 ## }}} ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_mem2pix/cmap_reg*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/GEN_FRAMEBUF.u_mem2pix/cmap*reg*}] 7.0 ## CLKCOUNTER ## {{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~thedesign/u_@$(PREFIX)/u_pixclk_counter/avgs*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_pixclk_counter/q_v*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~thedesign/u_@$(PREFIX)/u_siclk_counter/avgs*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_siclk_counter/q_v*}] 7.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~thedesign/u_@$(PREFIX)/u_hdmiclk_counter/avgs*}] -to [get_cells -hier -filter {NAME=~ thedesign/u_@$(PREFIX)/u_hdmiclk_counter/q_v*}] 7.0 ## }}} @PREFIX=pxclk @SLAVE.TYPE=other @SLAVE.BUS=wb32 @NADDR=128 @TOP.DEFNS= wire [31:0] @$(PREFIX)_debug; wire w_@$(PREFIX)_cyc, w_@$(PREFIX)_stb, w_@$(PREFIX)_we, w_@$(PREFIX)_stall, w_@$(PREFIX)_ack; wire [6:0] w_@$(PREFIX)_addr; wire [31:0] w_@$(PREFIX)_data, w_@$(PREFIX)_idata; wire [3:0] w_@$(PREFIX)_sel; @TOP.MAIN= w_@$(PREFIX)_cyc, w_@$(PREFIX)_stb, w_@$(PREFIX)_we, w_@$(PREFIX)_addr, w_@$(PREFIX)_data, w_@$(PREFIX)_sel, w_@$(PREFIX)_stall, w_@$(PREFIX)_ack, w_@$(PREFIX)_idata @MAIN.PORTLIST= o_@$(PREFIX)_cyc, o_@$(PREFIX)_stb, o_@$(PREFIX)_we, o_@$(PREFIX)_addr, o_@$(PREFIX)_data, o_@$(PREFIX)_sel, i_@$(PREFIX)_stall, i_@$(PREFIX)_ack, i_@$(PREFIX)_idata @MAIN.IODECL= output wire o_@$(PREFIX)_cyc, o_@$(PREFIX)_stb, o_@$(PREFIX)_we; output wire [6:0] o_@$(PREFIX)_addr; output wire [31:0] o_@$(PREFIX)_data; output wire [3:0] o_@$(PREFIX)_sel; input wire i_@$(PREFIX)_stall, i_@$(PREFIX)_ack; input wire [31:0] i_@$(PREFIX)_idata; @TOP.PORTLIST= @TOP.IODECL= @TOP.INSERT= //////////////////////////////////////////////////////////////////////// // // HDMI Clock generation // {{{ xpxclk u_xpxclk ( .i_sysclk(s_clk), // System clock .i_cksel(w_pxclk_cksel), // Clock select switch // .i_hdmirx_clk_p(i_hdmirx_clk_p), // HDMI RX input clock .i_hdmirx_clk_n(i_hdmirx_clk_n), .i_lcl_pixclk(s_clk_80mhz_unbuffered), // Locally generated clk .i_siclk(s_clk_80mhz_unbuffered), // .o_hdmick_locked(pxrx_locked), .o_hdmirx_clk(hdmirx_clk), // Clk for measurement only .o_pixclk(hdmi_ck), // Pixel clock .o_hdmick(hdmi_serdes_clk), // HS pixel clock // .i_wb_clk(s_clk), // .i_wb_cyc(w_@$(PREFIX)_cyc), .i_wb_stb(w_@$(PREFIX)_stb), .i_wb_we(w_@$(PREFIX)_we), .i_wb_addr(w_@$(PREFIX)_addr[7-1:0]), .i_wb_data(w_@$(PREFIX)_data), // 32 bits wide .i_wb_sel(w_@$(PREFIX)_sel), // 32/8 bits wide .o_wb_stall(w_@$(PREFIX)_stall),.o_wb_ack(w_@$(PREFIX)_ack), .o_wb_data(w_@$(PREFIX)_idata), // .o_debug(@$(PREFIX)_debug) ); // }}} @MAIN.INSERT= assign o_@$(PREFIX)_cyc = @$(SLAVE.PREFIX)_cyc; assign o_@$(PREFIX)_stb = @$(SLAVE.PREFIX)_stb; assign o_@$(PREFIX)_we = @$(SLAVE.PREFIX)_we; assign o_@$(PREFIX)_addr = @$(SLAVE.PREFIX)_addr[6:0]; assign o_@$(PREFIX)_data = @$(SLAVE.PREFIX)_data; assign o_@$(PREFIX)_sel = @$(SLAVE.PREFIX)_sel; assign @$(SLAVE.PREFIX)_stall = i_@$(PREFIX)_stall; assign @$(SLAVE.PREFIX)_ack = i_@$(PREFIX)_ack; assign @$(SLAVE.PREFIX)_idata = i_@$(PREFIX)_idata; @REGS.NOTE=// HDMI pixel clock PLL reconfiguration port @REGS.N=1 @REGS.0= 0 R_PXPLL PXPLL ## @BDEF.DEFN= @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=unsigned @BDEF.OSDEF=_BOARD_HAS_PXPLL @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME)=((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); @SIM.CLOCK=clk @SIM.TICK= m_core->i_@$(PREFIX)_stall = 0; m_core->i_@$(PREFIX)_ack = m_core->o_@$(PREFIX)_stb; m_core->i_@$(PREFIX)_idata = m_core->o_@$(PREFIX)_data; ================================================ FILE: auto-data/i2ccpu.txt ================================================ ################################################################################ ## ## Filename: auto-data/i2ccpu.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Drive and control the I2C bus ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=i2c @DEVID=I2CCPU @NADDR=4 @ACCESS=@$(DEVID)_ACCESS @SLAVE.BUS=wb32 @SLAVE.TYPE=DOUBLE @SLAVE.PREFIX=@$(SLAVE.BUS.NAME)_@$(PREFIX)s @MASTER.TYPE=CPU @MASTER.BUS=wbwide @MASTER.PREFIX=@$(MASTER.BUS.NAME)_@$(PREFIX)m @SGP=@$(BUS.PREFIX) @WBP=@$(SLAVE.BUS.PREFIX) @MASTER.ANSPREFIX=pf_ @IOSDA=io_sda @IOSCL=io_scl @IDW=2 @INTERRUPT=i2c_int @INT.I2C.WIRE=@$(INTERRUPT) @INT.I2C.PIC=syspic @TOP.PORTLIST= @$(IOSCL), @$(IOSDA) @TOP.IODECL= inout wire @$(IOSCL), @$(IOSDA); @TOP.DEFNS= // I2CCPU definitions // {{{ wire i_@$(PREFIX)_sda, i_@$(PREFIX)_scl, o_@$(PREFIX)_sda, o_@$(PREFIX)_scl; // }}} @TOP.INSERT= //////////////////////////////////////////////////////////////////////// // // I2C IO buffers // {{{ // We need these in order to (properly) ensure the high impedance // states (pull ups) of the I2C I/O lines. Our goals are: // // o_@$(PREFIX)_X io_@$(PREFIX)_X Derived:T // 1'b0 1'b0 1'b0 // 1'b1 1'bz 1'b1 // IOBUF @$(PREFIX)sclp( // {{{ .I(1'b0), .T(o_@$(PREFIX)_scl), .O(i_@$(PREFIX)_scl), .IO(@$(IOSCL)) // }}} ); IOBUF @$(PREFIX)sdap( // {{{ .I(1'b0), .T(o_@$(PREFIX)_sda), .O(i_@$(PREFIX)_sda), .IO(@$(IOSDA)) // }}} ); // }}} @TOP.MAIN= // I2CCPU i_@$(PREFIX)_sda, i_@$(PREFIX)_scl, o_@$(PREFIX)_sda, o_@$(PREFIX)_scl @MAIN.PORTLIST= i_@$(PREFIX)_sda, i_@$(PREFIX)_scl, o_@$(PREFIX)_sda, o_@$(PREFIX)_scl @MAIN.IODECL= // I2C Port declarations // {{{ input wire i_@$(PREFIX)_sda, i_@$(PREFIX)_scl; output wire o_@$(PREFIX)_sda, o_@$(PREFIX)_scl; // }}} @MAIN.DEFNS= // I2C Controller // {{{ // Verilator lint_off UNUSED localparam @$(DEVID)_WIDTH=(@$(IDW) == 0) ? 1 : @$(IDW); wire @$(PREFIX)_valid, @$(PREFIX)_ready, @$(PREFIX)_last; wire [7:0] @$(PREFIX)_data; wire [@$(DEVID)_WIDTH-1:0] @$(PREFIX)_id; wire [31:0] @$(PREFIX)_debug; // Verilator lint_on UNUSED // }}} @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // The I2C Controller // {{{ wbi2ccpu #( .ADDRESS_WIDTH(@$(MASTER.BUS.AWID)), .DATA_WIDTH(@$(MASTER.BUS.WIDTH)), .AXIS_ID_WIDTH(@$(IDW)) ) u_@$(PREFIX) ( // {{{ .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), .i_reset(@$(SLAVE.BUS.CLOCK.RESET)), @$(SLAVE.ANSIPORTLIST), @$(MASTER.ANSIPORTLIST), .i_i2c_sda(i_@$(PREFIX)_sda), .i_i2c_scl(i_@$(PREFIX)_scl), .o_i2c_sda(o_@$(PREFIX)_sda), .o_i2c_scl(o_@$(PREFIX)_scl), .M_AXIS_TVALID(@$(PREFIX)_valid), .M_AXIS_TREADY(@$(PREFIX)_ready), .M_AXIS_TDATA(@$(PREFIX)_data), .M_AXIS_TLAST(@$(PREFIX)_last), .M_AXIS_TID(@$(PREFIX)_id), .i_sync_signal(rtc_pps), // .o_interrupt(@$(INTERRUPT)), .o_debug(@$(PREFIX)_debug) // }}} ); assign @$(PREFIX)_ready = (!@$(PREFIX)_valid) || (1'b0 || (@$(PREFIX)_id == 0) // NULL address || (@$(PREFIX)_id == 1) `ifdef I2CDMA_ACCESS || (@$(PREFIX)_id == 2 && i2cdma_ready) `else || (@$(PREFIX)_id == 2) `endif || (@$(PREFIX)_id > 2)); // }}} @MAIN.ALT= assign o_@$(PREFIX)_scl = 1'b1; assign o_@$(PREFIX)_sda = 1'b1; ## ## regdefs.h / regdefs.cpp ## @REGS.N=4 @REGS.NOTE=// I2C Controller registers @REGS.0= 0 R_@$(DEVID) @$(DEVID) @$(DEVID)_CTRL @$(DEVID)CTRL @REGS.1= 1 R_@$(DEVID)_OVW @$(DEVID)_OVW @$(DEVID)_OVERRIDE @REGS.2= 2 R_@$(DEVID)_ADDR @$(DEVID)_ADDR @$(DEVID)_ADDRESS @REGS.3= 3 R_@$(DEVID)_CKCOUNT @$(DEVID)CLK @$(DEVID)_CKCOUNT ## ## board.h ## @BDEF.DEFN= //////////////////////////////////////////////////////////////////////// // // I2C CPU data structures // {{{ //////////////////////////////////////////////////////////////////////// // // #ifndef @$(DEVID)_H #define @$(DEVID)_H #define I2CC_WAITING 0x00800000 // True if waiting for synch signal #define I2CC_HALT 0x00400000 // Halt request #define I2CC_ABORT 0x00200000 // Abort #define I2CC_ERROR 0x00100000 #define I2CC_HARDHALT 0x00080000 #define I2CC_SCL 0x00000200 #define I2CC_SDA 0x00000100 #define I2CC_STOPPED I2CC_HARDHALT #define I2CC_FAULT (I2CC_ERROR | I2CC_ABORT) #define I2CC_CLEAR (I2CC_FAULT | I2CC_HALT) // For the manual port #define I2CC_MANSCL 0x00008000 #define I2CC_MANSDA 0x00004000 #define I2CC_MANUAL 0x00000800 #define I2CC_TVALID 0x00000200 #define I2CC_TLAST 0x00000100 typedef struct @$(DEVID)_S { volatile unsigned ic_control, ic_override, ic_address, ic_clkcount; } @$(DEVID); #endif // @$(DEVID)_H // }}} @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=@$(DEVID) @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME)=((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); ## ## Makefile insert info ## @RTL.MAKE.GROUP=@$(DEVID) @RTL.MAKE.SUBD=wbi2c ## RTL.MAKE.FILES *shoul* also include dblfetch, but that's a part of the CPU ## directory, so we don't include it here a second time @RTL.MAKE.FILES=wbi2ccpu.v axisi2c.v ## ## Makefile insert info ## @SIM.CLOCK=clk @SIM.TICK= m_core->i_@$(PREFIX)_scl = m_core->o_@$(PREFIX)_scl; m_core->i_@$(PREFIX)_sda = m_core->o_@$(PREFIX)_sda; ================================================ FILE: auto-data/i2cdma.txt ================================================ ################################################################################ ## ## Filename: auto-data/i2cdma.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Connect an (optional) DMA to the main I2C bus. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=i2cdma @DEVID=I2CDMA @ACCESS=@$(DEVID)_ACCESS @NADDR=4 @SLAVE.BUS=wb32 @SLAVE.TYPE=DOUBLE @MASTER.BUS=wbwide @MASTER.TYPE=DMA @MASTER.ANSPREFIX=dma_ @STREAM=i2c @MAIN.DEFNS= wire @$(PREFIX)_ready; @MAIN.INSERT= wbi2cdma #( .AW(@$(MASTER.BUS.AWID)), .DW(@$(MASTER.BUS.WIDTH)), .SW(8), .OPT_LITTLE_ENDIAN(1'b0) ) u_@$(PREFIX) ( // {{{ .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), .i_reset(@$(SLAVE.BUS.CLOCK.RESET)), // @$(SLAVE.ANSIPORTLIST), .S_VALID(@$(STREAM)_valid && @$(STREAM)_id == 2), .S_READY(@$(PREFIX)_ready), .S_DATA(@$(STREAM)_data), .S_LAST(@$(STREAM)_last), @$(MASTER.ANSIPORTLIST) // }}} ); @MAIN.ALT= assign @$(PREFIX)_ready = 1'b0; @RTL.MAKE.GROUP=@$(DEVID) @RTL.MAKE.SUBD=wbi2c @RTL.MAKE.FILES=wbi2cdma.v @REGS.N=4 @REGS.0=0 R_@$(DEVID) @$(DEVID) @REGS.1=1 R_@$(DEVID)_ADDR @$(DEVID)ADDR @REGS.2=2 R_@$(DEVID)_BASE @$(DEVID)BASE @REGS.3=3 R_@$(DEVID)_LEN @$(DEVID)LEN ## ## board.h ## @BDEF.DEFN= #ifndef @$(DEVID)_H #define @$(DEVID)_H //////////////////////////////////////////////////////////////////////// // // I2C DMA data structures // {{{ //////////////////////////////////////////////////////////////////////// // // typedef struct @$(DEVID)_S { unsigned id_control, id_current, id_base, id_memlen; } @$(DEVID); #endif // @$(DEVID)_H // }}} @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=@$(DEVID) @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME)=((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); ## ================================================ FILE: auto-data/i2saudio.txt ================================================ ################################################################################ ## ## Filename: auto-data/i2saudio.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=i2saudio @ACCESS=I2SAUDIO @DEPENDS=ARBITRARY_CLOCK_GENERATOR_ACCESS @DEVID=AUDIO @SOURCE=audio_in @SINK=audio_out @NADDR=1 @MAIN.PORTLIST= o_i2s_lrclk, o_i2s_bclk, o_i2s_mclk, o_i2s_dac, i_i2s_adc @MAIN.IODECL= output wire o_i2s_lrclk, o_i2s_bclk, o_i2s_mclk, o_i2s_dac; input wire i_i2s_adc; @MAIN.DEFNS= //////////////////////////////////////////////////////////////////////// // // I2S Audio signal definitions // {{{ wire w_@$(PREFIX)_en; // Verilator lint_off UNUSED // // These wires may or may not be connected to anything ... wire w_@$(SINK)_valid, w_@$(SINK)_ready, w_@$(SINK)_last; wire [23:0] w_@$(SINK)_data; // // w_@$(SOURCE)... comes from the microphone (if present) wire w_@$(SOURCE)_valid, w_@$(SOURCE)_ready, w_@$(SOURCE)_last; wire [23:0] w_@$(SOURCE)_data; wire [31:0] w_@$(PREFIX)_debug; // Verilator lint_on UNUSED // }}} @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // I2S Audio signal handler // {{{ assign o_i2s_mclk = i_genclk_clk; assign w_@$(PREFIX)_en = 1'b1; axisi2s #( .BDIV(4'h1) ) u_@$(PREFIX) ( // {{{ .S_AXI_ACLK(i_clk), .S_AXI_ARESETN(!i_reset), // // Inputs to drive the speakers .S_AXIS_TVALID(w_@$(SINK)_valid), .S_AXIS_TREADY(w_@$(SINK)_ready), .S_AXIS_TDATA(w_@$(SINK)_data), .S_AXIS_TLAST(w_@$(SINK)_last), // // Outputs from the microphone .M_AXIS_TVALID(w_@$(SOURCE)_valid), .M_AXIS_TREADY(w_@$(SOURCE)_ready), .M_AXIS_TDATA(w_@$(SOURCE)_data), .M_AXIS_TLAST(w_@$(SOURCE)_last), // .i_mclk(o_i2s_mclk), .i_clken(w_@$(PREFIX)_en), .o_lrclk(o_i2s_lrclk), .o_bclk(o_i2s_bclk), .i_adc(i_i2s_adc), .o_dac(o_i2s_dac), .o_debug(w_@$(PREFIX)_debug) // }}} ); `ifndef AUDIOSINK_ACCESS assign w_@$(SINK)_valid = 0; assign w_@$(SINK)_data = 0; assign w_@$(SINK)_last = 0; `endif `ifndef AUDIOSOURCE_ACCESS assign w_@$(SOURCE)_ready = 1; `endif // }}} @MAIN.ALT= //////////////////////////////////////////////////////////////////////// // // (No) I2S Audio signal handler (option) // {{{ `ifndef AUDIOSINK_ACCESS assign w_@$(SINK)_valid = 0; assign w_@$(SINK)_data = 0; assign w_@$(SINK)_last = 0; `endif assign w_@$(SINK)_ready = 0; assign w_@$(SOURCE)_valid = 0; assign w_@$(SOURCE)_data = 0; assign w_@$(SOURCE)_last = 0; `ifndef AUDIOSOURCE_ACCESS assign w_@$(SOURCE)_ready = 0; `endif // }}} @XDC.INSERT= ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ sdrami/r_sys_reset* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/mclk_reset* }] 10.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_adc_fifo/rgray* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_adc_fifo/rgray_cross* }] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_adc_fifo/wgray* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_adc_fifo/wgray_cross* }] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_adc_fifo/mem_reg* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_adc_fifo/GEN_REGISTERED_READ.o_rd_data* }] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_dac_fifo/mem_reg* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_dac_fifo/GEN_REGISTERED_READ.o_rd_data* }] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_dac_fifo/rgray* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_dac_fifo/rgray_cross* }] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_dac_fifo/wgray* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_dac_fifo/wgray_cross* }] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/u_dac_fifo/wr_rgray* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/r_dac_data* }] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/lli2si/o_lrclk* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_pipe* }] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/lli2si/o_bclk* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_pipe* }] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/lli2si/o_dac* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_pipe* }] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *xgenclki/GEN_PLL.pll* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_pipe* }] 8.0 set_false_path -hold -from [get_cells -hier -filter {NAME=~ *xgenclki/GEN_PLL.pll* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_pipe* }] set_false_path -hold -from [get_cells -hier -filter {NAME=~ *xgenclki/GEN_PLL.pll* }] -rise_to [get_clocks -filter {NAME=~ *clk_pll_i* }] ## ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/lli2si/o_lrclk* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_debug* }] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/lli2si/o_bclk* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_debug* }] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/lli2si/o_dac* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_debug* }] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *xgenclki/GEN_PLL.pll* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_debug* }] 8.0 ## set_false_path -hold -from [get_cells -hier -filter {NAME=~ *xgenclki/GEN_PLL.pll* }] -to [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/xclk_debug* }] @RTL.MAKE.GROUP=AUDIO @RTL.MAKE.SUBD=audio @RTL.MAKE.FILES=axisi2s.v lli2s.v @REGS.N=1 @REGS.0= 0 R_@$(DEVID) @$(DEVID) ================================================ FILE: auto-data/icape.txt ================================================ ################################################################################ ## ## Filename: auto-data/icape.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: A description of how to connect the wbicapetwo interface for ## Xilinx's ICAPE2 interface to a wishbone bus. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=icape @NADDR=32 @ACCESS=CFG_ACCESS @SLAVE.TYPE=OTHER @SLAVE.BUS=wb32 @MAIN.PARAM= localparam ICAPE_LGDIV=3; @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // ICAPE2 driver/controller // {{{ //////////////////////////////////////////////////////////////////////// // // `ifdef VERILATOR reg r_@$(PREFIX)_ack; initial r_@$(PREFIX)_ack = 1'b0; always @(posedge i_clk) r_@$(PREFIX)_ack <= @$(SLAVE.PREFIX)_stb; assign @$(SLAVE.PREFIX)_ack = r_@$(PREFIX)_ack; assign @$(SLAVE.PREFIX)_stall = 1'b0; assign @$(SLAVE.PREFIX)_idata = 32'h00; `else wbicapetwo #( .LGDIV(ICAPE_LGDIV) ) u_@$(PREFIX) ( // {{{ .i_clk(i_clk), .i_reset(i_reset), @$(SLAVE.ANSIPORTLIST) // }}} ); `endif // }}} @REGS.NOTE=// FPGA CONFIG REGISTERS: 0x4e0-0x4ff @REGS.N=20 @REGS.0= 0 R_CFG_CRC FPGACRC @REGS.1= 1 R_CFG_FAR FPGAFAR @REGS.2= 2 R_CFG_FDRI FPGAFDRI @REGS.3= 3 R_CFG_FDRO FPGAFDRO @REGS.4= 4 R_CFG_CMD FPGACMD @REGS.5= 5 R_CFG_CTL0 FPGACTL0 @REGS.6= 6 R_CFG_MASK FPGAMASK @REGS.7= 7 R_CFG_STAT FPGASTAT @REGS.8= 8 R_CFG_LOUT FPGALOUT @REGS.9= 9 R_CFG_COR0 FPGACOR0 @REGS.10= 10 R_CFG_MFWR FPGAMFWR @REGS.11= 11 R_CFG_CBC FPGACBC @REGS.12= 12 R_CFG_IDCODE FPGAIDCODE @REGS.13= 13 R_CFG_AXSS FPGAAXSS @REGS.14= 14 R_CFG_COR1 FPGACOR1 @REGS.15= 16 R_CFG_WBSTAR WBSTAR @REGS.16= 17 R_CFG_TIMER CFGTIMER @REGS.17= 22 R_CFG_BOOTSTS BOOTSTS @REGS.18= 24 R_CFG_CTL1 FPGACTL1 @REGS.19= 31 R_CFG_BSPI FPGABSPI @BDEF.DEFN= // Offsets for the ICAPE2 interface #define CFG_CRC 0 #define CFG_FAR 1 #define CFG_FDRI 2 #define CFG_FDRO 3 #define CFG_CMD 4 #define CFG_CTL0 5 #define CFG_MASK 6 #define CFG_STAT 7 #define CFG_LOUT 8 #define CFG_COR0 9 #define CFG_MFWR 10 #define CFG_CBC 11 #define CFG_IDCODE 12 #define CFG_AXSS 13 #define CFG_COR1 14 #define CFG_WBSTAR 16 #define CFG_TIMER 17 #define CFG_BOOTSTS 22 #define CFG_CTL1 24 #define CFG_BSPI 31 @BDEF.IONAME=_icape[32] @BDEF.IOTYPE=unsigned @BDEF.OSDEF=_BOARD_HAS_ICAPETWO @BDEF.OSVAL=static volatile @$THIS.BDEF.IOTYPE *const _icape = ((unsigned *)@$[0x%08x](REGBASE)); @RTL.MAKE.GROUP=ICAP @RTL.MAKE.SUBD= @RTL.MAKE.FILES=wbicapetwo.v ================================================ FILE: auto-data/legalgen.txt ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: auto-data/legalgen.txt // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Computer Generated: This file is computer generated by AUTOFPGA. DO NOT EDIT. // DO NOT EDIT THIS FILE! // // CmdLine: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} ================================================ FILE: auto-data/mdio.txt ================================================ ################################################################################ ## ## Filename: auto-data/mdio.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: This file describes how the network MDIO core is to be ## connected to the rest of the design, for use by the autofpga ## program. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=mdio @NADDR=1024 @ACCESS=NETCTRL_ACCESS @SLAVE.TYPE=OTHER @SLAVE.BUS=wb32 @TOP.PORTLIST= // Toplevel ethernet MDIO ports o_eth_mdclk, io_eth_mdio @TOP.IODECL= // Ethernet control (MDIO) output wire o_eth_mdclk; inout wire io_eth_mdio; @TOP.DEFNS= // Ethernet control (MDIO) wire w_mdio, w_mdwe; @TOP.MAIN= o_eth_mdclk, w_mdio, w_mdwe, io_eth_mdio @TOP.INSERT= assign io_eth_mdio = (w_mdwe)?w_mdio : 1'bz; @MAIN.PORTLIST= // The ethernet MDIO wires o_mdclk, o_mdio, o_mdwe, i_mdio @MAIN.IODECL= // Ethernet control (MDIO) output wire o_mdclk, o_mdio, o_mdwe; input wire i_mdio; @MAIN.DEFNS= // Verilator lint_off UNUSED wire[31:0] @$(PREFIX)_debug; // Verilator lint_on UNUSED @MAIN.INSERT= enetctrl #( .CLKBITS(6) ) u_@$(PREFIX) ( .i_clk(i_clk), .i_reset(i_reset), @$(SLAVE.ANSIPORTLIST), .o_mdclk(o_mdclk), .o_mdio(o_mdio), .i_mdio(i_mdio), .o_mdwe(o_mdwe), .o_debug(@$(PREFIX)_debug) ); @MAIN.ALT= assign o_mdclk = 1'b1; assign o_mdio = 1'b1; assign o_mdwe = 1'b0; @REGS.NOTE= // Ethernet configuration (MDIO) port @REGS.N=30 @REGS.0= 0 R_MDIO_BMCR BMCR @REGS.1= 1 R_MDIO_BMSR BMSR @REGS.2= 2 R_MDIO_PHYIDR1 PHYIDR1 @REGS.3= 3 R_MDIO_PHYIDR2 PHYIDR2 @REGS.4= 4 R_MDIO_ANAR ANAR @REGS.5= 5 R_MDIO_ANLPAR ANLPAR @REGS.6= 6 R_MDIO_ANER ANER @REGS.7= 7 R_MDIO_ANNPTR ANNPTR @REGS.8= 8 R_MDIO_ANNPRR ANNPRR @REGS.9= 9 R_MDIO_GBCR GBCR @REGS.10= 10 R_MDIO_GBSR GBSR @REGS.11= 13 R_MDIO_MACR MACR @REGS.12= 14 R_MDIO_MAADR MAADR @REGS.13= 15 R_MDIO_GBESR GBESR @REGS.14= 16 R_MDIO_PHYCR PHYCR @REGS.15= 17 R_MDIO_PHYSR PHYSR @REGS.16= 18 R_MDIO_INER INER @REGS.17= 19 R_MDIO_INSR INSR ## 20-23 are reserved @REGS.18=24 R_MDIO_RXERC RXERC ## 25-26 are reserved @REGS.19=27 R_MDIO_LDPSR LDPSR @REGS.20=30 R_MDIO_EPAGSR EPAGSR @REGS.21=31 R_MDIO_PAGSEL PAGSEL ## @REGS.22=0 R_XMDIO_PC1R XPC1R @REGS.23=1 R_XMDIO_PS1R XPS1R @REGS.24=20 R_XMDIO_EEECR XEEECR @REGS.25=16 R_XMDIO_EEEWER XEEEWER @REGS.26=60 R_XMDIO_EEEAR XEEEAR @REGS.27=61 R_XMDIO_EEELPAR XEEELPAR @REGS.28=26 R_XMDIO_LACR XLACR @REGS.29=28 R_XMDIO_LCR XLCR @REGS.30=45 R_XMDIO_ACCR XACCR @BDEF.DEFN= // // The Ethernet MDIO interface // #define MDIO_BMCR 0x00 #define MDIO_BMSR 0x01 #define MDIO_PHYIDR1 0x02 // PHY ID Register #1 #define MDIO_PHYIDR2 0x03 // PHY ID Register #2 #define MDIO_ANAR 0x04 // Autonegotiation advertisement #define MDIO_ANLPAR 0x05 // Autonegotiation link partner ability #define MDIO_ANER 0x06 // Autonegotiation expansion #define MDIO_ANNPTR 0x07 // Autonegotiation next page #define MDIO_ANNPRR 0x08 // Autonegotiation link partner next page #define MDIO_GBCR 0x09 // 1GBase-T Control #define MDIO_GBSR 0x0a // 1GBase-T Status #define MDIO_MACR 0x0d // MMD Access control #define MDIO_MAADR 0x0e // MMD Access register/data #define MDIO_GBESR 0x0f #define MDIO_PHYCR 0x10 #define MDIO_PHYSR 0x11 #define MDIO_INER 0x12 #define MDIO_INSR 0x13 #define MDIO_LDPSR 0x1b #define MDIO_EPAGSR 0x1e #define MDIO_PAGSEL 0x1f #define XMDIO_PC1R 0x00 #define XMDIO_PS1R 0x01 #define XMDIO_EEECR 0x14 #define XMDIO_EEEWER 0x10 // #define XMDIO_EEEAR 0x // #define XMDIO_EEELPAR 0x18 #define XMDIO_LACR 0x1a #define XMDIO_LCR 0x1c // #define XMDIO_ACCR 0x1b typedef struct ENETMDIO_S { unsigned e_v[32][32]; } ENETMDIO; @BDEF.IOTYPE= ENETMDIO @BDEF.IONAME= io_netmdio @BDEF.OSDEF= _BOARD_HAS_NETMDIO @BDEF.OSVAL= static volatile @$THIS.BDEF.IOTYPE *const _mdio = ((@$THIS.BDEF.IOTYPE *)@$[0x%08x](REGBASE)); @SIM.CLOCK=clk @SIM.INCLUDE= #include "enetctrlsim.h" @SIM.DEFNS= #ifdef @$(ACCESS) ENETCTRLSIM *m_mdio; #endif // @$(ACCESS) @SIM.INIT= #ifdef @$(ACCESS) m_mdio = new ENETCTRLSIM; #endif // @$(ACCESS) @SIM.TICK= #ifdef @$(ACCESS) m_core->i_mdio = (*m_mdio)((m_core->i_reset)?1:0, m_core->o_mdclk, ((m_core->o_mdwe)&&(!m_core->o_mdio))?0:1); #else m_core->i_mdio = ((m_core->o_mdwe)&&(!m_core->o_mdio))?0:1; #endif // @$(ACCESS) @RTL.MAKE.SUBD=ethernet @RTL.MAKE.GROUP=ENETMDIO @RTL.MAKE.FILES=enetctrl.v ================================================ FILE: auto-data/meganet.txt ================================================ ################################################################################ ## ## Filename: auto-data/meganet.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2015-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=net @DEVID=MEGANET @ACCESS=@$(DEVID)_ACCESS @SLAVE.BUS=wb32 @NADDR=32 @SLAVE.TYPE=OTHER @$BASEPORT=6782 @$UARTDBGPORT=@$(BASEPORT) @$UARTPORT=@$(BASEPORT)+1 @$UDPDBGPORT=@$(BASEPORT)+2 @$DATAPORT=@$(BASEPORT)+3 @$HWMAC.0=0x82 @$HWMAC.1=0x33 @$HWMAC.2=0x48 @$HWMAC.3=0x02 @$HWMAC.4=0xe1 @$HWMAC.5=0xc8 @$IPADDR.0=192 @$IPADDR.1=168 @$IPADDR.2=15 @$IPADDR.3=29 @TOP.PORTLIST= // Ethernet control (packets) lines o_@$(PREFIX)_reset_n, i_@$(PREFIX)_rx_clk, i_@$(PREFIX)_rx_ctl, i_@$(PREFIX)_rxd, o_@$(PREFIX)_tx_clk, o_@$(PREFIX)_tx_ctl, o_@$(PREFIX)_txd @TOP.IODECL= // MegaNet I/O port declarations // {{{ output wire o_@$(PREFIX)_reset_n; input wire i_@$(PREFIX)_rx_clk, i_@$(PREFIX)_rx_ctl; input wire [3:0] i_@$(PREFIX)_rxd; output wire o_@$(PREFIX)_tx_clk, o_@$(PREFIX)_tx_ctl; output wire [3:0] o_@$(PREFIX)_txd; // }}} @TOP.DEFNS= // Mega Net definitions // {{{ wire [7:0] w_@$(PREFIX)_rxd, w_@$(PREFIX)_txd; wire w_@$(PREFIX)_rxdv, w_@$(PREFIX)_rxerr, w_@$(PREFIX)_txctl; wire [1:0] w_@$(PREFIX)_tx_clk; reg @$(PREFIX)_last_tck; // }}} @TOP.MAIN= // Ethernet (RGMII) connections o_net_reset_n, i_net_rx_clk, w_net_rxdv, w_net_rxdv ^ w_net_rxerr, w_net_rxd, w_net_tx_clk, w_net_txctl, w_net_txd @TOP.INSERT= // RGMII control // {{{ xiddr @$(PREFIX)rx0(i_@$(PREFIX)_rx_clk, i_@$(PREFIX)_rxd[0], { w_@$(PREFIX)_rxd[4], w_@$(PREFIX)_rxd[0] }); xiddr @$(PREFIX)rx1(i_@$(PREFIX)_rx_clk, i_@$(PREFIX)_rxd[1], { w_@$(PREFIX)_rxd[5], w_@$(PREFIX)_rxd[1] }); xiddr @$(PREFIX)rx2(i_@$(PREFIX)_rx_clk, i_@$(PREFIX)_rxd[2], { w_@$(PREFIX)_rxd[6], w_@$(PREFIX)_rxd[2] }); xiddr @$(PREFIX)rx3(i_@$(PREFIX)_rx_clk, i_@$(PREFIX)_rxd[3], { w_@$(PREFIX)_rxd[7], w_@$(PREFIX)_rxd[3] }); xiddr @$(PREFIX)rxc(i_@$(PREFIX)_rx_clk, i_@$(PREFIX)_rx_ctl, { w_@$(PREFIX)_rxdv, w_@$(PREFIX)_rxerr }); // // All of the below is about delaying the clock 90 degrees from the data // xoserdes @$(PREFIX)tx0(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_@$(PREFIX)_txd[0]}}, {(2){w_@$(PREFIX)_txd[4]}} }, o_@$(PREFIX)_txd[0]); xoserdes @$(PREFIX)tx1(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_@$(PREFIX)_txd[1]}}, {(2){w_@$(PREFIX)_txd[5]}} }, o_@$(PREFIX)_txd[1]); xoserdes @$(PREFIX)tx2(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_@$(PREFIX)_txd[2]}}, {(2){w_@$(PREFIX)_txd[6]}} }, o_@$(PREFIX)_txd[2]); xoserdes @$(PREFIX)tx3(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_@$(PREFIX)_txd[3]}}, {(2){w_@$(PREFIX)_txd[7]}} }, o_@$(PREFIX)_txd[3]); always @(posedge s_clk_125mhz) @$(PREFIX)_last_tck <= w_@$(PREFIX)_tx_clk[0]; xoserdes @$(PREFIX)txc(s_clk_125mhz, pll_reset, s_clk_250mhz, {(4){w_@$(PREFIX)_txctl}}, o_@$(PREFIX)_tx_ctl ); xoserdes @$(PREFIX)txck(s_clk_125mhz, pll_reset, s_clk_250mhz, {@$(PREFIX)_last_tck, {(2){w_@$(PREFIX)_tx_clk[1]}},w_@$(PREFIX)_tx_clk[0]},o_@$(PREFIX)_tx_clk); // xoserdes @$(PREFIX)txck(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_@$(PREFIX)_tx_clk[1]}},{(2){w_@$(PREFIX)_tx_clk[0]}} }, o_@$(PREFIX)_tx_clk); // }}} @MAIN.PORTLIST= // Ethernet control (packets) lines o_@$(PREFIX)_reset_n, // eth_int_b // Interrupt, leave floating // eth_pme_b // Power management event, leave floating i_@$(PREFIX)_rx_clk, i_@$(PREFIX)_rx_dv, i_@$(PREFIX)_rx_err, i_@$(PREFIX)_rxd, o_@$(PREFIX)_tx_clk, o_@$(PREFIX)_tx_ctl, o_@$(PREFIX)_txd @MAIN.PARAM= parameter [15:0] UDP_DBGPORT = @$(UDPDBGPORT); localparam [47:0] DEF_HWMAC = 48'h@$[%02x](HWMAC.0)_@$[%02x](HWMAC.1)_@$[%02x](HWMAC.2)_@$[%02x](HWMAC.3)_@$[%02x](HWMAC.4)_@$[%02x](HWMAC.5); localparam [31:0] DEF_IPADDR = { 8'd@$(IPADDR.0), 8'd@$(IPADDR.1), 8'd@$(IPADDR.2), 8'd@$(IPADDR.3) }; @MAIN.IODECL= // Ethernet (RGMII) control // {{{ // Verilator lint_off SYNCASYNCNET output wire o_net_reset_n; // Verilator lint_on SYNCASYNCNET input wire i_@$(PREFIX)_rx_clk, i_@$(PREFIX)_rx_dv, i_@$(PREFIX)_rx_err; input wire [7:0] i_@$(PREFIX)_rxd; output wire [1:0] o_@$(PREFIX)_tx_clk; output wire o_@$(PREFIX)_tx_ctl; output wire [7:0] o_@$(PREFIX)_txd; // }}} @MAIN.DEFNS= // Ethernet (RGMII) control // {{{ // Verilator lint_off UNUSED wire [47:0] @$(PREFIX)_hwmac, @$(PREFIX)_last_ping_hwmac; wire [31:0] @$(PREFIX)_ip_addr, @$(PREFIX)_last_ping_ipaddr; wire @$(PREFIX)cpurx_valid, @$(PREFIX)cpurx_ready; wire [31:0] @$(PREFIX)cpurx_data; wire [1:0] @$(PREFIX)cpurx_bytes; wire @$(PREFIX)cpurx_last, @$(PREFIX)cpurx_abort; wire @$(PREFIX)cputx_valid, @$(PREFIX)cputx_ready, @$(PREFIX)cputx_last, @$(PREFIX)cputx_abort; wire [31:0] @$(PREFIX)cputx_data; wire [1:0] @$(PREFIX)cputx_bytes; wire @$(PREFIX)_dbg_valid, @$(PREFIX)_dbg_ready, @$(PREFIX)_dbg_last; wire [31:0] @$(PREFIX)_dbg_data; wire [1:0] @$(PREFIX)_dbg_bytes; wire @$(PREFIX)_high_speed; wire @$(PREFIX)_debug_clk; wire [31:0] @$(PREFIX)_debug; wire ign_rxpkt_@$(PREFIX)_ready; // Verilator lint_on UNUSED // }}} @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // MegaNET @$(DEVID) // {{{ //////////////////////////////////////////////////////////////////////// // // meganet #( // {{{ .DEF_HWMAC(DEF_HWMAC), .DEF_IPADDR(DEF_IPADDR), .UDP_DBGPORT(UDP_DBGPORT) // }}} ) u_@$(PREFIX) ( // {{{ .S_AXI_ACLK(i_clk), .S_AXI_ARESETN(!i_reset), // .o_hwmac(@$(PREFIX)_hwmac), .o_ipaddr(@$(PREFIX)_ip_addr), .o_ping_hwmac(@$(PREFIX)_last_ping_hwmac), .o_ping_ipaddr(@$(PREFIX)_last_ping_ipaddr), // Wishbone port // {{{ @$(SLAVE.ANSIPORTLIST), // }}} // ifdef @$(DEVID)CPUTX_ACCESS // {{{ .S_CPU_VALID(@$(PREFIX)cputx_valid), .S_CPU_READY(@$(PREFIX)cputx_ready), .S_CPU_DATA(@$(PREFIX)cputx_data), .S_CPU_BYTES(@$(PREFIX)cputx_bytes), .S_CPU_LAST(@$(PREFIX)cputx_last), .S_CPU_ABORT(@$(PREFIX)cputx_abort), // }}} `ifdef NETBUS_ACCESS // {{{ .S_DBG_VALID(@$(PREFIX)bus_valid), .S_DBG_READY(@$(PREFIX)bus_ready), .S_DBG_DATA(@$(PREFIX)bus_pkdata), // .S_DBG_BYTES(@$(PREFIX)bus_bytes), .S_DBG_LAST(@$(PREFIX)bus_last), `else .S_DBG_VALID(1'b0), .S_DBG_READY(@$(PREFIX)_dbg_ready), .S_DBG_DATA(32'h0), .S_DBG_LAST(1'b1), `endif // }}} // Data interface // {{{ .S_DATA_VALID(1'b0), .S_DATA_READY(ign_rxpkt_@$(PREFIX)_ready), .S_DATA_DATA(32'h0), .S_DATA_BYTES(2'h0), .S_DATA_LAST(1'b1), // }}} // ifdef @$(DEVID)CPURX_ACCESS // {{{ .M_CPU_VALID(@$(PREFIX)cpurx_valid), .M_CPU_READY(@$(PREFIX)cpurx_ready), .M_CPU_DATA(@$(PREFIX)cpurx_data), .M_CPU_BYTES(@$(PREFIX)cpurx_bytes), .M_CPU_LAST(@$(PREFIX)cpurx_last), .M_CPU_ABORT(@$(PREFIX)cpurx_abort), // }}} // Debug IP/UDP RX packets // {{{ .M_DBG_VALID(@$(PREFIX)_dbg_valid), .M_DBG_READY(@$(PREFIX)_dbg_ready), .M_DBG_DATA( @$(PREFIX)_dbg_data), .M_DBG_BYTES(@$(PREFIX)_dbg_bytes), .M_DBG_LAST( @$(PREFIX)_dbg_last), // }}} // Interface to top-level IOs // {{{ .o_net_reset_n(o_@$(PREFIX)_reset_n), .i_net_rx_clk(i_@$(PREFIX)_rx_clk), .i_net_rx_dv(i_@$(PREFIX)_rx_dv), .i_net_rx_err(i_@$(PREFIX)_rx_err), .i_net_rxd(i_@$(PREFIX)_rxd), // .i_net_tx_clk(i_net_tx_clk), .o_net_tx_ck(o_@$(PREFIX)_tx_clk), .o_net_tx_ctl(o_@$(PREFIX)_tx_ctl), .o_net_txd(o_@$(PREFIX)_txd), // }}} .o_debug_clk(@$(PREFIX)_debug_clk), .o_debug(@$(PREFIX)_debug) // }}} ); `ifndef NETBUS_ACCESS // {{{ assign @$(PREFIX)_dbg_ready = 1'b1; // Verilator lint_off UNUSED wire unused_@$(PREFIX)_dbgrx; assign unused_@$(PREFIX)_dbgrx = &{ 1'b0, @$(PREFIX)_dbg_valid, @$(PREFIX)_dbg_data, @$(PREFIX)_dbg_bytes, @$(PREFIX)_dbg_last }; // Verilator lint_on UNUSED // }}} `endif `ifndef @$(DEVID)CPURX_ACCESS // {{{ assign @$(PREFIX)cpurx_ready = 1'b1; // Verilator lint_off UNUSED wire unused_@$(PREFIX)_cpu_rx; assign unused_@$(PREFIX)_cpu_rx = &{ 1'b0, @$(PREFIX)cpurx_valid, @$(PREFIX)cpurx_data, @$(PREFIX)cpurx_bytes, @$(PREFIX)cpurx_abort, @$(PREFIX)cpurx_last }; // Verilator lint_on UNUSED // }}} `endif `ifndef @$(DEVID)CPUTX_ACCESS // {{{ assign @$(PREFIX)cputx_valid = 1'b0; assign @$(PREFIX)cputx_data = 32'h0; assign @$(PREFIX)cputx_bytes = 2'h0; assign @$(PREFIX)cputx_last = 1'b1; assign @$(PREFIX)cputx_abort = 1'b0; // }}} `endif // }}} @REGDEFS.H.INCLUDE= #ifndef FPGAPORT #define FPGAPORT @$(BASEPORT) #define UARTDBGPORT @$(UARTDBGPORT) #define UARTPORT @$(UARTPORT) #define UDP_DBGPORT @$(UDPDBGPORT) #define UDP_DATAPORT @$(DATAPORT) #endif @REGS.N=19 @REGS.NOTE=// Meganet register definitions @REGS.0= 0 R_@$(DEVID)_RXCMD @$(DEVID)RX @REGS.1= 1 R_@$(DEVID)_TXCMD @$(DEVID)TX @REGS.2= 2 R_@$(DEVID)_MACHI @$(DEVID)MACHI @REGS.3= 3 R_@$(DEVID)_MACLO @$(DEVID)MACLO @REGS.4= 4 R_@$(DEVID)_IPADDR @$(DEVID)IPADDR @$(DEVID)IP @REGS.5= 5 R_@$(DEVID)_RXMISS @$(DEVID)MISS @REGS.6= 6 R_@$(DEVID)_RXERR @$(DEVID)ERR @REGS.7= 7 R_@$(DEVID)_RXCRC @$(DEVID)CRCER @REGS.8= 8 R_@$(DEVID)_DBGSEL @$(DEVID)DBGSL @REGS.9= 8 R_@$(DEVID)_RXPKTS @$(DEVID)RXPKT @REGS.10= 9 R_@$(DEVID)_ARPRX @$(DEVID)ARPRX @REGS.11= 10 R_@$(DEVID)_ICMPRX @$(DEVID)ICMRX @REGS.12= 11 R_@$(DEVID)_TXPKTS @$(DEVID)TXPKT @REGS.13= 12 R_@$(DEVID)_ARPTX @$(DEVID)ARPTX @REGS.14= 13 R_@$(DEVID)_ICMPTX @$(DEVID)ICMTX @REGS.15= 14 R_@$(DEVID)_DATATX @$(DEVID)DATTX @REGS.16= 15 R_@$(DEVID)_TXABORTS @$(DEVID)ABRTS @REGS.17= 16 R_@$(DEVID)_DBGRX @$(DEVID)DBGRX @REGS.18= 17 R_@$(DEVID)_DBGTX @$(DEVID)DBGTX @BDEF.INCLUDE= #ifndef UDP_DBGPORT #define UDP_DBGPORT @$(UDPDBGPORT) #define UDP_DATAPORT @$(DATAPORT) #endif @BDEF.DEFN= // Network stream/packet interface // {{{ #ifndef ENETSTREAM_H #define ENETSTREAM_H typedef struct ENETSTREAM_S { unsigned n_rxcmd, n_txcmd; unsigned long n_mac; unsigned n_ipaddr; unsigned n_rxmiss, n_rxerr, n_rxcrc; // unsigned n_rxpkt, n_rxarp, n_rxicmp; unsigned n_txpkt, n_txarp, n_txicmp; unsigned n_data, n_aborts; unsigned n_rxdbg, n_txdbg; } ENETSTREAM; #endif // }}} @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=ENETSTREAM @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((ENETSTREAM *)@$[0x%08x](REGBASE)); @RTL.MAKE.GROUP=ENET @RTL.MAKE.SUBD=ethernet @RTL.MAKE.FILES= enetstream.v addecrc.v addemac.v addepad.v addepreamble.v rxecrc.v rxehwmac.v rxeipchk.v rxemin.v rxepacket.v rxepreambl.v axinwidth.v axincdc.v pktgate.v txespeed.v xiddr.v @CLOCK.NAME=@$(PREFIX)_rx_clk @$CLOCK.FREQUENCY=125000000 @SIM.CLOCK=@$(PREFIX)_rx_clk @SIM.INCLUDE= #include "netsim.h" @SIM.DEFNS= NETSIM *m_@$(PREFIX); @SIM.INIT= // Network init // {{{ m_@$(PREFIX) = new NETSIM(); // DBGPORT: @$(UDPDBGPORT), DATAPORT: @$(DATAPORT); m_@$(PREFIX)->external_mac[0] = 0xde; m_@$(PREFIX)->external_mac[1] = 0xad; m_@$(PREFIX)->external_mac[2] = 0xbe; m_@$(PREFIX)->external_mac[3] = 0xef; m_@$(PREFIX)->external_mac[4] = 0xda; m_@$(PREFIX)->external_mac[5] = 0xd0 | (@$(HWMAC.5) & 0x0f); m_@$(PREFIX)->external_ip[0] = 127; m_@$(PREFIX)->external_ip[1] = 0; m_@$(PREFIX)->external_ip[2] = 0; m_@$(PREFIX)->external_ip[3] = 1; m_@$(PREFIX)->local_mac[0] = 0x@$[%02x](HWMAC.0) & 0x0ff; m_@$(PREFIX)->local_mac[1] = 0x@$[%02x](HWMAC.1) & 0x0ff; m_@$(PREFIX)->local_mac[2] = 0x@$[%02x](HWMAC.2) & 0x0ff; m_@$(PREFIX)->local_mac[3] = 0x@$[%02x](HWMAC.3) & 0x0ff; m_@$(PREFIX)->local_mac[4] = 0x@$[%02x](HWMAC.4) & 0x0ff; m_@$(PREFIX)->local_mac[5] = 0x@$[%02x](HWMAC.5) & 0x0ff; m_@$(PREFIX)->local_ip[0] = 0x@$[%02x](IPADDR.0) & 0x0ff; // @$[%3d](IPADDR.0) m_@$(PREFIX)->local_ip[1] = 0x@$[%02x](IPADDR.1) & 0x0ff; // @$[%3d](IPADDR.1) m_@$(PREFIX)->local_ip[2] = 0x@$[%02x](IPADDR.2) & 0x0ff; // @$[%3d](IPADDR.2) m_@$(PREFIX)->local_ip[3] = 0x@$[%02x](IPADDR.3) & 0x0ff; // @$[%3d](IPADDR.3) m_@$(PREFIX)->local_ipu = 0x@$[%02x](IPADDR.0)@$[%02x](IPADDR.1)@$[%02x](IPADDR.2)@$[%02x](IPADDR.3); // }}} @SIM.TICK= // Simulate the network // {{{ { unsigned rxtmp = (*m_@$(PREFIX))(m_core->o_net_reset_n, m_core->o_@$(PREFIX)_tx_ctl, m_core->o_@$(PREFIX)_txd); m_core->i_@$(PREFIX)_rx_err = 0; if (rxtmp & 0x0100) { m_core->i_@$(PREFIX)_rx_dv = 1; m_core->i_@$(PREFIX)_rxd = rxtmp & 0x0ff; } else { m_core->i_@$(PREFIX)_rx_dv = 0; m_core->i_@$(PREFIX)_rxd = 0x044; } } // }}} ## @XDC.INSERT= ################################################################################ # # MegaNET # {{{ create_clock -period 8.0 -name NETRX -waveform { 0.0 4.0 } -add [get_ports {i_net_rx_clk} ]; ## All clocks set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *afifo*/wgray_r*}] -to [ get_cells -hier -filter {NAME =~ *afifo*/wgray_cross*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *afifo*/rgray_r*}] -to [ get_cells -hier -filter {NAME =~ *afifo*/rgray_cross*}] 8.0 ## CLK -> NETTX ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *sdrami/r_sys_reset*}] -to [ get_cells -hier -filter {NAME =~ *pre_tx_reset*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/o_net_reset*}] -to [ get_cells -hier -filter {NAME =~*n_tx_reset*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/*afifo*}] -to [ get_cells -hier -filter {NAME =~*u_@$(PREFIX)/*afifo*/GEN_REGISTERED_READ.o_rd_data*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *sdrami/r_sys_reset*}] -to [ get_cells -hier -filter {NAME =~*net_core/preq_tx_reset*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/o_net_reset*}] -to [ get_cells -hier -filter {NAME =~*net_core/q_tx_reset*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/tfrtxspd/a_req*}] -to [ get_cells -hier -filter {NAME =~*u_@$(PREFIX)/net_core/tfrtxspd/b_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/tfrtxspd/a_data*}] -to [ get_cells -hier -filter {NAME =~*u_@$(PREFIX)/net_core/tfrtxspd/o_b_data*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/hw_mac*}] -to [ get_cells -hier -filter {NAME =~*txmaci/r_hw*}] 8.0 ## NETTX -> CLK ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_adc/b_reset_n*}] -to [ get_cells -hier -filter {NAME =~ *u_adc/b_last*}] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_adc/b_reset_n*}] -to [ get_cells -hier -filter {NAME =~ *u_adc/b_pipe*}] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_adc/b_reset_n*}] -to [ get_cells -hier -filter {NAME =~ *u_adc/b_req*}] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_adc/b_reset_n*}] -to [ get_cells -hier -filter {NAME =~ *u_adc/o_b_valid*}] 8.0 # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/tx_spd*}] -to [ get_cells -hier -filter {NAME =~ *tfrtxspd/a_data*}] 8.0 # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/tx_spd*}] -to [ get_cells -hier -filter {NAME =~ *net_core/o_wb_data*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/tfrtxspd/b_last*}] -to [ get_cells -hier -filter {NAME =~ *tfrtxspd/a_pipe*}] 8.0 ## NETTX -> NETTX_D # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/txspdi/o_ck*}] -to [ get_cells -hier -filter {NAME =~ txck/ODDR*}] 2.0 ## NETTX -> NETRX ## CLK -> NETRX # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *sdrami/r_sys_reset*}] -to [ get_cells -hier -filter {NAME =~ *net_core/pre_rx_reset*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *sdrami/r_sys_reset*}] -to [ get_cells -hier -filter {NAME =~ *net_core/preq_rx_reset*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *sdrami/r_sys_reset*}] -to [ get_cells -hier -filter {NAME =~ *tfrrxspd/a_ack*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *sdrami/r_sys_reset*}] -to [ get_cells -hier -filter {NAME =~*tfrrxspd/a_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *sdrami/r_sys_reset*}] -to [ get_cells -hier -filter {NAME =~ *tfrrxspd/a_req*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/o_net_reset_n*}] -to [ get_cells -hier -filter {NAME =~ *n_rx_reset*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/o_net_reset_n*}] -to [ get_cells -hier -filter {NAME =~ *q_rx_reset*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/tfrrxspd/b_last*}] -to [ get_cells -hier -filter {NAME =~ *tfrrxspd/a_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/my_ipaddr*}] -to [ get_cells -hier -filter {NAME =~*o_no_match*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/my_ipaddr*}] -to [ get_cells -hier -filter {NAME =~*o_match*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/my_ipaddr*}] -to [ get_cells -hier -filter {NAME =~*rxipci/o_err*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/my_ipaddr*}] -to [ get_cells -hier -filter {NAME =~*rxipci/o_err*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/hw_mac*}] -to [ get_cells -hier -filter {NAME =~*rxmaci/r_hwmac*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/n_rx_reset*}] -to [ get_cells -hier -filter {NAME =~*u_@$(PREFIX)/net_core/tfr_rxipaddr/b_last*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/n_rx_reset*}] -to [ get_cells -hier -filter {NAME =~*u_@$(PREFIX)/net_core/tfr_rxipaddr/b_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/n_rx_reset*}] -to [ get_cells -hier -filter {NAME =~*u_@$(PREFIX)/net_core/tfr_rxipaddr/b_req*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *tfr_rxipaddr/b_last*}] -to [ get_cells -hier -filter {NAME =~*tfr_rxipaddr/a_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *tfr_rxipaddr/a_data*}] -to [ get_cells -hier -filter {NAME =~*tfr_rxipaddr/o_b_data*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *tfr_rxipaddr/a_req*}] -to [ get_cells -hier -filter {NAME =~*tfr_rxipaddr/o_b_data*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *tfr_rxipaddr/a_req*}] -to [ get_cells -hier -filter {NAME =~*tfr_rxipaddr/b_pipe*}] 8.0 # NETRX ->CLK # set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/tfrrxspd/a_data*}] -to [ get_cells -hier -filter {NAME =~ *net_core/tfrrxspd/o_b_data*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/n_rx_reset*}] -to [ get_cells -hier -filter {NAME =~ *net_core/tfrrxspd/b_last*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/n_rx_reset*}] -to [ get_cells -hier -filter {NAME =~ *net_core/tfrrxspd/b_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/n_rx_reset*}] -to [ get_cells -hier -filter {NAME =~ *net_core/tfrrxspd/b_req*}] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/txclk_check*}] -to [ get_cells -hier -filter {NAME =~ *net_core/net_reset_timer*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/n_rx_crcerr*}] -to [ get_cells -hier -filter {NAME =~ *net_core/rx_crc_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/tfrrxspd/a*}] -to [ get_cells -hier -filter {NAME =~ *net_core/tfrrxspd/b*}] 8.0 ## set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/rxclk_check*}] -to [ get_cells -hier -filter {NAME =~ *net_core/net_reset_timer*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/n_rx_miss*}] -to [ get_cells -hier -filter {NAME =~ *net_core/rx_miss_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/tfr_*/a_data*}] -to [ get_cells -hier -filter {NAME =~ *u_@$(PREFIX)/tfr*/o_b_data*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/tfr_*/a_req*}] -to [ get_cells -hier -filter {NAME =~ *u_@$(PREFIX)/tfr*/b_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/tfr_*/b_last*}] -to [ get_cells -hier -filter {NAME =~ *u_@$(PREFIX)/tfr*/a_pipe*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *u_@$(PREFIX)/net_core/n_rx_err*}] -to [ get_cells -hier -filter {NAME =~ *u_@$(PREFIX)/net_core/rx_err_pipe*}] 8.0 ## ## ARP ## {{{ set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/hw_mac*}] -to [ get_cells -hier -filter {NAME =~*arp/M_AXIN_DATA*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/hw_mac*}] -to [ get_cells -hier -filter {NAME =~*u_@$(PREFIX)/u_arp/M_AXIN_DATA*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *net_core/my_ipaddr*}] -to [ get_cells -hier -filter {NAME =~*u_@$(PREFIX)/u_arp/M_AXIN_DATA*}] 8.0 ## }}} ## ICMP ## {{{ ## }}} ## # }}} ================================================ FILE: auto-data/nexysv.xdc ================================================ ### This file is a general .xdc for the Nexys Video Rev. A ### To use it in a project: ### - uncomment the lines corresponding to used pins ### - rename the used ports (in each line, after get_ports) according to the top level signal names in the project ## Clock Signal set_property -dict {PACKAGE_PIN R4 IOSTANDARD LVCMOS33} [get_ports i_clk] create_clock -period 10.000 -name INCLK -waveform {0.000 5.000} -add [get_ports i_clk] ## FMC Transceiver clocks (Must be set to value provided by Mezzanine card, currently set to 156.25 MHz) ## Note: This clock is attached to a MGTREFCLK pin #set_property -dict { PACKAGE_PIN E6 } [get_ports { GTP_CLK_N }]; #set_property -dict { PACKAGE_PIN F6 } [get_ports { GTP_CLK_P }]; #create_clock -add -name gtpclk0_pin -period 6.400 -waveform {0 3.200} [get_ports {GTP_CLK_P}]; #set_property -dict { PACKAGE_PIN E10 } [get_ports { FMC_MGT_CLK_N }]; #set_property -dict { PACKAGE_PIN F10 } [get_ports { FMC_MGT_CLK_P }]; #create_clock -add -name mgtclk1_pin -period 6.400 -waveform {0 3.200} [get_ports {FMC_MGT_CLK_P}]; ## LEDs # set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS25} [get_ports {o_led[0]}] # set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS25} [get_ports {o_led[1]}] # set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS25} [get_ports {o_led[2]}] # set_property -dict {PACKAGE_PIN U16 IOSTANDARD LVCMOS25} [get_ports {o_led[3]}] # set_property -dict {PACKAGE_PIN V15 IOSTANDARD LVCMOS25} [get_ports {o_led[4]}] # set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS25} [get_ports {o_led[5]}] # set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS25} [get_ports {o_led[6]}] # set_property -dict {PACKAGE_PIN Y13 IOSTANDARD LVCMOS25} [get_ports {o_led[7]}] ## Buttons # set_property -dict {PACKAGE_PIN B22 IOSTANDARD LVCMOS12} [get_ports i_btnc] # set_property -dict {PACKAGE_PIN D22 IOSTANDARD LVCMOS12} [get_ports i_btnd] # set_property -dict {PACKAGE_PIN C22 IOSTANDARD LVCMOS12} [get_ports i_btnl] # set_property -dict {PACKAGE_PIN D14 IOSTANDARD LVCMOS12} [get_ports i_btnr] # set_property -dict {PACKAGE_PIN F15 IOSTANDARD LVCMOS12} [get_ports i_btnu] # set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS12} [get_ports i_cpu_resetn] ## Switches # set_property -dict {PACKAGE_PIN E22 IOSTANDARD LVCMOS12} [get_ports {i_sw[0]}] # set_property -dict {PACKAGE_PIN F21 IOSTANDARD LVCMOS12} [get_ports {i_sw[1]}] # set_property -dict {PACKAGE_PIN G21 IOSTANDARD LVCMOS12} [get_ports {i_sw[2]}] # set_property -dict {PACKAGE_PIN G22 IOSTANDARD LVCMOS12} [get_ports {i_sw[3]}] # set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS12} [get_ports {i_sw[4]}] # set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS12} [get_ports {i_sw[5]}] # set_property -dict {PACKAGE_PIN K13 IOSTANDARD LVCMOS12} [get_ports {i_sw[6]}] # set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS12} [get_ports {i_sw[7]}] ## OLED Display # set_property -dict { PACKAGE_PIN W22 IOSTANDARD LVCMOS33 } [get_ports { o_oled_dcn }]; #IO_L7N_T1_D10_14 Sch=oled_dc SPI select port # set_property -dict { PACKAGE_PIN U21 IOSTANDARD LVCMOS33 } [get_ports { o_oled_reset_n }]; #IO_L4N_T0_D05_14 Sch=oled_res RESET # set_property -dict { PACKAGE_PIN W21 IOSTANDARD LVCMOS33 } [get_ports { o_oled_sck }]; #IO_L7P_T1_D09_14 Sch=oled_sclk SPI Clk port # set_property -dict { PACKAGE_PIN Y22 IOSTANDARD LVCMOS33 } [get_ports { o_oled_mosi }]; #IO_L9N_T1_DQS_D13_14 Sch=oled_sdin Data port # set_property -dict { PACKAGE_PIN P20 IOSTANDARD LVCMOS33 } [get_ports { o_oled_panel_en }]; #IO_0_14 Sch=oled_vbat VBAT # set_property -dict { PACKAGE_PIN V22 IOSTANDARD LVCMOS33 } [get_ports { o_oled_logic_en }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=oled_vdd VDD ## HDMI in # set_property -dict { PACKAGE_PIN AA5 IOSTANDARD LVCMOS33 } [get_ports io_hdmi_in_cec ] # set_property -dict { PACKAGE_PIN W4 IOSTANDARD TMDS_33 } [get_ports i_hdmi_in_clk_n ] # set_property -dict { PACKAGE_PIN V4 IOSTANDARD TMDS_33 } [get_ports i_hdmi_in_clk_p ] # set_property -dict { PACKAGE_PIN AB12 IOSTANDARD LVCMOS25 } [get_ports o_hdmi_in_hpa ] # set_property -dict { PACKAGE_PIN Y4 IOSTANDARD LVCMOS33 } [get_ports io_hdmi_in_scl ] # set_property -dict { PACKAGE_PIN AB5 IOSTANDARD LVCMOS33 } [get_ports io_hdmi_in_sda ] # set_property -dict { PACKAGE_PIN R3 IOSTANDARD LVCMOS33 } [get_ports o_hdmi_in_txen ] # set_property -dict { PACKAGE_PIN AA3 IOSTANDARD TMDS_33 } [get_ports { i_hdmi_in_n[0] } ]; #IO_L9N_T1_DQS_34 Sch=hdmi_rx_n[0] # set_property -dict { PACKAGE_PIN Y3 IOSTANDARD TMDS_33 } [get_ports { i_hdmi_in_p[0] } ]; #IO_L9P_T1_DQS_34 Sch=hdmi_rx_p[0] # set_property -dict { PACKAGE_PIN Y2 IOSTANDARD TMDS_33 } [get_ports { i_hdmi_in_n[1] } ]; #IO_L4N_T0_34 Sch=hdmi_rx_n[1] # set_property -dict { PACKAGE_PIN W2 IOSTANDARD TMDS_33 } [get_ports { i_hdmi_in_p[1] } ]; #IO_L4P_T0_34 Sch=hdmi_rx_p[1] # set_property -dict { PACKAGE_PIN V2 IOSTANDARD TMDS_33 } [get_ports { i_hdmi_in_n[2] } ]; #IO_L2N_T0_34 Sch=hdmi_rx_n[2] # set_property -dict { PACKAGE_PIN U2 IOSTANDARD TMDS_33 } [get_ports { i_hdmi_in_p[2] } ]; #IO_L2P_T0_34 Sch=hdmi_rx_p[2] ## HDMI out # set_property -dict { PACKAGE_PIN AA4 IOSTANDARD LVCMOS33 } [get_ports io_hdmi_out_cec ] # set_property -dict { PACKAGE_PIN U1 IOSTANDARD TMDS_33 } [get_ports o_hdmi_out_clk_n ] # set_property -dict { PACKAGE_PIN T1 IOSTANDARD TMDS_33 } [get_ports o_hdmi_out_clk_p ] # set_property -dict { PACKAGE_PIN AB13 IOSTANDARD LVCMOS25 } [get_ports i_hdmi_out_hpd_n ] # set_property -dict { PACKAGE_PIN U3 IOSTANDARD LVCMOS33 } [get_ports { io_hdmi_out_scl }]; #IO_L6P_T0_34 Sch=hdmi_tx_rscl # set_property -dict { PACKAGE_PIN V3 IOSTANDARD LVCMOS33 } [get_ports { io_hdmi_out_sda }]; #IO_L6N_T0_VREF_34 Sch=hdmi_tx_rsda # set_property -dict { PACKAGE_PIN Y1 IOSTANDARD TMDS_33 } [get_ports { o_hdmi_out_n[0] }]; #IO_L5N_T0_34 Sch=hdmi_tx_n[0] # set_property -dict { PACKAGE_PIN W1 IOSTANDARD TMDS_33 } [get_ports { o_hdmi_out_p[0] }]; #IO_L5P_T0_34 Sch=hdmi_tx_p[0] # set_property -dict { PACKAGE_PIN AB1 IOSTANDARD TMDS_33 } [get_ports { o_hdmi_out_n[1] }]; #IO_L7N_T1_34 Sch=hdmi_tx_n[1] # set_property -dict { PACKAGE_PIN AA1 IOSTANDARD TMDS_33 } [get_ports { o_hdmi_out_p[1] }]; #IO_L7P_T1_34 Sch=hdmi_tx_p[1] # set_property -dict { PACKAGE_PIN AB2 IOSTANDARD TMDS_33 } [get_ports { o_hdmi_out_n[2] }]; #IO_L8N_T1_34 Sch=hdmi_tx_n[2] # set_property -dict { PACKAGE_PIN AB3 IOSTANDARD TMDS_33 } [get_ports { o_hdmi_out_p[2] }]; #IO_L8P_T1_34 Sch=hdmi_tx_p[2] ## Display Port #set_property -dict { PACKAGE_PIN AB10 IOSTANDARD LVDS } [get_ports { dp_tx_aux_n }]; #IO_L8N_T1_13 Sch=dp_tx_aux_n #set_property -dict { PACKAGE_PIN AA11 IOSTANDARD LVDS } [get_ports { dp_tx_aux_n }]; #IO_L9N_T1_DQS_13 Sch=dp_tx_aux_n #set_property -dict { PACKAGE_PIN AA9 IOSTANDARD LVDS } [get_ports { dp_tx_aux_p }]; #IO_L8P_T1_13 Sch=dp_tx_aux_p #set_property -dict { PACKAGE_PIN AA10 IOSTANDARD LVDS } [get_ports { dp_tx_aux_p }]; #IO_L9P_T1_DQS_13 Sch=dp_tx_aux_p #set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { dp_tx_hpd }]; #IO_25_14 Sch=dp_tx_hpd ## Audio Codec #set_property -dict { PACKAGE_PIN T4 IOSTANDARD LVCMOS33 } [get_ports { ac_adc_sdata }]; #IO_L13N_T2_MRCC_34 Sch=ac_adc_sdata #set_property -dict { PACKAGE_PIN T5 IOSTANDARD LVCMOS33 } [get_ports { ac_bclk }]; #IO_L14P_T2_SRCC_34 Sch=ac_bclk #set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports { ac_dac_sdata }]; #IO_L15P_T2_DQS_34 Sch=ac_dac_sdata #set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports { ac_lrclk }]; #IO_L14N_T2_SRCC_34 Sch=ac_lrclk #set_property -dict { PACKAGE_PIN U6 IOSTANDARD LVCMOS33 } [get_ports { ac_mclk }]; #IO_L16P_T2_34 Sch=ac_mclk ## Pmod header JA -- We'll use the bottom for GPS #set_property -dict { PACKAGE_PIN AB22 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L10N_T1_D15_14 Sch=ja[1] #set_property -dict { PACKAGE_PIN AB21 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L10P_T1_D14_14 Sch=ja[2] #set_property -dict { PACKAGE_PIN AB20 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ja[3] #set_property -dict { PACKAGE_PIN AB18 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L17N_T2_A13_D29_14 Sch=ja[4] # set_property -dict {PACKAGE_PIN Y21 IOSTANDARD LVCMOS33} [get_ports i_gps_3df] # set_property -dict {PACKAGE_PIN AA21 IOSTANDARD LVCMOS33} [get_ports o_gpsu_tx] # set_property -dict {PACKAGE_PIN AA20 IOSTANDARD LVCMOS33} [get_ports i_gpsu_rx] # set_property -dict {PACKAGE_PIN AA18 IOSTANDARD LVCMOS33} [get_ports i_gps_pps] ## Pmod header JB --- Reserved for the Differential PMod Challenge #set_property -dict { PACKAGE_PIN V9 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L21P_T3_DQS_34 Sch=jb_p[1] #set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L21N_T3_DQS_34 Sch=jb_n[1] #set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L19P_T3_34 Sch=jb_p[2] #set_property -dict { PACKAGE_PIN W7 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L19N_T3_VREF_34 Sch=jb_n[2] #set_property -dict { PACKAGE_PIN W9 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L24P_T3_34 Sch=jb_p[3] #set_property -dict { PACKAGE_PIN Y9 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L24N_T3_34 Sch=jb_n[3] #set_property -dict { PACKAGE_PIN Y8 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L23P_T3_34 Sch=jb_p[4] #set_property -dict { PACKAGE_PIN Y7 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L23N_T3_34 Sch=jb_n[4] ## Pmod header JC -- We'll use the bottom for the PModMIC #set_property -dict { PACKAGE_PIN Y6 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L18P_T2_34 Sch=jc_p[1] #set_property -dict { PACKAGE_PIN AA6 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L18N_T2_34 Sch=jc_n[1] #set_property -dict { PACKAGE_PIN AA8 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L22P_T3_34 Sch=jc_p[2] #set_property -dict { PACKAGE_PIN AB8 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L22N_T3_34 Sch=jc_n[2] # set_property -dict { PACKAGE_PIN R6 IOSTANDARD LVCMOS33 } [get_ports { o_mic_csn }]; #IO_L17P_T2_34 Sch=jc_p[3] # set_property -dict { PACKAGE_PIN T6 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L17N_T2_34 Sch=jc_n[3] # set_property -dict { PACKAGE_PIN AB7 IOSTANDARD LVCMOS33 } [get_ports { i_mic_din }]; #IO_L20P_T3_34 Sch=jc_p[4] # set_property -dict { PACKAGE_PIN AB6 IOSTANDARD LVCMOS33 } [get_ports { o_mic_sck }]; #IO_L20N_T3_34 Sch=jc_n[4] ## XADC Header #set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { xa_p[0] }]; #IO_L3P_T0_DQS_AD1P_15 Sch=xa_p[1] #set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { xa_n[0] }]; #IO_L3N_T0_DQS_AD1N_15 Sch=xa_n[1] #set_property -dict { PACKAGE_PIN H13 IOSTANDARD LVCMOS33 } [get_ports { xa_p[1] }]; #IO_L1P_T0_AD0P_15 Sch=xa_p[2] #set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { xa_n[1] }]; #IO_L1N_T0_AD0N_15 Sch=xa_n[2] #set_property -dict { PACKAGE_PIN G15 IOSTANDARD LVCMOS33 } [get_ports { xa_p[2] }]; #IO_L2P_T0_AD8P_15 Sch=xa_p[3] #set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { xa_n[2] }]; #IO_L2N_T0_AD8N_15 Sch=xa_n[3] #set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { xa_p[3] }]; #IO_L5P_T0_AD9P_15 Sch=xa_p[4] #set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { xa_n[3] }]; #IO_L5N_T0_AD9N_15 Sch=xa_n[4] ## UART # set_property -dict {PACKAGE_PIN AA19 IOSTANDARD LVCMOS33 } [get_ports o_host_uart_tx ] # set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33 } [get_ports i_host_uart_rx ] ## Ethernet #set_property -dict { PACKAGE_PIN Y14 IOSTANDARD LVCMOS25 } [get_ports { eth_int_b }]; #IO_L6N_T0_VREF_13 Sch=eth_int_b # set_property -dict {PACKAGE_PIN AA16 IOSTANDARD LVCMOS25} [get_ports o_eth_mdclk] # set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS25} [get_ports io_eth_mdio] #set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS25 } [get_ports { eth_pme_b }]; #IO_L6P_T0_13 Sch=eth_pme_b #set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports { eth_rst_b }]; #IO_25_34 Sch=eth_rst_b #set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS25 } [get_ports { eth_rxck }]; #IO_L13P_T2_MRCC_13 Sch=eth_rxck #set_property -dict { PACKAGE_PIN W10 IOSTANDARD LVCMOS25 } [get_ports { eth_rxctl }]; #IO_L10N_T1_13 Sch=eth_rxctl #set_property -dict { PACKAGE_PIN AB16 IOSTANDARD LVCMOS25 } [get_ports { eth_rxd[0] }]; #IO_L2P_T0_13 Sch=eth_rxd[0] #set_property -dict { PACKAGE_PIN AA15 IOSTANDARD LVCMOS25 } [get_ports { eth_rxd[1] }]; #IO_L4P_T0_13 Sch=eth_rxd[1] #set_property -dict { PACKAGE_PIN AB15 IOSTANDARD LVCMOS25 } [get_ports { eth_rxd[2] }]; #IO_L4N_T0_13 Sch=eth_rxd[2] #set_property -dict { PACKAGE_PIN AB11 IOSTANDARD LVCMOS25 } [get_ports { eth_rxd[3] }]; #IO_L7P_T1_13 Sch=eth_rxd[3] #set_property -dict { PACKAGE_PIN AA14 IOSTANDARD LVCMOS25 } [get_ports { eth_txck }]; #IO_L5N_T0_13 Sch=eth_txck #set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS25 } [get_ports { eth_txctl }]; #IO_L10P_T1_13 Sch=eth_txctl #set_property -dict { PACKAGE_PIN Y12 IOSTANDARD LVCMOS25 } [get_ports { eth_txd[0] }]; #IO_L11N_T1_SRCC_13 Sch=eth_txd[0] #set_property -dict { PACKAGE_PIN W12 IOSTANDARD LVCMOS25 } [get_ports { eth_txd[1] }]; #IO_L12N_T1_MRCC_13 Sch=eth_txd[1] #set_property -dict { PACKAGE_PIN W11 IOSTANDARD LVCMOS25 } [get_ports { eth_txd[2] }]; #IO_L12P_T1_MRCC_13 Sch=eth_txd[2] #set_property -dict { PACKAGE_PIN Y11 IOSTANDARD LVCMOS25 } [get_ports { eth_txd[3] }]; #IO_L11P_T1_SRCC_13 Sch=eth_txd[3] ## Fan PWM #set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS25 } [get_ports { fan_pwm }]; #IO_L14P_T2_SRCC_13 Sch=fan_pwm ## DPTI/DSPI #set_property -dict { PACKAGE_PIN Y18 IOSTANDARD LVCMOS33 } [get_ports { prog_clko }]; #IO_L13P_T2_MRCC_14 Sch=prog_clko #set_property -dict { PACKAGE_PIN U20 IOSTANDARD LVCMOS33 } [get_ports { prog_d[0] }]; #IO_L11P_T1_SRCC_14 Sch=prog_d0/sck #set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { prog_d[1] }]; #IO_L19P_T3_A10_D26_14 Sch=prog_d1/mosi #set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { prog_d[2] }]; #IO_L22P_T3_A05_D21_14 Sch=prog_d2/miso #set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { prog_d[3] }]; #IO_L18P_T2_A12_D28_14 Sch=prog_d3/ss #set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { prog_d[4] }]; #IO_L24N_T3_A00_D16_14 Sch=prog_d[4] #set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { prog_d[5] }]; #IO_L24P_T3_A01_D17_14 Sch=prog_d[5] #set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { prog_d[6] }]; #IO_L20P_T3_A08_D24_14 Sch=prog_d[6] #set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { prog_d[7] }]; #IO_L23N_T3_A02_D18_14 Sch=prog_d[7] #set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { prog_oen }]; #IO_L16P_T2_CSI_B_14 Sch=prog_oen #set_property -dict { PACKAGE_PIN P19 IOSTANDARD LVCMOS33 } [get_ports { prog_rdn }]; #IO_L5P_T0_D06_14 Sch=prog_rdn #set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { prog_rxen }]; #IO_L21P_T3_DQS_14 Sch=prog_rxen #set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { prog_siwun }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=prog_siwun #set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { prog_spien }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=prog_spien #set_property -dict { PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 } [get_ports { prog_txen }]; #IO_L13N_T2_MRCC_14 Sch=prog_txen #set_property -dict { PACKAGE_PIN R19 IOSTANDARD LVCMOS33 } [get_ports { prog_wrn }]; #IO_L5N_T0_D07_14 Sch=prog_wrn ## HID port # set_property -dict {PACKAGE_PIN W17 IOSTANDARD LVCMOS33} [get_ports io_ps2_clk] # set_property -dict {PACKAGE_PIN N13 IOSTANDARD LVCMOS33} [get_ports io_ps2_data] ## QSPI # set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports o_qspi_cs_n] # set_property -dict {PACKAGE_PIN P22 IOSTANDARD LVCMOS33} [get_ports {io_qspi_dat[0]}] # set_property -dict {PACKAGE_PIN R22 IOSTANDARD LVCMOS33} [get_ports {io_qspi_dat[1]}] # set_property -dict {PACKAGE_PIN P21 IOSTANDARD LVCMOS33} [get_ports {io_qspi_dat[2]}] # set_property -dict {PACKAGE_PIN R21 IOSTANDARD LVCMOS33} [get_ports {io_qspi_dat[3]}] #set_property -dict { PACKAGE_PIN W5 IOSTANDARD LVCMOS33 } [get_ports { scl }]; #IO_L15N_T2_DQS_34 Sch=scl ## SD card #set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { o_sd_sck }]; #IO_L12P_T1_MRCC_14 Sch=sd_cclk # set_property -dict {PACKAGE_PIN T18 IOSTANDARD LVCMOS33} [get_ports i_sd_cd] #set_property -dict { PACKAGE_PIN W20 IOSTANDARD LVCMOS33 } [get_ports { io_sd_cmd }]; #IO_L12N_T1_MRCC_14 Sch=sd_cmd #set_property -dict { PACKAGE_PIN V19 IOSTANDARD LVCMOS33 } [get_ports { io_sd[0] }]; #IO_L14N_T2_SRCC_14 Sch=sd_d[0] #set_property -dict { PACKAGE_PIN T21 IOSTANDARD LVCMOS33 } [get_ports { io_sd[1] }]; #IO_L4P_T0_D04_14 Sch=sd_d[1] #set_property -dict { PACKAGE_PIN T20 IOSTANDARD LVCMOS33 } [get_ports { io_sd[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sd_d[2] #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { io_sd[3] }]; #IO_L18N_T2_A11_D27_14 Sch=sd_d[3] # set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVCMOS33} [get_ports o_sd_reset] #set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports { sda }]; #IO_L16N_T2_34 Sch=sda ## Voltage Adjust #set_property -dict { PACKAGE_PIN AA13 IOSTANDARD LVCMOS25 } [get_ports { set_vadj[0] }]; #IO_L3P_T0_DQS_13 Sch=set_vadj[0] #set_property -dict { PACKAGE_PIN AB17 IOSTANDARD LVCMOS25 } [get_ports { set_vadj[1] }]; #IO_L2N_T0_13 Sch=set_vadj[1] #set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS25 } [get_ports { vadj_en }]; #IO_L13N_T2_MRCC_13 Sch=vadj_en ## FMC #set_property -dict { PACKAGE_PIN H19 IOSTANDARD LVCMOS12 } [get_ports { fmc_clk0_m2c_n }]; #IO_L12N_T1_MRCC_15 Sch=fmc_clk0_m2c_n #set_property -dict { PACKAGE_PIN J19 IOSTANDARD LVCMOS12 } [get_ports { fmc_clk0_m2c_p }]; #IO_L12P_T1_MRCC_15 Sch=fmc_clk0_m2c_p #set_property -dict { PACKAGE_PIN C19 IOSTANDARD LVCMOS12 } [get_ports { fmc_clk1_m2c_n }]; #IO_L13N_T2_MRCC_16 Sch=fmc_clk1_m2c_n #set_property -dict { PACKAGE_PIN C18 IOSTANDARD LVCMOS12 } [get_ports { fmc_clk1_m2c_p }]; #IO_L13P_T2_MRCC_16 Sch=fmc_clk1_m2c_p #set_property -dict { PACKAGE_PIN K19 IOSTANDARD LVCMOS12 } [get_ports { fmc_la00_cc_n }]; #IO_L13N_T2_MRCC_15 Sch=fmc_la00_cc_n #set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS12 } [get_ports { fmc_la00_cc_p }]; #IO_L13P_T2_MRCC_15 Sch=fmc_la00_cc_p #set_property -dict { PACKAGE_PIN J21 IOSTANDARD LVCMOS12 } [get_ports { fmc_la01_cc_n }]; #IO_L11N_T1_SRCC_15 Sch=fmc_la01_cc_n #set_property -dict { PACKAGE_PIN J20 IOSTANDARD LVCMOS12 } [get_ports { fmc_la01_cc_p }]; #IO_L11P_T1_SRCC_15 Sch=fmc_la01_cc_p #set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[02] }]; #IO_L16N_T2_A27_15 Sch=fmc_la_n[02] #set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[02] }]; #IO_L16P_T2_A28_15 Sch=fmc_la_p[02] #set_property -dict { PACKAGE_PIN N19 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[03] }]; #IO_L17N_T2_A25_15 Sch=fmc_la_n[03] #set_property -dict { PACKAGE_PIN N18 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[03] }]; #IO_L17P_T2_A26_15 Sch=fmc_la_p[03] #set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[04] }]; #IO_L18N_T2_A23_15 Sch=fmc_la_n[04] #set_property -dict { PACKAGE_PIN N20 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[04] }]; #IO_L18P_T2_A24_15 Sch=fmc_la_p[04] #set_property -dict { PACKAGE_PIN L21 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[05] }]; #IO_L10N_T1_AD11N_15 Sch=fmc_la_n[05] #set_property -dict { PACKAGE_PIN M21 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[05] }]; #IO_L10P_T1_AD11P_15 Sch=fmc_la_p[05] #set_property -dict { PACKAGE_PIN M22 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[06] }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=fmc_la_n[06] #set_property -dict { PACKAGE_PIN N22 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[06] }]; #IO_L15P_T2_DQS_15 Sch=fmc_la_p[06] #set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[07] }]; #IO_L20N_T3_A19_15 Sch=fmc_la_n[07] #set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[07] }]; #IO_L20P_T3_A20_15 Sch=fmc_la_p[07] #set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[08] }]; #IO_L24N_T3_RS0_15 Sch=fmc_la_n[08] #set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[08] }]; #IO_L24P_T3_RS1_15 Sch=fmc_la_p[08] #set_property -dict { PACKAGE_PIN G20 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[09] }]; #IO_L8N_T1_AD10N_15 Sch=fmc_la_n[09] #set_property -dict { PACKAGE_PIN H20 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[09] }]; #IO_L8P_T1_AD10P_15 Sch=fmc_la_p[09] #set_property -dict { PACKAGE_PIN K22 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[10] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=fmc_la_n[10] #set_property -dict { PACKAGE_PIN K21 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[10] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=fmc_la_p[10] #set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[11] }]; #IO_L22N_T3_A16_15 Sch=fmc_la_n[11] #set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[11] }]; #IO_L22P_T3_A17_15 Sch=fmc_la_p[11] #set_property -dict { PACKAGE_PIN L20 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[12] }]; #IO_L14N_T2_SRCC_15 Sch=fmc_la_n[12] #set_property -dict { PACKAGE_PIN L19 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[12] }]; #IO_L14P_T2_SRCC_15 Sch=fmc_la_p[12] #set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[13] }]; #IO_L21N_T3_DQS_A18_15 Sch=fmc_la_n[13] #set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[13] }]; #IO_L21P_T3_DQS_15 Sch=fmc_la_p[13] #set_property -dict { PACKAGE_PIN H22 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[14] }]; #IO_L7N_T1_AD2N_15 Sch=fmc_la_n[14] #set_property -dict { PACKAGE_PIN J22 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[14] }]; #IO_L7P_T1_AD2P_15 Sch=fmc_la_p[14] #set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[15] }]; #IO_L23N_T3_FWE_B_15 Sch=fmc_la_n[15] #set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[15] }]; #IO_L23P_T3_FOE_B_15 Sch=fmc_la_p[15] #set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[16] }]; #IO_L4N_T0_15 Sch=fmc_la_n[16] #set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[16] }]; #IO_L4P_T0_15 Sch=fmc_la_p[16] #set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS12 } [get_ports { fmc_la17_cc_n }]; #IO_L11N_T1_SRCC_16 Sch=fmc_la17_cc_n #set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS12 } [get_ports { fmc_la17_cc_p }]; #IO_L11P_T1_SRCC_16 Sch=fmc_la17_cc_p #set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS12 } [get_ports { fmc_la18_cc_n }]; #IO_L12N_T1_MRCC_16 Sch=fmc_la18_cc_n #set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS12 } [get_ports { fmc_la18_cc_p }]; #IO_L12P_T1_MRCC_16 Sch=fmc_la18_cc_p #set_property -dict { PACKAGE_PIN A19 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[19] }]; #IO_L17N_T2_16 Sch=fmc_la_n[19] #set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[19] }]; #IO_L17P_T2_16 Sch=fmc_la_p[19] #set_property -dict { PACKAGE_PIN F20 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[20] }]; #IO_L18N_T2_16 Sch=fmc_la_n[20] #set_property -dict { PACKAGE_PIN F19 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[20] }]; #IO_L18P_T2_16 Sch=fmc_la_p[20] #set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[21] }]; #IO_L14N_T2_SRCC_16 Sch=fmc_la_n[21] #set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[21] }]; #IO_L14P_T2_SRCC_16 Sch=fmc_la_p[21] #set_property -dict { PACKAGE_PIN D21 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[22] }]; #IO_L23N_T3_16 Sch=fmc_la_n[22] #set_property -dict { PACKAGE_PIN E21 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[22] }]; #IO_L23P_T3_16 Sch=fmc_la_p[22] #set_property -dict { PACKAGE_PIN A21 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[23] }]; #IO_L21N_T3_DQS_16 Sch=fmc_la_n[23] #set_property -dict { PACKAGE_PIN B21 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[23] }]; #IO_L21P_T3_DQS_16 Sch=fmc_la_p[23] #set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[24] }]; #IO_L7N_T1_16 Sch=fmc_la_n[24] #set_property -dict { PACKAGE_PIN B15 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[24] }]; #IO_L7P_T1_16 Sch=fmc_la_p[24] #set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[25] }]; #IO_L2N_T0_16 Sch=fmc_la_n[25] #set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[25] }]; #IO_L2P_T0_16 Sch=fmc_la_p[25] #set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[26] }]; #IO_L15N_T2_DQS_16 Sch=fmc_la_n[26] #set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[26] }]; #IO_L15P_T2_DQS_16 Sch=fmc_la_p[26] #set_property -dict { PACKAGE_PIN A20 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[27] }]; #IO_L16N_T2_16 Sch=fmc_la_n[27] #set_property -dict { PACKAGE_PIN B20 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[27] }]; #IO_L16P_T2_16 Sch=fmc_la_p[27] #set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[28] }]; #IO_L8N_T1_16 Sch=fmc_la_n[28] #set_property -dict { PACKAGE_PIN C13 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[28] }]; #IO_L8P_T1_16 Sch=fmc_la_p[28] #set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[29] }]; #IO_L3N_T0_DQS_16 Sch=fmc_la_n[29] #set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[29] }]; #IO_L3P_T0_DQS_16 Sch=fmc_la_p[29] #set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[30] }]; #IO_L10N_T1_16 Sch=fmc_la_n[30] #set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[30] }]; #IO_L10P_T1_16 Sch=fmc_la_p[30] #set_property -dict { PACKAGE_PIN E14 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[31] }]; #IO_L4N_T0_16 Sch=fmc_la_n[31] #set_property -dict { PACKAGE_PIN E13 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[31] }]; #IO_L4P_T0_16 Sch=fmc_la_p[31] #set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[32] }]; #IO_L9N_T1_DQS_16 Sch=fmc_la_n[32] #set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[32] }]; #IO_L9P_T1_DQS_16 Sch=fmc_la_p[32] #set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_n[33] }]; #IO_L1N_T0_16 Sch=fmc_la_n[33] #set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS12 } [get_ports { fmc_la_p[33] }]; #IO_L1P_T0_16 Sch=fmc_la_p[33] set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *avgs*}] -to [get_cells -hier -filter {NAME =~ *q_v*}] 10.0; set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] set_property BITSTREAM.CONFIG.CCLKPIN PULLNONE [current_design] set_property CONFIG_MODE SPIx4 [current_design] set_property CFGBVS VCCO [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design] ================================================ FILE: auto-data/pic.txt ================================================ ################################################################################ ## ## Filename: auto-data/pic.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=buspic @DEVID=BUSPIC @NADDR=1 @BUSP=wb32 @ACCESS=BUSPIC_ACCESS @SLAVE.TYPE=SINGLE @SLAVE.BUS=@$(BUSP) @PIC.BUS= bus_int_vector @PIC.MAX= 15 @INT.BUS.WIRE= w_bus_int @INT.BUS.PIC= syspic @INT.BUS.ID= 6 @BDEF.DEFN= #define BUSPIC(X) (1< for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=pwrcount @NADDR=1 @ACCESS=PWRCOUNT_ACCESS @SLAVE.TYPE=SINGLE @SLAVE.BUS=wb32 @MAIN.DEFNS= reg [31:0] r_@$(PREFIX)_data; @MAIN.INSERT= initial r_@$(PREFIX)_data = 32'h0; always @(posedge i_clk) if (r_@$(PREFIX)_data[31]) r_@$(PREFIX)_data[30:0] <= r_@$(PREFIX)_data[30:0] + 1'b1; else r_@$(PREFIX)_data[31:0] <= r_@$(PREFIX)_data[31:0] + 1'b1; assign @$(SLAVE.PREFIX)_stall = 1'b0; assign @$(SLAVE.PREFIX)_ack = @$(SLAVE.PREFIX)_stb; assign @$(SLAVE.PREFIX)_idata = r_@$(PREFIX)_data; @REGS.N=1 @REGS.0= 0 R_PWRCOUNT PWRCOUNT @BDEF.OSVAL= static volatile unsigned *const _@$(PREFIX) = ((unsigned *)@$[0x%08x](REGBASE)); ================================================ FILE: auto-data/rtccount.txt ================================================ ################################################################################ ## ## Filename: auto-data/rtccount.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Define a very simple peripheral that counts fractions of a ## second since startup. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2015-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=rtccount @DEVID=RTCCOUNT @ACCESS=@$(DEVID)_ACCESS @NADDR=1 @CLOCK.NAME=clk @SLAVE.TYPE=SINGLE @SLAVE.BUS=wb32 @$STEP=((1<<32) + @$(CLOCK.FREQUENCY)/2)/@$(CLOCK.FREQUENCY) @MAIN.DEFNS= reg [31:0] r_@$(PREFIX)_data; @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // RTC Counter // {{{ // // Using clock @$(CLOCK.WIRE) with frequency @$(CLOCK.FREQUENCY) // assign @$(SLAVE.PREFIX)_stall = 1'b0; assign @$(SLAVE.PREFIX)_ack = @$(SLAVE.PREFIX)_stb; initial r_@$(PREFIX)_data = 32'h0; always @(posedge i_clk) r_@$(PREFIX)_data <= r_@$(PREFIX)_data + @$(STEP); assign @$(SLAVE.PREFIX)_idata = r_@$(PREFIX)_data; // }}} @REGS.N=1 @REGS.0= 0 R_RTCCOUNT RTCCOUNT @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=unsigned @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL= static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((unsigned *)@$[0x%08x](REGBASE)); ================================================ FILE: auto-data/rtcdate.txt ================================================ ################################################################################ ## ## Filename: auto-data/rtcdate.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=rtcdate @DEVID=RTCDATE @NADDR=1 @ACCESS=@$(DEVID)_ACCESS @DEPENDS=RTC_ACCESS @SLAVE.TYPE=SINGLE @SLAVE.BUS=wb32 @MAIN.INSERT= // // The Calendar DATE // rtcdate #( .INITIAL_DATE(`DATESTAMP) ) u_@$(PREFIX)( .i_clk(i_clk), .i_ppd(rtc_ppd), @$(SLAVE.ANSIPORTLIST) ); @REGS.N=1 @REGS.0= 0 R_@$(DEVID) @$(DEVID) DATE @BDEF.IONAME= _@$(PREFIX) @BDEF.IOTYPE= unsigned @BDEF.OSDEF= _BOARD_HAS_@$(DEVID) @BDEF.OSVAL= static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$BDEF.IOTYPE *)@$REGBASE); @RTL.MAKE.GROUP=@$(DEVID) @RTL.MAKE.SUBD=rtc @RTL.MAKE.FILES=rtcdate.v ================================================ FILE: auto-data/rtcgps.txt ================================================ ################################################################################ ## ## Filename: auto-data/rtcgps.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=rtc @DEVID=RTC @NADDR=4 @SLAVE.TYPE=DOUBLE @SLAVE.BUS=wb32 @ACCESS=RTC_ACCESS @CLOCK.NAME=clk @CLKFREQHZ=@$(CLOCK.FREQUENCY) @$CLKSTEP=((1<<48)/@$(CLOCK.FREQUENCY)) @INT.RTC.WIRE=rtc_int @INT.RTC.PIC=altpic @MAIN.DEFNS= // Definitions in support of the GPS driven RTC // This clock step is designed to match @$(CLOCK.FREQUENCY) Hz localparam [31:0] RTC_CLKSTEP = @$[32'h%08x](CLKSTEP); wire @$(PREFIX)_ppd; wire @$(PREFIX)_pps; @MAIN.INSERT= `ifdef GPSTRK_ACCESS rtcgps #( .DEFAULT_SPEED(RTC_CLKSTEP) ) u_@$(PREFIX)( .i_clk(i_clk), .i_reset(i_reset), @$(SLAVE.ANSIPORTLIST), .o_interrupt(@$(PREFIX)_int), .o_ppd(@$(PREFIX)_ppd), .i_gps_valid(gps_tracking), .i_gps_pps(ck_pps), .i_gps_ckspeed(gps_step[47:16]), .o_rtc_pps(rtc_pps) ); `else rtclight #( .DEFAULT_SPEED(@$[32'h%x](CLKSTEP)) ) u_@$(PREFIX)( .i_clk(i_clk), .i_reset(i_reset), // Can't use the ANSIPORTLIST tag, because the address widths // don't match .i_wb_cyc(@$(SLAVE.PREFIX)_cyc), .i_wb_stb(@$(SLAVE.PREFIX)_stb), .i_wb_we(@$(SLAVE.PREFIX)_we), .i_wb_addr({ 1'b0, @$(SLAVE.PREFIX)_addr[1:0] }), .i_wb_data(@$(SLAVE.PREFIX)_data), .i_wb_sel(@$(SLAVE.PREFIX)_sel), .o_wb_stall(@$(SLAVE.PREFIX)_stall), .o_wb_ack(@$(SLAVE.PREFIX)_ack), .o_wb_data(@$(SLAVE.PREFIX)_idata), .o_interrupt(@$(PREFIX)_int), .o_pps(rtc_pps), .o_ppd(@$(PREFIX)_ppd) ); // Verilator lint_off UNUSED wire unused_@$(PREFIX); assign unused_@$(PREFIX) = &{ 1'b0, i_gps_pps }; // Verilator lint_on UNUSED `endif @MAIN.ALT= `ifdef GPSTRK_ACCESS assign @$(PREFIX)_pps = ck_pps; `endif assign @$(PREFIX)_ppd = 1'b0; @REGS.NOTE= // RTC clock registers @REGS.N=4 @REGS.0= 0 R_CLOCK CLOCK @REGS.1= 1 R_TIMER TIMER @REGS.2= 2 R_STOPWATCH STOPWATCH @REGS.3= 3 R_CKALARM ALARM CKALARM @BDEF.DEFN= typedef struct RTCLIGHT_S { unsigned r_clock, r_stopwatch, r_timer, r_alarm; } RTCLIGHT; @BDEF.IONAME=_rtc @BDEF.IOTYPE=RTCLIGHT @BDEF.OSDEF=_BOARD_HAS_RTC @BDEF.OSVAL=static volatile @$BDEF.IOTYPE *const @$(BDEF.IONAME) = ((@$BDEF.IOTYPE *)@$[0x%08x](REGBASE)); # # @RTL.MAKE.GROUP=RTCGPS @RTL.MAKE.SUBD=rtc @RTL.MAKE.FILES=rtcgps.v rtcbare.v rtctimer.v rtcstopwatch.v rtcalarm.v rtclight.v ## ## @PREFIX=subseconds @DEVID=SUBSECONDS @NADDR=1 @SLAVE.BUS=wb32 @SLAVE.TYPE=SINGLE @MAIN.DEFNS= `ifndef GPSTRK_ACCESS reg [31:0] r_@$(PREFIX)_data; `endif @MAIN.INSERT= `ifdef GPSTRK_ACCESS assign @$(SLAVE.PREFIX)_idata = gps_now[31:0]; `else always @(posedge i_clk) if (@$(SLAVE.PREFIX)_stb && @$(SLAVE.PREFIX)_we) r_@$(PREFIX)_data <= @$(SLAVE.PREFIX)_data; else r_@$(PREFIX)_data <= r_@$(PREFIX)_data + { 16'h0, RTC_CLKSTEP[31:16] }; assign @$(SLAVE.PREFIX)_idata = r_@$(PREFIX)_data; `endif @REGS.NOTE= // A register capturing subseconds, locked to GPS if present @REGS.N=1 @REGS.0= 0 R_SUBSECONDS SUBSECONDS @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=unsigned @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$BDEF.IOTYPE *)@$[0x%08x](REGBASE)); ================================================ FILE: auto-data/sdio.txt ================================================ ################################################################################ ## ## Filename: auto-data/sdio.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Describes how to connect an SDIO peripheral to a wishbone ## bus, as used by autofpga. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=sdio @DEVID=SDIO @NAME=SDIO SD Card @NADDR=8 @CRCTOKEN=1 @$NUMIO=4 @ACCESS=SDIO_ACCESS @SLAVE.TYPE=OTHER @SLAVE.BUS=wbflash @MASTER.TYPE=DMA @MASTER.BUS=wbwide @MASTER.ANSPREFIX=dma_ ## @SCOPE.TRIGGER=@$(PREFIX)_debug[31] ## @SCOPE.DATA=@$(PREFIX)_debug @INT.SDCARD.WIRE= @$(PREFIX)_int @INT.SDCARD.PIC= syspic @CARD_DETECT=1'b1 @OPT_SERDES=1'b1 @OPT_DDR=1'b1 @OPT_EMMC=1'b0 @OPT_DMA=1'b1 @OPT_1P8V=1'b0 @TOP.IOPREFIX=sd @OPT_HWRESET=@$(OPT_EMMC) @SDIO.IORESET= @SDIO.CLKASSIGN= assign o_@$(TOP.IOPREFIX)_clk = w_@$(PREFIX)_ck; @SDIO.DSASSIGN= assign w_@$(PREFIX)_ds = 1'b0; @SDIO.HWRSTASSIGN= @SDIO.RSTDECL= @SDIO.DSDECL= @SDIO.CDETDECL= i_@$(TOP.IOPREFIX)_cd_n, @SDIO.CLKDECL= o_@$(TOP.IOPREFIX)_clk, @SDIO.IORST= @SDIO.IODS= @SDIO.IOCDET= input wire i_@$(TOP.IOPREFIX)_cd_n; @SDIO.IOCLK= output wire o_@$(TOP.IOPREFIX)_clk; @TOP.PORTLIST= // @$(NAME) @$(SDIO.RSTDECL) @$(SDIO.CLKDECL) @$(SDIO.CDETDECL) @$(SDIO.DSDECL) io_@$(TOP.IOPREFIX)_cmd, io_@$(TOP.IOPREFIX)_dat @TOP.IODECL= // @$(NAME) // {{{ @$(SDIO.IORST) @$(SDIO.IOCLK) @$(SDIO.IODS) @$(SDIO.IOCDET) inout wire io_@$(TOP.IOPREFIX)_cmd; inout wire [@$(NUMIO)-1:0] io_@$(TOP.IOPREFIX)_dat; // }}} @SDIO.TOP.DEFNS= // @$(NAME) definitions // {{{ wire w_@$(PREFIX)_hwreset_n, w_@$(PREFIX)_1p8v; wire w_@$(PREFIX)_cfg_ddr; wire w_@$(PREFIX)_cfg_ds, w_@$(PREFIX)_cfg_dscmd; wire [4:0] w_@$(PREFIX)_cfg_sample_shift; wire w_@$(PREFIX)_cmd_tristate; wire w_@$(PREFIX)_data_tristate; // wire [7:0] w_@$(PREFIX)_sdclk; wire w_@$(PREFIX)_cmd_en; wire [1:0] w_@$(PREFIX)_cmd_data; wire w_@$(PREFIX)_data_en; wire w_@$(PREFIX)_rx_en; wire [31:0] w_@$(PREFIX)_tx_data; // wire [1:0] w_@$(PREFIX)_cmd_strb; wire [1:0] w_@$(PREFIX)_cmd_idata; wire w_@$(PREFIX)_cmd_collision; wire w_@$(PREFIX)_crcack, w_@$(PREFIX)_crcnak; wire w_@$(PREFIX)_card_busy; wire [1:0] w_@$(PREFIX)_rx_strb; wire [15:0] w_@$(PREFIX)_rx_data; // wire w_@$(PREFIX)_ac_valid; wire [1:0] w_@$(PREFIX)_ac_data; wire w_@$(PREFIX)_ad_valid; wire [31:0] w_@$(PREFIX)_ad_data; wire w_@$(PREFIX)_ck; wire w_@$(PREFIX)_ds; wire [31:0] w_@$(PREFIX)_debug; // }}} @TOP.DEFNS= @$(SDIO.TOP.DEFNS) @SDIO.FRONTEND= sdfrontend #( .OPT_SERDES(@$(OPT_SERDES)), .OPT_DDR(@$(OPT_DDR)), .NUMIO(@$(NUMIO)), .BUSY_CLOCKS(16), .OPT_CRCTOKEN(@$(CRCTOKEN)) ) u_@$(PREFIX)_frontend ( // {{{ .i_clk(s_clk), .i_hsclk(s_clk_400mhz), .i_reset(s_reset), // Configuration .i_cfg_ddr(w_@$(PREFIX)_cfg_ddr), .i_cfg_ds(w_@$(PREFIX)_cfg_ds), .i_cfg_dscmd(w_@$(PREFIX)_cfg_dscmd), .i_sample_shift(w_@$(PREFIX)_cfg_sample_shift), .i_cmd_tristate(w_@$(PREFIX)_cmd_tristate), .i_data_tristate(w_@$(PREFIX)_data_tristate), // Run-time inputs .i_sdclk(w_@$(PREFIX)_sdclk), .i_cmd_en(w_@$(PREFIX)_cmd_en), .i_cmd_data(w_@$(PREFIX)_cmd_data), .i_data_en(w_@$(PREFIX)_data_en), .i_rx_en(w_@$(PREFIX)_rx_en), .i_tx_data(w_@$(PREFIX)_tx_data), // Return values .o_cmd_strb(w_@$(PREFIX)_cmd_strb), .o_cmd_data(w_@$(PREFIX)_cmd_idata), .o_cmd_collision(w_@$(PREFIX)_cmd_collision), .o_crcack(w_@$(PREFIX)_crcack), .o_crcnak(w_@$(PREFIX)_crcnak), .o_data_busy(w_@$(PREFIX)_card_busy), .o_rx_strb( w_@$(PREFIX)_rx_strb), .o_rx_data( w_@$(PREFIX)_rx_data), // .MAC_VALID(w_@$(PREFIX)_ac_valid), .MAC_DATA( w_@$(PREFIX)_ac_data), .MAD_VALID(w_@$(PREFIX)_ad_valid), .MAD_DATA( w_@$(PREFIX)_ad_data), // IO ports .o_ck(w_@$(PREFIX)_ck), .i_ds(w_@$(PREFIX)_ds), .io_cmd(io_@$(TOP.IOPREFIX)_cmd), .io_dat(io_@$(TOP.IOPREFIX)_dat), .o_debug(w_@$(PREFIX)_debug) // }}} ); @TOP.INSERT= @$(SDIO.FRONTEND) @$(SDIO.CLKASSIGN) @$(SDIO.DSASSIGN) @TOP.MAIN= // @$(NAME) !i_@$(TOP.IOPREFIX)_cd_n, // w_@$(PREFIX)_cfg_ddr, w_@$(PREFIX)_cfg_ds, w_@$(PREFIX)_cfg_dscmd, w_@$(PREFIX)_cfg_sample_shift, w_@$(PREFIX)_cmd_tristate, w_@$(PREFIX)_data_tristate, // w_@$(PREFIX)_sdclk, w_@$(PREFIX)_cmd_en, w_@$(PREFIX)_cmd_data, w_@$(PREFIX)_data_en, w_@$(PREFIX)_rx_en, w_@$(PREFIX)_tx_data, // w_@$(PREFIX)_cmd_strb, w_@$(PREFIX)_cmd_idata, w_@$(PREFIX)_cmd_collision, w_@$(PREFIX)_crcack, w_@$(PREFIX)_crcnak, w_@$(PREFIX)_card_busy, w_@$(PREFIX)_rx_strb, w_@$(PREFIX)_rx_data, // w_@$(PREFIX)_ac_valid, w_@$(PREFIX)_ac_data, w_@$(PREFIX)_ad_valid, w_@$(PREFIX)_ad_data, w_@$(PREFIX)_hwreset_n, w_@$(PREFIX)_1p8v, w_@$(PREFIX)_debug @TOP.INSERT= assign i_@$(PREFIX)_ds = 1'b0; @MAIN.PORTLIST= // @$(NAME) i_@$(PREFIX)_detect, // o_@$(PREFIX)_cfg_ddr, o_@$(PREFIX)_cfg_ds, o_@$(PREFIX)_cfg_dscmd, o_@$(PREFIX)_cfg_sample_shift, o_@$(PREFIX)_cmd_tristate, o_@$(PREFIX)_data_tristate, // o_@$(PREFIX)_sdclk, o_@$(PREFIX)_cmd_en, o_@$(PREFIX)_cmd_data, o_@$(PREFIX)_data_en, o_@$(PREFIX)_rx_en, o_@$(PREFIX)_tx_data, // i_@$(PREFIX)_cmd_strb, i_@$(PREFIX)_cmd_data, i_@$(PREFIX)_cmd_collision, i_@$(PREFIX)_crcack, i_@$(PREFIX)_crcnak, i_@$(PREFIX)_card_busy, i_@$(PREFIX)_rx_strb, i_@$(PREFIX)_rx_data, // i_@$(PREFIX)_ac_valid, i_@$(PREFIX)_ac_data, i_@$(PREFIX)_ad_valid, i_@$(PREFIX)_ad_data, o_@$(PREFIX)_hwreset_n, o_@$(PREFIX)_1p8v, i_@$(PREFIX)_debug @MAIN.IODECL= // @$(NAME) declarations // {{{ input wire i_@$(PREFIX)_detect; // output wire o_@$(PREFIX)_cfg_ddr; output wire o_@$(PREFIX)_cfg_ds; output wire o_@$(PREFIX)_cfg_dscmd; output wire [4:0] o_@$(PREFIX)_cfg_sample_shift; output wire o_@$(PREFIX)_cmd_tristate; output wire o_@$(PREFIX)_data_tristate; // output wire [7:0] o_@$(PREFIX)_sdclk; output wire o_@$(PREFIX)_cmd_en; output wire [1:0] o_@$(PREFIX)_cmd_data; output wire o_@$(PREFIX)_data_en; output wire o_@$(PREFIX)_rx_en; output wire [31:0] o_@$(PREFIX)_tx_data; // input wire [1:0] i_@$(PREFIX)_cmd_strb; input wire [1:0] i_@$(PREFIX)_cmd_data; input wire i_@$(PREFIX)_cmd_collision; input wire i_@$(PREFIX)_crcack; input wire i_@$(PREFIX)_crcnak; input wire i_@$(PREFIX)_card_busy; input wire [1:0] i_@$(PREFIX)_rx_strb; input wire [15:0] i_@$(PREFIX)_rx_data; // input wire i_@$(PREFIX)_ac_valid; input wire [1:0] i_@$(PREFIX)_ac_data; input wire i_@$(PREFIX)_ad_valid; input wire [31:0] i_@$(PREFIX)_ad_data; output wire o_@$(PREFIX)_hwreset_n, o_@$(PREFIX)_1p8v; // Verilator lint_off UNUSED input wire [31:0] i_@$(PREFIX)_debug; // Verilator lint_on UNUSED // }}} @MAIN.DEFNS= // @$(NAME) definitions // Verilator lint_off UNUSED wire [31:0] w_@$(PREFIX)_sdwb_debug; wire s_@$(PREFIX)_ready, m_@$(PREFIX)_valid, m_@$(PREFIX)_last; reg [31:0] @$(PREFIX)_debug; wire [31:0] m_@$(PREFIX)_data; // assign @$(PREFIX)_debug = i_@$(PREFIX)_debug; // Verilator lint_on UNUSED @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // @$(NAME) handling // {{{ //////////////////////////////////////////////////////////////////////// // // always @(*) begin @$(PREFIX)_debug = i_@$(PREFIX)_debug; @$(PREFIX)_debug = w_@$(PREFIX)_sdwb_debug; end sdio #( // {{{ .LGFIFO(10), .NUMIO(@$(NUMIO)), .MW(@$(SLAVE.BUS.WIDTH)), .ADDRESS_WIDTH(@$(MASTER.BUS.AWID)+$clog2(@$(MASTER.BUS.WIDTH)/8)), .DMA_DW(@$(MASTER.BUS.WIDTH)), .OPT_SERDES(@$(OPT_SERDES)), .OPT_EMMC(@$(OPT_EMMC)), .OPT_DMA(@$(OPT_DMA)), .OPT_DDR(@$(OPT_DDR)), .OPT_HWRESET(@$(OPT_HWRESET)), .OPT_CARD_DETECT(@$(CARD_DETECT)), .OPT_CRCTOKEN(@$(CRCTOKEN)), .OPT_1P8V(@$(OPT_1P8V)), `ifdef VERILATOR .LGTIMEOUT(18), `else .LGTIMEOUT(26), `endif .OPT_ISTREAM(1'b0), .OPT_OSTREAM(1'b0) // }}} ) u_@$(PREFIX)( // {{{ .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), .i_reset(@$(SLAVE.BUS.CLOCK.RESET)), @$(SLAVE.ANSIPORTLIST), @$(MASTER.ANSIPORTLIST), // (Unused) DMA Stream assignments // {{{ .s_valid(1'b0), .s_ready(s_@$(PREFIX)_ready), .s_data(32'h0), // .m_valid(m_@$(PREFIX)_valid), .m_ready(1'b1), .m_data(m_@$(PREFIX)_data), .m_last(m_@$(PREFIX)_last), // }}} .i_card_detect(i_@$(PREFIX)_detect), .o_hwreset_n(o_@$(PREFIX)_hwreset_n), .o_1p8v(o_@$(PREFIX)_1p8v), .o_int(@$(PREFIX)_int), // .o_cfg_ddr(o_@$(PREFIX)_cfg_ddr), .o_cfg_ds(o_@$(PREFIX)_cfg_ds), .o_cfg_dscmd(o_@$(PREFIX)_cfg_dscmd), .o_cfg_sample_shift(o_@$(PREFIX)_cfg_sample_shift), .o_cmd_tristate(o_@$(PREFIX)_cmd_tristate), .o_data_tristate(o_@$(PREFIX)_data_tristate), // .o_sdclk( o_@$(PREFIX)_sdclk), .o_cmd_en( o_@$(PREFIX)_cmd_en), .o_cmd_data(o_@$(PREFIX)_cmd_data), .o_data_en( o_@$(PREFIX)_data_en), .o_rx_en( o_@$(PREFIX)_rx_en), .o_tx_data( o_@$(PREFIX)_tx_data), // .i_cmd_strb( i_@$(PREFIX)_cmd_strb), .i_cmd_data( i_@$(PREFIX)_cmd_data), .i_cmd_collision( i_@$(PREFIX)_cmd_collision), .i_crcack( i_@$(PREFIX)_crcack), .i_crcnak( i_@$(PREFIX)_crcnak), .i_card_busy(i_@$(PREFIX)_card_busy), .i_rx_strb( i_@$(PREFIX)_rx_strb), .i_rx_data( i_@$(PREFIX)_rx_data), // .S_AC_VALID(i_@$(PREFIX)_ac_valid), .S_AC_DATA( i_@$(PREFIX)_ac_data), .S_AD_VALID(i_@$(PREFIX)_ad_valid), .S_AD_DATA( i_@$(PREFIX)_ad_data), // .o_debug(w_@$(PREFIX)_sdwb_debug) // }}} ); // }}} @MAIN.ALT= @REGS.N=5 @REGS.NOTE= // @$(NAME) addresses @REGS.0= 0 R_@$(DEVID)_CTRL SDCARD @REGS.1= 1 R_@$(DEVID)_DATA SDDATA @REGS.2= 2 R_@$(DEVID)_FIFOA SDFIFOA, SDFIF0, SDFIFA @REGS.3= 3 R_@$(DEVID)_FIFOB SDFIFOB, SDFIF1, SDFIFB @REGS.4= 4 R_@$(DEVID)_PHY SDPHY @BDEF.DEFN= //////////////////////////////////////////////////////////////////////////////// // // @$(NAME) constants // {{{ //////////////////////////////////////////////////////////////////////////////// // // // These will be defined in sdiodrv.h for the SDIO controller struct @$(DEVID)_S; // }}} @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=struct @$(DEVID)_S @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); @SIM.CLOCK=clk @SIM.INCLUDE= #include "sdiosim.h" @SIM.DEFNS= SDIOSIM *m_@$(PREFIX); @SIM.FILE="sdcard.img" @SIM.INIT= #ifdef @$(ACCESS) m_@$(PREFIX) = new SDIOSIM(@$(SIM.FILE)); m_core->i_sdio_detect = 1; m_core->i_@$(PREFIX)_crcack = 0; m_core->i_@$(PREFIX)_crcnak = 0; #endif @SIM.TICK= #ifdef @$(ACCESS) { unsigned tmp, tmp_async; m_@$(PREFIX)->apply( (unsigned)m_core->o_@$(PREFIX)_sdclk, (unsigned)m_core->o_@$(PREFIX)_cfg_ddr, (unsigned)m_core->o_@$(PREFIX)_cmd_en, (unsigned)m_core->o_@$(PREFIX)_cmd_data, (unsigned)m_core->o_@$(PREFIX)_data_en, (unsigned)m_core->o_@$(PREFIX)_rx_en, (unsigned)m_core->o_@$(PREFIX)_tx_data, tmp, tmp_async, m_core->i_@$(PREFIX)_ad_data); m_core->i_@$(PREFIX)_cmd_strb = (tmp >> 30) & 3; m_core->i_@$(PREFIX)_cmd_data = (tmp >> 28) & 3; m_core->i_@$(PREFIX)_rx_strb = (tmp >> 24) & 3; m_core->i_@$(PREFIX)_rx_data = tmp & 0x0ffff; m_core->i_@$(PREFIX)_ac_valid = (tmp_async & 2) ? 1:0; m_core->i_@$(PREFIX)_ad_valid = tmp_async & 1; m_core->i_@$(PREFIX)_detect = 1; m_core->i_@$(PREFIX)_card_busy = m_@$(PREFIX)->card_busy() ? 1:0; m_core->i_@$(PREFIX)_crcack = m_@$(PREFIX)->crctoken(); m_core->i_@$(PREFIX)_crcnak = (m_core->i_@$(PREFIX)_crcack & 2)?1:0; m_core->i_@$(PREFIX)_crcack &= 1; if (!m_core->o_@$(PREFIX)_cfg_dscmd) { m_core->i_@$(PREFIX)_ac_valid = 0; m_core->i_@$(PREFIX)_ac_data = 0; } if (!m_core->o_@$(PREFIX)_cfg_ds) { m_core->i_@$(PREFIX)_ad_valid = 0; m_core->i_@$(PREFIX)_ad_data = 0; } } #endif @RTL.MAKE.GROUP= SDIO @RTL.MAKE.SUBD=sdspi @RTL.MAKE.FILES= sdio.v sdfrontend.v sdckgen.v sdwb.v sdtxframe.v sdrxframe.v sdcmd.v sddma.v sddma_mm2s.v sddma_rxgears.v sdfifo.v sddma_txgears.v sddma_s2mm.v xsdddr.v xsdserdes8x.v @XDC.SERDES= set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ u_@$(PREFIX)_frontend/GEN_WIDE_IO.r_debug*}] -to [get_cells -hier -filter {NAME=~ u_@$(PREFIX)_frontend/GEN_WIDE_IO.cmd_serdes/u_oserdes*}] 4.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ u_@$(PREFIX)_frontend/GEN_WIDE_IO.r_debug*}] -to [get_cells -hier -filter {NAME=~ u_@$(PREFIX)_frontend/GEN_WIDE_IO.GEN_WIDE_DATIO*.io_serdes/u_oserdes*}] 4.0 @XDC.INSERT= set_property -dict { PULLTYPE PULLUP } [get_ports io_@$(TOP.IOPREFIX)_cmd] @$(XDC.SERDES) ================================================ FILE: auto-data/sdspi.txt ================================================ ################################################################################ ## ## Filename: auto-data/sdspi.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Describes how to connect an SD-SPI peripheral to a wishbone ## bus, as used by autofpga. Note how the description requires ## both a description of what needs to take place in a top level file, as ## well as in the main ## ## An interesting consequence of this description is that upgrading to a ## proper SDIO device would involve no more than swapping this file for an ## sdio.c peripheral description file. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=sdcard @DEVID=SDSPI @NADDR=4 @ACCESS=SDSPI_ACCESS @SLAVE.TYPE=OTHER @SLAVE.BUS=wb32 @BUS.NAME=wb @INT.SDCARD.WIRE= @$(PREFIX)_int @INT.SDCARD.PIC= buspic syspic @IOPREFIX=@$(PREFIX) @TOP.PORTLIST= // SD Card o_@$(IOPREFIX)_clk, io_@$(IOPREFIX)_cmd, io_@$(IOPREFIX)_dat, i_@$(IOPREFIX)_cd_n @TOP.IODECL= // SD Card // {{{ output wire o_@$(IOPREFIX)_clk; inout wire io_@$(IOPREFIX)_cmd; inout wire [3:0] io_@$(IOPREFIX)_dat; input wire i_@$(IOPREFIX)_cd_n; // }}} @TOP.DEFNS= // SD Card definitions // {{{ wire w_@$(IOPREFIX)_cmd; wire [3:0] w_@$(IOPREFIX)_data; wire i_@$(IOPREFIX)_cmd; wire [3:0] i_@$(IOPREFIX)_data; // }}} @TOP.MAIN= // SD Card o_@$(IOPREFIX)_clk, w_@$(IOPREFIX)_cmd, w_@$(IOPREFIX)_data, i_@$(IOPREFIX)_data, !i_@$(IOPREFIX)_cd_n @TOP.INSERT= ////////////////////////////////////////////////////////////////////// // // SD Card SPI Controller // {{{ ////////////////////////////////////////////////////////////////////// // // // Wires for setting up the SD Card Controller // {{{ // This is how we'd set up for SDIO // assign io_@$(PREFIX)_cmd = w_@$(PREFIX)_cmd ? 1'bz:1'b0; // MOSI // assign io_@$(PREFIX)[0] = w_@$(PREFIX)_data[0]? 1'bz:1'b0; // MISO // assign io_@$(PREFIX)[1] = w_@$(PREFIX)_data[1]? 1'bz:1'b0; // assign io_@$(PREFIX)[2] = w_@$(PREFIX)_data[2]? 1'bz:1'b0; // assign io_@$(PREFIX)[3] = w_@$(PREFIX)_data[3]? 1'bz:1'b0; // CS_n // }}} IOBUF @$(PREFIX)_cmd_bf(.T(1'b0),.O(i_@$(IOPREFIX)_cmd),.I(w_@$(IOPREFIX)_cmd),.IO(io_@$(IOPREFIX)_cmd));// MISO IOBUF @$(PREFIX)_dat0_bf(.T(1'b1),.O(i_@$(IOPREFIX)_data[0]),.I(1'b1),.IO(io_@$(IOPREFIX)_dat[0]));// MISO IOBUF @$(PREFIX)_dat1_bf(.T(1'b1),.O(i_@$(IOPREFIX)_data[1]),.I(1'b1),.IO(io_@$(IOPREFIX)_dat[1])); IOBUF @$(PREFIX)_dat2_bf(.T(1'b1),.O(i_@$(IOPREFIX)_data[2]),.I(1'b1),.IO(io_@$(IOPREFIX)_dat[2])); // Implement an open-drain output IOBUF @$(PREFIX)_dat3_bf(.T(w_@$(IOPREFIX)_data[3]),.O(i_@$(IOPREFIX)_data[3]),.I(1'b0),.IO(io_@$(IOPREFIX)_dat[3])); // }}} @MAIN.PORTLIST= // The SD-Card wires o_@$(PREFIX)_clk, o_@$(PREFIX)_cmd, o_@$(PREFIX)_data, i_@$(PREFIX)_data, i_@$(PREFIX)_detect @MAIN.IODECL= // SD-Card declarations // {{{ output wire o_@$(PREFIX)_clk, o_@$(PREFIX)_cmd; output wire [3:0] o_@$(PREFIX)_data; // verilator lint_off UNUSED input wire i_@$(PREFIX)_cmd; input wire [3:0] i_@$(PREFIX)_data; // verilator lint_on UNUSED input wire i_@$(PREFIX)_detect; // }}} @MAIN.DEFNS= // SD SPI definitions // Verilator lint_off UNUSED wire [31:0] @$(PREFIX)_debug; // Verilator lint_on UNUSED wire w_@$(PREFIX)_cs_n, w_@$(PREFIX)_mosi, w_@$(PREFIX)_miso; @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // SD Card SPI handling // {{{ //////////////////////////////////////////////////////////////////////// // // sdspi #( // {{{ .OPT_CARD_DETECT(1'b1), .OPT_LITTLE_ENDIAN(1'b0), .OPT_SPI_ARBITRATION(1'b0) // }}} ) u_@$(PREFIX)( // {{{ .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), .i_sd_reset(@$(SLAVE.BUS.CLOCK.RESET)), @$(SLAVE.ANSIPORTLIST), .o_cs_n(w_@$(PREFIX)_cs_n), .o_sck(o_@$(PREFIX)_clk), .o_mosi(w_@$(PREFIX)_mosi), .i_miso(w_@$(PREFIX)_miso), .i_card_detect(i_@$(PREFIX)_detect), .o_int(@$(PREFIX)_int), .i_bus_grant(1'b1), .o_debug(@$(PREFIX)_debug) // }}} ); assign w_@$(PREFIX)_miso = i_@$(PREFIX)_data[0]; assign o_@$(PREFIX)_data = { w_@$(PREFIX)_cs_n, 3'b111 }; assign o_@$(PREFIX)_cmd = w_@$(PREFIX)_mosi; // }}} @MAIN.ALT= assign o_@$(PREFIX)_clk = 1'b1; assign o_@$(PREFIX)_cmd = 1'b1; assign o_@$(PREFIX)_data = 4'hf; @REGS.N=4 @REGS.NOTE= // SD-SPI addresses @REGS.0= 0 R_@$(DEVID)_CTRL SDCARD @REGS.1= 1 R_@$(DEVID)_DATA SDDATA @REGS.2= 2 R_@$(DEVID)_FIFOA SDFIFOA, SDFIF0, SDFIFA @REGS.3= 3 R_@$(DEVID)_FIFOB SDFIFOB, SDFIF1, SDFIFB @BDEF.DEFN= //////////////////////////////////////////////////////////////////////////////// // // SD SPI constants // {{{ //////////////////////////////////////////////////////////////////////////////// // // #ifndef @$(DEVID)_H #define @$(DEVID)_H struct @$(DEVID)_S; #endif // @$(DEVID)_H // }}} @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=struct @$(DEVID)_S @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); @SIM.CLOCK=clk @SIM.INCLUDE= #include "sdspisim.h" @SIM.DEFNS= #ifdef SDSPI_ACCESS SDSPISIM m_@$(PREFIX); #endif // @$(ACCESS) @SIM.INIT= #ifdef @$(ACCESS) m_@$(PREFIX).debug(false); #endif // @$(ACCESS) @SIM.METHODS= #ifdef @$(ACCESS) void setsdcard(const char *fn) { m_@$(PREFIX).load(fn); } #endif // @$(ACCESS) @SIM.TICK= // SD Card simulation // {{{ #ifdef @$(ACCESS) m_core->i_@$(PREFIX)_data = m_@$(PREFIX)( (m_core->o_@$(PREFIX)_data&8)?1:0, m_core->o_@$(PREFIX)_clk, m_core->o_@$(PREFIX)_cmd); m_core->i_@$(PREFIX)_data &= 1; m_core->i_@$(PREFIX)_data |= (m_core->o_@$(PREFIX)_data&0x0e); m_core->i_@$(PREFIX)_detect = 1; #endif // @$(ACCESS) // }}} @SIM.DEFINES= //////////////////////////////////////////////////////////////////////////////// // // SD SPI Defines // {{{ //////////////////////////////////////////////////////////////////////////////// // // #ifndef VVAR #ifdef ROOT_VERILATOR #include "Vmain___024root.h" #define VVAR(A) rootp->main__DOT_ ## A #elif defined(NEW_VERILATOR) #define VVAR(A) main__DOT_ ## A #else #define VVAR(A) v__DOT_ ## A #endif #endif #define sd_cmd_busy VVAR(_@$(PREFIX)i__DOT__r_cmd_busy) #define sd_clk VVAR(_@$(PREFIX)i__DOT__r_sdspi_clk) #define sd_cmd_state VVAR(_@$(PREFIX)i__DOT__r_cmd_state) #define sd_rsp_state VVAR(_@$(PREFIX)i__DOT__r_rsp_state) #define sd_ll_cmd_stb VVAR(_@$(PREFIX)__DOT__ll_cmd_stb) #define sd_ll_cmd_dat VVAR(_@$(PREFIX)__DOT__ll_cmd_dat) #define sd_ll_z_counter VVAR(_@$(PREFIX)__DOT__lowlevel__DOT__r_z_counter) #define sd_ll_clk_counter VVAR(_@$(PREFIX)__DOT__lowlevel__DOT__r_clk_counter) #define sd_ll_idle VVAR(_@$(PREFIX)__DOT__lowlevel__DOT__r_idle) #define sd_ll_state VVAR(_@$(PREFIX)__DOT__lowlevel__DOT__r_state) #define sd_ll_byte VVAR(_@$(PREFIX)__DOT__lowlevel__DOT__r_byte) #define sd_ll_ireg VVAR(_@$(PREFIX)__DOT__lowlevel__DOT__r_ireg) #define sd_ll_out_stb VVAR(_@$(PREFIX)__DOT__ll_out_stb) #define sd_ll_out_dat VVAR(_@$(PREFIX)__DOT__ll_out_dat) #define sd_lgblklen VVAR(_@$(PREFIX)__DOT__r_lgblklen) #define sd_fifo_rd_crc VVAR(_@$(PREFIX)__DOT__fifo_rd_crc_reg) #define sd_cmd_crc VVAR(_@$(PREFIX)__DOT__r_cmd_crc) #define sd_cmd_crc_cnt VVAR(_@$(PREFIX)__DOT__r_cmd_crc_cnt) #define sd_fifo_rd_crc_stb VVAR(_@$(PREFIX)__DOT__fifo_rd_crc_stb) #define ll_fifo_pkt_state VVAR(_@$(PREFIX)__DOT__ll_fifo_pkt_state) #define sd_have_data_response_token VVAR(_@$(PREFIX)__DOT__r_have_data_response_token) #define sd_fifo_wr_crc VVAR(_@$(PREFIX)__DOT__fifo_wr_crc_reg) #define sd_fifo_wr_crc_stb VVAR(_@$(PREFIX)__DOT__fifo_wr_crc_stb,) #define sd_ll_fifo_wr_state VVAR(_@$(PREFIX)__DOT__ll_fifo_wr_state,) #define sd_ll_fifo_wr_complete VVAR(_@$(PREFIX)__DOT__ll_fifo_wr_complete) #define sd_use_fifo VVAR(_@$(PREFIX)__DOT__r_use_fifo) #define sd_fifo_wr VVAR(_@$(PREFIX)__DOT__r_fifo_wr) @SIM.DEBUG= /* printf(" SDSPI[%d,%d(%d),(%d)]", m_core->sd_cmd_busy, m_core->sd_clk, m_core->sd_cmd_state, m_core->sd_rsp_state); printf(" LL[%d,%2x->CK=%d/%2x,%s,ST=%2d,TX=%2x,RX=%2x->%d,%2x] ", m_core->sd_ll_cmd_stb, m_core->sd_ll_cmd_dat, m_core->sd_ll_z_counter, // (m_core->sd_ll_clk_counter==0)?1:0, m_core->sd_ll_clk_counter, (m_core->sd_ll_idle)?"IDLE":" ", m_core->sd_ll_state, m_core->sd_ll_byte, m_core->sd_ll_ireg, m_core->sd_ll_out_stb, m_core->sd_ll_out_dat ); printf(" CRC=%02x/%2d", m_core->sd_cmd_crc, m_core->sd_cmd_crc_cnt); printf(" SPI(%d,%d,%d/%d,%d)->?", m_core->o_sf_cs_n, m_core->o_sd_cs_n, m_core->o_spi_sck, m_core->@$(VERILATOR_PREFIX)__DOT__sdcard_sck, m_core->o_spi_mosi); printf(" CK=%d,LN=%d", m_core->sd_clk, m_core->sd_lgblklen); if (m_core->sd_use_fifo){ printf(" FIFO"); if (m_core->sd_fifo_wr) printf("-WR(%04x,%d,%d,%d)", m_core->sd_fifo_rd_crc, m_core->sd_fifo_rd_crc_stb, m_core->sd_ll_fifo_pkt_state, m_core->sd_have_data_response_token); else printf("-RD(%04x,%d,%d,%d)", m_core->sd_fifo_wr_crc, m_core->sd_fifo_wr_crc_stb, m_core->sd_ll_fifo_wr_state, m_core->sd_ll_fifo_wr_complete ); } */ ## @RTL.MAKE.GROUP= SDSPI @RTL.MAKE.SUBD=sdspi @RTL.MAKE.FILES= sdspi.v llsdspi.v spicmd.v spirxdata.v spitxdata.v ================================================ FILE: auto-data/spio.txt ================================================ ################################################################################ ## ## Filename: auto-data/spio.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To describe how to interact with the special purpose device ## controller (spio) for the Nexys Video Board (SW, BTN, LEDs) ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=spio @DEVID=SPIO @NADDR=1 @SLAVE.TYPE=SINGLE @SLAVE.BUS=wb32 @ACCESS=@$(DEVID)_ACCESS @INT.SPIO.WIRE=@$(PREFIX)_int @INT.SPIO.PIC=buspic @NLED=8 @NBTN=5 @NSW=8 @TOP.DEFNS= wire [@$(NLED)-1:0] w_led; @TOP.INSERT= assign o_led = { w_led[@$(NLED)-1:3], (w_led[2] || !syncd_stable[3]), (w_led[1] || !clocks_locked), (w_led[0] || s_reset) }; @TOP.MAIN= i_sw, i_btnc, i_btnd, i_btnl, i_btnr, i_btnu, w_led @MAIN.PORTLIST= // SPIO interface i_sw, i_btnc, i_btnd, i_btnl, i_btnr, i_btnu, o_led @MAIN.IODECL= // @$(DEVID) interface input wire [@$(NSW)-1:0] i_sw; input wire i_btnc, i_btnd, i_btnl, i_btnr, i_btnu; output wire [@$(NLED)-1:0] o_led; @MAIN.DEFNS= wire [@$(NBTN)-1:0] w_btn; wire [@$(NLED)-1:0] w_led; @MAIN.INSERT= // // Special purpose I/O driver (buttons, LEDs, and switches) // assign w_btn = { i_btnc, i_btnd, i_btnl, i_btnr, i_btnu }; spio #( .NBTN(@$(NBTN)), .NLEDS(@$(NLED)), .NSW(@$(NSW)) ) u_@$(PREFIX) ( .i_clk(i_clk), .i_reset(i_reset), @$(SLAVE.ANSIPORTLIST), .i_sw(i_sw), .i_btn(w_btn), .o_led(w_led), .o_int(@$(PREFIX)_int) ); assign o_led = w_led; @MAIN.ALT= assign w_btn = 0; assign o_led = 0; @REGS.N=1 @REGS.0= 0 R_@$(DEVID) @$(DEVID) @BDEF.DEFN= #define SPIO_BTNC 0x01000 #define SPIO_BTND 0x00800 #define SPIO_BTNL 0x00400 #define SPIO_BTNR 0x00200 #define SPIO_BTNU 0x00100 @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=unsigned @BDEF.OSDEF= _BOARD_HAS_@$(DEVID) @BDEF.OSVAL= static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); ================================================ FILE: auto-data/vadj33.txt ================================================ ################################################################################ ## ## Filename: auto-data/vadj33.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Set the IO ports to 3.3Volts ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=vadj33 @DEVID=VADJ @ACCESS=@$(DEVID)_ACCESS @TOP.PORTLIST= // @$(DEVID) ports o_vadj_en, o_vadj @TOP.IODECL= // @$(DEVID) wires output wire o_vadj_en; output wire [1:0] o_vadj; @TOP.DEFNS= reg [4:0] @$(PREFIX)_vadj_counter; @TOP.INSERT= assign o_vadj = 2'b11; initial @$(PREFIX)_vadj_counter = 0; always @(posedge i_clk_buffered) if (!@$(PREFIX)_vadj_counter[4]) @$(PREFIX)_vadj_counter[4] <= @$(PREFIX)_vadj_counter[4] + 1; assign o_vadj_en = @$(PREFIX)_vadj_counter[4]; ================================================ FILE: auto-data/version.txt ================================================ ################################################################################ ## ## Filename: auto-data/version.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=version @DEVID=VERSION @ACCESS=VERSION_ACCESS @NADDR=1 @SLAVE.TYPE=SINGLE @SLAVE.BUS=wb32 @MAIN.INCLUDE= `include "builddate.v" @MAIN.INSERT= assign @$(SLAVE.PREFIX)_idata = `DATESTAMP; assign @$(SLAVE.PREFIX)_ack = @$(SLAVE.PREFIX)_stb; assign @$(SLAVE.PREFIX)_stall = 1'b0; @REGS.N=1 @REGS.0= 0 R_@$(DEVID) @$(DEVID) @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=unsigned @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); ## ## ## @PREFIX=buildtime @DEVID=BUILDTIME @NADDR=1 @SLAVE.TYPE=SINGLE @SLAVE.BUS=wb32 @MAIN.DEFNS= // BUILDTIME doesnt need to include builddate.v a second time // `include "builddate.v" @MAIN.INSERT= assign @$(SLAVE.PREFIX)_idata = `BUILDTIME; assign @$(SLAVE.PREFIX)_ack = @$(SLAVE.PREFIX)_stb; assign @$(SLAVE.PREFIX)_stall = 1'b0; @REGS.N=1 @REGS.0= 0 R_@$(DEVID) @$(DEVID) BUILDTIME @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=unsigned @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); ================================================ FILE: auto-data/wboledbw.txt ================================================ ################################################################################ ## ## Filename: auto-data/wboledbw.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To describe how to interact with an OLED device driver, in order ## to drive an OLED display. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=oled @NADDR=4 @DEVID=OLEDBW @ACCESS=@$(DEVID)_ACCESS @SLAVE.TYPE=DOUBLE @SLAVE.BUS=wb32 @MASTER.TYPE=CPU @MASTER.BUS=wbwide @MASTER.PREFIX=@$(MASTER.BUS.NAME)_@$(PREFIX)m @MASTER.ANSPREFIX=pf_ @INT.OLED.WIRE=oled_int @INT.OLED.PIC=syspic @MAIN.PORTLIST= // OLED control interface (roughly SPI) o_oled_sck, o_oled_mosi, o_oled_dcn @MAIN.IODECL= // OLEDBW interface output wire o_oled_sck, o_oled_mosi, o_oled_dcn; @MAIN.DEFNS= // OLEDBW // {{{ // Verilator lint_off UNUSED wire [1:0] w_oled_csn; wire ign_@$(PREFIX)_valid, ign_@$(PREFIX)_last, ign_@$(PREFIX)_id; wire [7:0] ign_@$(PREFIX)_data; wire [31:0] @$(PREFIX)_debug; // Verilator lint_on UNUSED // }}} @MAIN.INSERT= spicpu #( // {{{ .ADDRESS_WIDTH(@$(MASTER.BUS.AWID)), .DATA_WIDTH(@$(MASTER.BUS.WIDTH)), .NCE(2), .OPT_MANUAL(1'b1), .OPT_LITTLE_ENDIAN(1'b0), .OPT_START_HALTED(1'b1), .OPT_SHARED_MISO(1'b1) // }}} ) u_@$(PREFIX) ( // {{{ .i_clk(@$(SLAVE.BUS.CLOCK.WIRE)), .i_reset(@$(SLAVE.BUS.CLOCK.RESET)), @$(SLAVE.ANSIPORTLIST), @$(MASTER.ANSIPORTLIST), .o_spi_csn(w_oled_csn), .o_spi_sck(o_oled_sck), .o_spi_mosi(o_oled_mosi), .i_spi_miso(1'b0), .M_AXIS_TVALID(ign_@$(PREFIX)_valid), .M_AXIS_TREADY(1'b1), .M_AXIS_TDATA( ign_@$(PREFIX)_data), .M_AXIS_TLAST( ign_@$(PREFIX)_last), .M_AXIS_TID( ign_@$(PREFIX)_id), // .o_interrupt(oled_int), .i_sync_signal(rtc_pps), .o_debug(@$(PREFIX)_debug) // }}} ); assign o_oled_dcn = w_oled_csn[0]; @MAIN.ALT= assign o_oled_sck = 1'b1; assign o_oled_mosi = 1'b1; assign o_oled_dcn = 1'b1; @REGS.N=4 @REGS.0= 0 R_OLED OLED @REGS.1= 1 R_OLED_OV OLEDOV @REGS.2= 2 R_OLED_ADDR OLEDADDR @REGS.3= 3 R_OLED_CLK OLEDCLK @BDEF.DEFN= typedef struct OLEDBW_S { unsigned o_cmd, o_override, o_addr, o_clk; } OLEDBW; @BDEF.IONAME=_oled @BDEF.IOTYPE=OLEDBW @BDEF.OSDEF= _BOARD_HAS_OLEDBW @BDEF.OSVAL= static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$(REGBASE)); @RTL.MAKE.GROUP=WBSPI @RTL.MAKE.SUBD=wbspi @RTL.MAKE.FILES=spicpu.v ================================================ FILE: auto-data/wbpmic.txt ================================================ ################################################################################ ## ## Filename: auto-data/wbpmic.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To describe the interface of a very simple ADC (PModMIC3) for ## autogen to work with. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=pmic @NADDR= 2 @SLAVE.TYPE= OTHER @SLAVE.BUS=wb32 @ACCESS= MICROPHONE_ACCESS @$SAMPLERATE=48000 @$CLKSPERSAMPLE.EXPR=@$CLKFREQHZ/@$.SAMPLERATE @UARTSETUP.FORMAT=20'h%08x @INT.MIC.WIRE=pmic_int @INT.MIC.PIC=syspic @MAIN.PORTLIST= // The PMic3 microphone wires o_mic_csn, o_mic_sck, i_mic_din @MAIN.IODECL= output wire o_mic_csn, o_mic_sck; input wire i_mic_din; @MAIN.INSERT= wbmic #(.DEFAULT_RELOAD(@$.CLKSPERSAMPLE)) microphone(i_clk, 1'b0, @$(SLAVE.PORTLIST), o_mic_csn, o_mic_sck, i_mic_din, pmic_int); @MAIN.ALT= assign o_mic_csn = 1'b1; assign o_mic_sck = 1'b1; @REGS.NOTE = // WB-Microphone registers @REGS.N = 2 @REGS.0 = 0 R_MIC_DATA MICD @REGS.1 = 1 R_MIC_CTRL MICC @BDEF.DEFN = #define WBMIC_ENABLE 0 #define WBMIC_DISABLE (1<<20) #define WBMIC_NONEMPTY 0 #define WBMIC_HALFINT (1<<22) #define WBMIC_RESET (1<<24) typedef struct WBMIC_S { unsigned m_data; unsigned m_setup; } WBMIC; @BDEF.IONAME= io_wbmic @BDEF.IOTYPE= WBMIC @BDEF.OSDEF= _BOARD_HAS_WBMIC @BDEF.OSVAL=static volatile @$.BDEF.IOTYPE *const _wbmic = ((@$.BDEF.IOTYPE *)@$(REGBASE)); ================================================ FILE: auto-data/wbscopc.txt ================================================ ################################################################################ ## ## Filename: auto-data/wbscopc.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: A generic scope description, from which other internal wbscopes ## may depend upon ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=scopc @DEVID=SCOPC @ACCESS=@$(DEVID)_SCOPC @CORE=wbscopc @REGS.NOTE=// @$(PREFIX) compressed scope @RTL.MAKE.GROUP=SCOPC @RTL.MAKE.FILES=wbscopc.v @TRIGGER=@$(TARGET)_debug[31] @DEBUG=@$(TARGET)_debug[30:0] @INCLUDEFILE=wbscope.txt ================================================ FILE: auto-data/wbscope.txt ================================================ ################################################################################ ## ## Filename: auto-data/wbscope.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: A generic scope description, from which other internal wbscopes ## may depend upon ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=scope @DEVID=SCOPE @NADDR= 2 @ACCESS=@$(DEVID)_SCOPE @SLAVE.TYPE=OTHER @SLAVE.BUS=wb32 @$LOG_CAPTURE_SIZE=12 @DATA_CLOCK=i_clk @CAPTURECE=1'b1 @SYNCHRONOUS=1 @CORE=wbscope @TRIGGER=@$(TARGET)_dbg_trigger @DEBUG=@$(TARGET)_debug @$DEFHOLDOFF= (1<<(@$(LOG_CAPTURE_SIZE)-1))-4 @MAIN.DEFNS= // Remove this scope tag via inheritance when/if you connect the // scope interrupt // // Verilator lint_off UNUSED wire @$(PREFIX)_int; // Verilator lint_on UNUSED @MAIN.INSERT= @$(CORE) #( // {{{ .LGMEM(@$(LOG_CAPTURE_SIZE)), .SYNCHRONOUS(@$(SYNCHRONOUS)), .DEFAULT_HOLDOFF(@$(DEFHOLDOFF)) // }}} ) u_@$(PREFIX) ( // {{{ .i_data_clk(@$(DATA_CLOCK)), .i_ce(@$(CAPTURECE)), .i_trigger(@$(TRIGGER)), .i_data(@$(DEBUG)), .i_wb_clk(@$(SLAVE.BUS.CLOCK.WIRE)), @$(SLAVE.ANSIPORTLIST), .o_interrupt(@$(PREFIX)_int) // }}} ); @MAIN.ALT= @REGS.NOTE=// @$(PREFIX) scope @REGS.N=2 @REGS.0=0 R_@$(DEVID) @$(DEVID) @REGS.1=1 R_@$(DEVID)D @$(DEVID)D @RTL.MAKE.GROUP=SCOPE @RTL.MAKE.SUBD=wbscope @RTL.MAKE.FILES=@$(CORE).v @BDEF.DEFN= #ifndef WBSCOPE_H #define WBSCOPE_H #define WBSCOPE_NO_RESET 0x80000000u #define WBSCOPE_STOPPED 0x40000000u #define WBSCOPE_TRIGGERED 0x20000000u #define WBSCOPE_PRIMED 0x10000000u #define WBSCOPE_TRIGGER (WBSCOPE_NO_RESET|0x08000000u) #define WBSCOPE_MANUAL (WBSCOPE_TRIGGER) #define WBSCOPE_DISABLE 0x04000000u typedef struct WBSCOPE_S { volatile unsigned s_ctrl, s_data; } WBSCOPE; #endif @BDEF.IONAME=_@$(PREFIX) @BDEF.IOTYPE=WBSCOPE @BDEF.OSDEF=_BOARD_HAS_@$(DEVID) @BDEF.OSVAL=static volatile @$(BDEF.IOTYPE) *const @$(BDEF.IONAME) = ((@$(BDEF.IOTYPE) *)@$[0x%08x](REGBASE)); ================================================ FILE: auto-data/wbuarbiter.txt ================================================ ################################################################################ ## ## Filename: auto-data/wbuarbiter.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: Connect the debugging bus to the rest of the system. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=wbu_arbiter @MASTER.BUS=wbwide @MASTER.TYPE=ARBITER @SLAVE.BUS=wbu @SLAVE.TYPE=OTHER @ERROR.WIRE=@$(SLAVE.PREFIX)_err ## @$NADDR=(1<<@$(MASTER.BUS.AWID)) @IANSI=i_ @OANSI=o_ @SLAVE.ANSPREFIX=s @MASTER.ANSPREFIX=w @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // WBUBUS "wbu_arbiter" master->slave connection // {{{ wbupsz #( // {{{ // Slave bus address width : @$(SLAVE.BUS.AWID) // Slave address width : @$(SLAVE.AWID) // Master bus address width: @$(MASTER.BUS.AWID) .ADDRESS_WIDTH(@$(MASTER.BUS.AWID)+$clog2(@$(MASTER.BUS.WIDTH)/8)), .SMALL_DW(@$(SLAVE.BUS.WIDTH)), .WIDE_DW(@$(MASTER.BUS.WIDTH)), .OPT_LITTLE_ENDIAN(1'b0) // }}} ) u_@$(SLAVE.BUS.NAME)_@$(MASTER.BUS.NAME)_downsz ( // {{{ .i_clk(@$(MASTER.BUS.CLOCK.WIRE)), .i_reset(@$(MASTER.BUS.CLOCK.RESET)), @$(SLAVE.ANSIPORTLIST), @$(MASTER.ANSIPORTLIST) // }}} ); // }}} @RTL.MAKE.GROUP=UPSZ @RTL.MAKE.SUBD= @RTL.MAKE.FILES=wbupsz.v ================================================ FILE: auto-data/wbuart.txt ================================================ ################################################################################ ## ## Filename: auto-data/wbuart.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To describe a UART for autogen to work with. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} # The prefix is used to create a series of bus data lines for interaction with # the bus. In this case, these will be uart_sel, uart_stall, uart_ack, and # uart_data. @PREFIX=uart # The number of addressable registers this peripheral has on the wishbone bus. # Set this to zero to have no bus presence. @NADDR= 4 # The type of peripheral. This can either: # NOBUS Doesn't reply on the bus # SINGLE, for a peripheral that only has one address, and whose result # is available on every clock. In the future, these may be # gathered together into a singleio.v file. # DOUBLE, for a peripheral that takes one clock to access before its # value is available on its output. This might be true for a # peripheral that has several single-clocked registers within it, # which then selects from among these registers in one clock # cycle. In the future, these may be gathered together into a # doubleio.v file. # MEMORY # OTHER (the default), for a peripheral that may take *many* clocks to # respond to a bus transaction, ... one that uses its stall # line of a necessity. @SLAVE.TYPE= OTHER @SLAVE.BUS=wb32 @ACCESS= CONSOLE_ACCESS @$BAUDRATE=1000000 @$UARTSETUP.EXPR=@$CLKFREQHZ/@$.BAUDRATE @UARTSETUP.FORMAT=31'h%08x @$SIM.UARTSETUP.EXPR=@$UARTSETUP @SIM.UARTSETUP.FORMAT=0x%08x @SIM.PORTOFFSET=1 @INT.INTLIST = @$(PREFIX)rx_int @$(PREFIX)tx_int @$(PREFIX)rxf_int @INT.INTLIST += @$(PREFIX)txf_int @INT.UARTRX.WIRE=@$(PREFIX)rx_int @INT.UARTTX.WIRE=@$(PREFIX)tx_int @INT.UARTRXF.WIRE=@$(PREFIX)rxf_int @INT.UARTTXF.WIRE=@$(PREFIX)txf_int @INT.UARTRX.PIC=altpic @INT.UARTTX.PIC=altpic @INT.UARTRXF.PIC=syspic @INT.UARTTXF.PIC=syspic @CTS=i_@$(PREFIX)_cts_n @RTS=o_@$(PREFIX)_rts_n @MAIN.PORTLIST= // The UART console i_@$(PREFIX)_rx, o_@$(PREFIX)_tx, @$CTS, @$RTS @MAIN.IODECL= input wire i_@$(PREFIX)_rx, @$CTS; output wire o_@$(PREFIX)_tx, @$RTS; @MAIN.INSERT= wbuart #( .INITIAL_SETUP(@$.UARTSETUP) ) u_@$(PREFIX)_uart( i_clk, 1'b0, @$(SLAVE.PORTLIST), i_@$(PREFIX)_rx, o_@$(PREFIX)_tx, @$CTS, @$RTS, @$(PREFIX)rx_int, @$(PREFIX)tx_int, @$(PREFIX)rxf_int, @$(PREFIX)txf_int ); @MAIN.ALT= assign o_@$(PREFIX)_tx = 1'b1; assign @$RTS = 1'b0; @REGS.NOTE = // WBUART registers @REGS.N = 4 @REGS.0 = 0 R_UART_SETUP USETUP @REGS.1 = 1 R_UART_FIFO UFIFO @REGS.2 = 2 R_UART_UARTRX RX @REGS.3 = 3 R_UART_UARTTX TX @BDEF.DEFN = #ifndef WBUART_H #define WBUART_H #define UART_PARITY_NONE 0 #define UART_HWFLOW_OFF 0x40000000 #define UART_PARITY_ODD 0x04000000 #define UART_PARITY_EVEN 0x05000000 #define UART_PARITY_SPACE 0x06000000 #define UART_PARITY_MARK 0x07000000 #define UART_STOP_ONEBIT 0 #define UART_STOP_TWOBITS 0x08000000 #define UART_DATA_8BITS 0 #define UART_DATA_7BITS 0x10000000 #define UART_DATA_6BITS 0x20000000 #define UART_DATA_5BITS 0x30000000 #define UART_RX_BREAK 0x0800 #define UART_RX_FRAMEERR 0x0400 #define UART_RX_PARITYERR 0x0200 #define UART_RX_NOTREADY 0x0100 #define UART_RX_ERR (-256) #define UART_TX_BUSY 0x0100 #define UART_TX_BREAK 0x0200 typedef struct WBUART_S { unsigned u_setup; unsigned u_fifo; unsigned u_rx, u_tx; } WBUART; #endif // WBUART_H @BDEF.IONAME= _@$PREFIX @BDEF.IOTYPE= WBUART @BDEF.OSDEF= _BOARD_HAS_WBUART @BDEF.OSVAL=static volatile WBUART *const @$BDEF.IONAME = ((WBUART *)@$[0x%08x](REGBASE)); @RTL.MAKE.GROUP=WBUART @RTL.MAKE.FILES= wbuart.v ufifo.v rxuart.v txuart.v @SIM.INCLUDE= #include "uartsim.h" @SIM.DEFNS= #ifdef @$(ACCESS) UARTSIM *m_@$(PREFIX); #endif // @$(ACCESS) @SIM.INIT= #ifdef @$(ACCESS) m_@$(PREFIX) = new UARTSIM(FPGAPORT+@$(SIM.PORTOFFSET),@$(SIM.UARTSETUP)); m_core->@$CTS = 0; // The sim doesnt use flow control #endif // @$(ACCESS) @SIM.CLOCK=@$(SLAVE.BUS.CLOCK) @SIM.TICK= #ifdef @$(ACCESS) m_core->i_@$(PREFIX)_rx = (*m_@$(PREFIX))(m_core->o_@$(PREFIX)_tx); #else m_core->i_@$(PREFIX)_rx = 1; #endif // @$(ACCESS) ================================================ FILE: auto-data/wbubus.txt ================================================ ################################################################################ ## ## Filename: auto-data/wbubus.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To describe what needs to be done to make the UART to Wishbone ## external bus master a part of the main .v and toplevel.v files. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} @PREFIX=wbu @ACCESS=WBUBUS_MASTER @MASTER.TYPE=HOST @MASTER.BUS=wbu @BUS.NAME=wbu @BUS.CLOCK=clk @BUS.WIDTH=32 @$BAUDRATE=1000000 @CLOCK.NAME=clk @$SETUP=@$(CLOCK.FREQUENCY) / @$BAUDRATE @SETUP.FORMAT=24'h%x @$BUS_ADDRESS_WIDTH=@$(MASTER.BUS.AWID) @BP=@$(MASTER.PREFIX) # @TOP.PORTLIST= # // UART/host to wishbone interface # i_host_uart_rx, o_host_uart_tx # @TOP.IODECL= # // UART/host to wishbone interface # input wire i_host_uart_rx; # output wire o_host_uart_tx; # @TOP.MAIN= # // External USB-UART bus control # i_host_uart_rx, o_host_uart_tx @MAIN.PORTLIST= // UART/host to wishbone interface i_host_uart_rx, o_host_uart_tx @MAIN.IODECL= input wire i_host_uart_rx; output wire o_host_uart_tx; @MAIN.DEFNS= // // // UART interface // // localparam [23:0] BUSUART = @$SETUP; // @$BAUDRATE baud // wire w_ck_uart, w_uart_tx; wire rx_host_stb; wire [7:0] rx_host_data; wire tx_host_stb; wire [7:0] tx_host_data; wire tx_host_busy; // // Definitions for the WB-UART converter. We really only need one // (more) non-bus wire--one to use to select if we are interacting // with the ZipCPU or not. wire wbu_zip_sel; wire [0:0] wbubus_dbg; `ifndef INCLUDE_ZIPCPU // // The bus-console depends upon the zip_dbg wires. If there is no // ZipCPU defining them, we'll need to define them here anyway. // wire zip_dbg_stall, zip_dbg_ack; wire [31:0] zip_dbg_data; `endif @$ZIP_ADDRESS_BIT=@$BUS_ADDRESS_WIDTH-1 @$ZIP_ADDRESS=(1<<(@$THIS.ZIP_ADDRESS_BIT+2)) @ZIP_ADDRESS.FORMAT= 0x%08x @$ZIP_DBGDATA=4+@$.ZIP_ADDRESS @ZIP_DBGDATA.FORMAT= 0x%08x @MAIN.INSERT= // The Host USB interface, to be used by the WB-UART bus rxuartlite #(BUSUART) rcv(s_clk, i_host_uart_rx, rx_host_stb, rx_host_data); txuartlite #(BUSUART) txv(s_clk, tx_host_stb, tx_host_data, o_host_uart_tx, tx_host_busy); `ifdef INCLUDE_ZIPCPU // assign wbu_zip_sel = wbu_addr[@$.ZIP_ADDRESS_BIT]; `else assign wbu_zip_sel = 1'b0; assign zip_dbg_ack = 1'b0; assign zip_dbg_stall = 1'b0; assign zip_dbg_data = 0; `endif `ifndef BUSPIC_ACCESS wire w_bus_int; assign w_bus_int = 1'b0; `endif wire [31:0] wbu_tmp_addr; wbubus genbus(i_clk, i_host_rx_stb, i_host_rx_data, @$(BP)_cyc, @$(BP)_stb, @$(BP)_we, @$(PREFIX)_tmp_addr, @$(BP)_data, @$(BP)_stall, @$(BP)_ack, @$(BP)_idata, @$(BP)_err, w_bus_int, o_host_tx_stb, o_host_tx_data, i_host_tx_busy, wbubus_dbg[0]); assign wbu_sel = 4'hf; assign wbu_addr = wbu_tmp_addr[(@$BUS_ADDRESS_WIDTH-1):0]; @REGDEFS.H.DEFNS= #define R_ZIPCTRL @$.ZIP_ADDRESS #define R_ZIPDATA @$.ZIP_DBGDATA # SIM.INIT= m_core->i_host_uart_rx = 1; SIM.CLOCK=clk SIM.TICK= m_core->i_host_uart_rx = (*m_dbgbus)(m_core->o_host_uart_tx); @RTL.MAKE.GROUP= @RTL.MAKE.SUBD=wbubus @RTL.MAKE.FILES= wbconsole.v wbubus.v wbucompactlines.v wbucompress.v wbuconsole.v wbudecompress.v wbudeword.v wbuexec.v wbufifo.v wbuidleint.v wbuinput.v wbuoutput.v wbureadcw.v wbusixchar.v wbutohex.v ================================================ FILE: auto-data/zipcpu.txt ================================================ ################################################################################ ## ## Filename: auto-data/zipcpu.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To describe what needs to be done to make the ZipCPU a part ## of a main .v file. This Wishbone Master description ## illustrates how some of how a wishbone bus master might be integrated ## into the automatic FPGA designer. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2015-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## ## Define @SYSPIC so that other peripherals needing to be on the ZipSystem's ## PIC know the name of the PIC we are using. Note that this is a global. ## }}} @PREFIX=zip @SIM.CLOCK=clk @ACCESS=INCLUDE_ZIPCPU @DBGBUS=wbu @MASTER.TYPE=CPU @MASTER.BUS=wbwide @MASTER.BUS.OPT_DBLBUFFER=1'b0 @SCOPE.TRIGGER=zip_trigger @SCOPE.DATA=zip_debug @CPURESET=i_cpu_reset @$RESET_ADDRESS=@$(flash.REGBASE)+(6<<20) @INT.ZIP.WIRE=zip_cpu_int @INT.ZIP.BUS=buspic @CACHABLE.FILE=iscachable.v @LGICACHE=12 @LGDCACHE=12 @TOP.PORTLIST= # // A reset wire for the ZipCPU # i_cpu_resetn @TOP.IODECL= # // A reset wire for the ZipCPU # input wire i_cpu_resetn; @TOP.DEFNS= // Verilator lint_off UNUSED wire ign_cpu_stall, ign_cpu_ack; wire [31:0] ign_cpu_idata; // Verilator lint_on UNUSED @TOP.MAIN= // Simulation bus control for the CPU 1'b0, 1'b0, 1'b0, 7'h0, 32'h0, ign_cpu_stall, ign_cpu_ack, ign_cpu_idata, // Reset wire for the ZipCPU s_reset @MAIN.PORTLIST= // Veri1ator only interface cpu_sim_cyc, cpu_sim_stb, cpu_sim_we, cpu_sim_addr, cpu_sim_data, cpu_sim_stall, cpu_sim_ack, cpu_sim_idata, `ifdef VERILATOR cpu_prof_stb, cpu_prof_addr, cpu_prof_ticks, `endif @$(CPURESET) @MAIN.IODECL= input wire cpu_sim_cyc, cpu_sim_stb; input wire cpu_sim_we; input wire [6:0] cpu_sim_addr; input wire [31:0] cpu_sim_data; // output wire cpu_sim_stall, cpu_sim_ack; output wire [31:0] cpu_sim_idata; // `ifdef VERILATOR output wire cpu_prof_stb; output wire [@$(MASTER.BUS.AWID)+$clog2(@$(MASTER.BUS.WIDTH)/8)-1:0] cpu_prof_addr; output wire [31:0] cpu_prof_ticks; `endif input wire @$(CPURESET); @MAIN.PARAM= //////////////////////////////////////////////////////////////////////// // // Variables/definitions/parameters used by the ZipCPU bus master // {{{ // // A 32-bit address indicating where the ZipCPU should start running // from `ifdef BKROM_ACCESS localparam RESET_ADDRESS = @$(/bkrom.BASE); `else `ifdef FLASH_ACCESS localparam RESET_ADDRESS = @$(RESET_ADDRESS); `else localparam RESET_ADDRESS = @$(/bkram.BASE); `endif // FLASH_ACCESS `endif // BKROM_ACCESS // // The number of valid bits on the bus localparam ZIP_ADDRESS_WIDTH = @$(MASTER.BUS.AWID); // Zip-CPU address width // // Number of ZipCPU interrupts localparam ZIP_INTS = 16; // // ZIP_START_HALTED // // A boolean, indicating whether or not the ZipCPU be halted on startup? `ifdef BKROM_ACCESS localparam ZIP_START_HALTED=1'b0; `else localparam ZIP_START_HALTED=1'b1; `endif // }}} @MAIN.DEFNS= //////////////////////////////////////////////////////////////////////// // // ZipSystem/ZipCPU connection definitions // {{{ `ifndef VERILATOR wire cpu_prof_stb; wire [@$(MASTER.BUS.AWID)+$clog2(@$(MASTER.BUS.WIDTH)/8)-1:0] cpu_prof_addr; wire [31:0] cpu_prof_ticks; `endif // All we define here is a set of scope wires // Verilator lint_off UNUSED wire raw_cpu_dbg_stall, raw_cpu_dbg_ack; wire [31:0] zip_debug; wire zip_trigger; // Verilator lint_on UNUSED wire [ZIP_INTS-1:0] zip_int_vector; // }}} @MAIN.INSERT= //////////////////////////////////////////////////////////////////////// // // The ZipCPU/ZipSystem BUS master // {{{ // assign zip_int_vector = { alt_int_vector[14:8], sys_int_vector[14:6] }; zipsystem #( // {{{ .RESET_ADDRESS(RESET_ADDRESS), .ADDRESS_WIDTH(ZIP_ADDRESS_WIDTH + $clog2(@$(MASTER.BUS.WIDTH)/8)), .BUS_WIDTH(@$(MASTER.BUS.WIDTH)), .OPT_LGICACHE(@$(LGICACHE)), .OPT_LGDCACHE(@$(LGDCACHE)), .START_HALTED(ZIP_START_HALTED), .RESET_DURATION(20), .OPT_PIPELINED(1), `ifdef VERILATOR .OPT_PROFILER(1'b1), `else .OPT_PROFILER(1'b0), `endif `ifdef ZIPSCOPE_SCOPE .OPT_TRACE_PORT(1'b1), `else .OPT_TRACE_PORT(1'b0), `endif .OPT_DISTRIBUTED_REGS(1), .EXTERNAL_INTERRUPTS(ZIP_INTS) // }}} ) swic( // {{{ .i_clk(i_clk), .i_reset(i_reset || @$(CPURESET)), // Zipsys wishbone interface @$(MASTER.ANSIPORTLIST), .i_ext_int(zip_int_vector), .o_ext_int(zip_cpu_int), // Debug wishbone interface .i_dbg_cyc(@$(SLAVE.PREFIX)_cyc || cpu_sim_cyc), .i_dbg_stb(cpu_sim_cyc ? cpu_sim_stb : @$(SLAVE.PREFIX)_stb), .i_dbg_we( cpu_sim_cyc ? cpu_sim_we : @$(SLAVE.PREFIX)_we), .i_dbg_addr(cpu_sim_cyc? cpu_sim_addr : @$(SLAVE.PREFIX)_addr[6:0]), .i_dbg_data (cpu_sim_cyc? cpu_sim_data : @$(SLAVE.PREFIX)_data), .i_dbg_sel (cpu_sim_cyc? 4'hf : @$(SLAVE.PREFIX)_sel), .o_dbg_stall(raw_cpu_dbg_stall), .o_dbg_ack (raw_cpu_dbg_ack), .o_dbg_data (@$(SLAVE.PREFIX)_idata), // .o_cpu_debug(zip_debug), .o_prof_stb(cpu_prof_stb), .o_prof_addr(cpu_prof_addr), .o_prof_ticks(cpu_prof_ticks) // }}} ); assign zip_trigger = zip_debug[31]; assign @$(SLAVE.PREFIX)_stall = cpu_sim_cyc || raw_cpu_dbg_stall; assign @$(SLAVE.PREFIX)_ack = !cpu_sim_cyc && raw_cpu_dbg_ack; assign cpu_sim_stall = !cpu_sim_cyc || raw_cpu_dbg_stall; assign cpu_sim_ack = cpu_sim_cyc && raw_cpu_dbg_ack; assign cpu_sim_idata = @$(SLAVE.PREFIX)_idata; // Keep Verilator happy // {{{ // Verilator lint_off UNUSED wire @$(PREFIX)_unused; assign @$(PREFIX)_unused = &{ 1'b0, alt_int_vector[7:0], sys_int_vector[5:0]}; // Verilator lint_on UNUSED // }}} // }}} @BDEF.INCLUDE= //////////////////////////////////////////////////////////////////////////////// // // ZipCPU defines and macros // {{{ #include #define _HAVE_ZIPSYS #define PIC _zip->z_pic #ifdef INCLUDE_ZIPCPU #ifdef INCLUDE_DMA_CONTROLLER #define _HAVE_ZIPSYS_DMA #endif // INCLUDE_DMA_CONTROLLER #ifdef INCLUDE_ACCOUNTING_COUNTERS #define _HAVE_ZIPSYS_PERFORMANCE_COUNTERS #endif // INCLUDE_ACCOUNTING_COUNTERS #endif // INCLUDE_ZIPCPU // }}} @REGDEFS.H.INSERT= //////////////////////////////////////////////////////////////////////////////// // // ZipCPU register definitions // {{{ #define CPU_GO 0x0000 #define CPU_HALT 0x0001 #define CPU_STALL 0x0002 #define CPU_STEP 0x0004 #define CPU_RESET 0x0008 #define CPU_CLRCACHE 0x0010 // (Reserved) 0x00e0 #define CPU_SLEEPING 0x0100 #define CPU_GIE 0x0200 #define CPU_INT 0x0400 #define CPU_BREAK 0x0800 #define CPU_EXINT 0xfffff000 // #define CPU_sR0 0x0020 #define CPU_sSP 0x002d #define CPU_sCC 0x002e #define CPU_sPC 0x002f #define CPU_uR0 0x0030 #define CPU_uSP 0x003d #define CPU_uCC 0x003e #define CPU_uPC 0x003f #ifdef BKROM_ACCESS #define RESET_ADDRESS @$[0x%08x](bkrom.REGBASE) #else #ifdef FLASH_ACCESS #define RESET_ADDRESS @$[0x%08x](RESET_ADDRESS) #else #define RESET_ADDRESS @$[0x%08x](bkram.REGBASE) #endif // FLASH_ACCESS #endif // BKROM_ACCESS // }}} @SIM.CLOCK=clk @SIM.INCLUDE= #include "zipelf.h" @SIM.DEFINES= //////////////////////////////////////////////////////////////////////////////// // // ZipCPU simulation defines // {{{ #ifndef VVAR #ifdef ROOT_VERILATOR #include "Vmain___024root.h" #define VVAR(A) rootp->main__DOT_ ## A #elif defined(NEW_VERILATOR) #define VVAR(A) main__DOT_ ## A #else #define VVAR(A) v__DOT_ ## A #endif #endif #define OPT_PIPELINED #define CPUVAR(A) VVAR(_swic__DOT__thecpu__DOT__core__DOT_ ## A) #define cpu_break VVAR(_swic__DOT__cpu_break) // }}} @SIM.DEFNS= int m_cpu_bombed; @SIM.INIT= m_cpu_bombed = 0; @SIM.SETRESET= m_core->i_cpu_reset = 1; @SIM.CLRRESET= m_core->i_cpu_reset = 0; @SIM.METHODS= #ifdef @$(ACCESS) // ZipCPU Access functions // {{{ void loadelf(const char *elfname) { // {{{ ELFSECTION **secpp, *secp; uint32_t entry; elfread(elfname, entry, secpp); for(int s=0; secpp[s]->m_len; s++) { bool successful_load; secp = secpp[s]; successful_load = load(secp->m_start, secp->m_data, secp->m_len); if (!successful_load) { printf("Could not load section " "from %08x to %08x--no such address\n", secp->m_start, secp->m_start+secp->m_len); } } free(secpp); } // }}} void cpu_dbg_write(const uint32_t addr, const uint32_t data) { // {{{ // printf("CPU-DBG-WRITE(@0x%08x, 0x%08x);\n", addr, data); m_core->cpu_sim_cyc = 1; m_core->cpu_sim_stb = 1; m_core->cpu_sim_we = 1; m_core->cpu_sim_addr = addr >> 2; m_core->cpu_sim_data = data; do { tick_clk(); } while(m_core->cpu_sim_stall); m_core->cpu_sim_stb = 0; while(!m_core->cpu_sim_ack) tick_clk(); m_core->cpu_sim_cyc = 0; m_core->cpu_sim_we = 0; m_core->cpu_sim_addr = 0; m_core->cpu_sim_data = 0; tick_clk(); } // }}} uint32_t cpu_dbg_read(const uint32_t addr) { // {{{ unsigned result; // printf("CPU-DBG-WRITE(@0x%08x, 0x%08x);\n", addr, data); m_core->cpu_sim_cyc = 1; m_core->cpu_sim_stb = 1; m_core->cpu_sim_we = 0; m_core->cpu_sim_addr = addr >> 2; m_core->cpu_sim_data = 0; do { tick_clk(); } while(m_core->cpu_sim_stall); m_core->cpu_sim_stb = 0; while(!m_core->cpu_sim_ack) tick_clk(); result = m_core->cpu_sim_idata; m_core->cpu_sim_cyc = 0; m_core->cpu_sim_we = 0; m_core->cpu_sim_addr = 0; m_core->cpu_sim_data = 0; tick_clk(); return result; } // }}} // }}} #endif // @$(ACCESS) @SIM.TICK= #ifdef @$(ACCESS) // ZipCPU Sim instruction support // {{{ if (m_cpu_bombed) { if (m_cpu_bombed++ > 12) m_done = true; } else if (m_core->cpu_break) { printf("\n\nBOMB : CPU BREAK RECEIVED\n"); m_cpu_bombed++; } // }}} #endif // @$(ACCESS) ## ## ## @RTL.MAKE.GROUP=ZIPCPU @RTL.MAKE.FILES= zipsystem.v zipcore.v zipwb.v cpuops.v pfcache.v pipemem.v dblfetch.v pffifo.v pfcache.v idecode.v wbpriarbiter.v zipsystem.v zipcounter.v zipjiffies.v ziptimer.v icontrol.v wbwatchdog.v busdelay.v zipdma_ctrl.v zipdma_fsm.v zipdma_mm2s.v zipdma_rxgears.v zipdma_s2mm.v zipdma_txgears.v zipdma.v @RTL.MAKE.SUBD=cpu ## ################################################################################ ## ## ZipCPU debug port ## {{{ ## (was once @PREFIX=zip_dbg) @SLAVE.TYPE=OTHER @SLAVE.BUS=wbu @SLAVE.ANSPREFIX=dbg_ @SLAVE.ORDER=1000000 @NADDR=128 @REGS.N=52 @REGS.NOTE=// ZipCPU control/debug registers @REGS.0=0 R_ZIPCTRL CPU ZIPCTRL @REGS.1=32 R_ZIPREGS ZIPREGS @REGS.2=32 R_ZIPS0 SR0 @REGS.3=33 R_ZIPS1 SR1 @REGS.4=34 R_ZIPS2 SR2 @REGS.5=35 R_ZIPS3 SR3 @REGS.6=36 R_ZIPS4 SR4 @REGS.7=37 R_ZIPS5 SR5 @REGS.8=38 R_ZIPS6 SR6 @REGS.9=39 R_ZIPS7 SR7 @REGS.10=40 R_ZIPS8 SR8 @REGS.11=41 R_ZIPS9 SR9 @REGS.12=42 R_ZIPS10 SR10 @REGS.13=43 R_ZIPS11 SR11 @REGS.14=44 R_ZIPS12 SR12 @REGS.15=45 R_ZIPSSP SSP SR13 @REGS.16=46 R_ZIPCC ZIPCC CC SCC SR14 @REGS.17=47 R_ZIPPC ZIPPC PC SPC SR15 @REGS.18=48 R_ZIPUSER ZIPUSER @REGS.19=48 R_ZIPU0 UR0 @REGS.20=49 R_ZIPU1 UR1 @REGS.21=50 R_ZIPU2 UR2 @REGS.22=51 R_ZIPU3 UR3 @REGS.23=52 R_ZIPU4 UR4 @REGS.24=53 R_ZIPU5 UR5 @REGS.25=54 R_ZIPU6 UR6 @REGS.26=55 R_ZIPU7 UR7 @REGS.27=56 R_ZIPU8 UR8 @REGS.28=57 R_ZIPU9 UR9 @REGS.29=58 R_ZIPU10 SR10 @REGS.30=59 R_ZIPU11 SR11 @REGS.31=60 R_ZIPU12 SR12 @REGS.32=61 R_ZIPUSP USP UR13 @REGS.33=62 R_ZIPUCC ZIPUCC UCC @REGS.34=63 R_ZIPUPC ZIPUPC UPC @REGS.35=64 R_ZIPSYSTEM ZIPSYSTEM ZIPSYS @REGS.35=64 R_ZIPPIC ZIPPIC CPUPIC @REGS.36=65 R_ZIPWATCHDOG ZIPWATCHDOG @REGS.37=66 R_ZIPBUSDOG BUSDOG @REGS.38=67 R_ZIPAPIC ZIPAPIC ALTPIC @REGS.39=68 R_ZIPTIMERA ZIPTMA ZIPTIMERA @REGS.40=69 R_ZIPTIMERB ZIPTMB ZIPTIMERB @REGS.41=70 R_ZIPTIMERC ZIPTMC ZIPTIMERC @REGS.42=71 R_ZIPJIFFIES ZIPJIFF @REGS.43=72 R_ZIPMTASK ZIPMTASK @REGS.44=73 R_ZIPMSTALL ZIPMSTALL @REGS.45=74 R_ZIPMPSTAL ZIPMPSTAL @REGS.46=75 R_ZIPMINSN ZIPMINSN @REGS.47=76 R_ZIPUTASK ZIPUTASK @REGS.48=77 R_ZIPUSTALL ZIPUSTALL @REGS.49=78 R_ZIPUPSTAL ZIPUPSTAL @REGS.50=79 R_ZIPUINSN ZIPUINSN @REGS.51=80 R_ZIPUDMAC ZIPDMAC ## ## ## }}} ================================================ FILE: auto-data/zipmaster.txt ================================================ ################################################################################ ## ## Filename: auto-data/zipmaster.txt ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To describe what needs to be done to make the ZipCPU a part ## of a main .v file. This Wishbone Master description ## illustrates how some of how a wishbone bus master might be integrated ## into the automatic FPGA designer. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## ## Define @SYSPIC so that other peripherals needing to be on the ZipSystem's ## PIC know the name of the PIC we are using. Note that this is a global. ## }}} @SYSPIC= syspic @PREFIX=zip @INCLUDEFILE=zipcpu.txt @MASTER.BUS=wbwide ################################################################################ ## ## Interrupt definitions ## {{{ ################################################################################ @PREFIX=syspic @PIC.BUS= sys_int_vector @PIC.MAX=15 @BDEF.DEFN= #define SYSPIC(A) (1<<(A)) @PREFIX=zip_dmac @INT.DMAC.WIRE= @INT.DMAC.PIC= syspic @INT.DMAC.ID=0 ## #### ## @PREFIX=zip_jiffies @INT.JIFFIES.WIRE= @INT.JIFFIES.PIC= syspic @INT.JIFFIES.ID=1 ## #### ## @PREFIX=zip_tmc @INT.TMC.WIRE= @INT.TMC.PIC= syspic @INT.TMC.ID=2 ## #### ## @PREFIX=zip_tmb @INT.TMB.WIRE= @INT.TMB.PIC= syspic @INT.TMB.ID=3 ## #### ## @PREFIX=TMA @INT.TMA.WIRE= @INT.TMA.PIC= syspic @INT.TMA.ID=4 ## #### ## @PREFIX=alt @INT.ALT.WIRE= @INT.ALT.PIC= syspic @INT.ALT.ID=5 ## #### ## ## @PREFIX=altpic @PIC.BUS= alt_int_vector @PIC.MAX=15 @BDEF.DEFN= #define ALTPIC(A) (1<<(A)) # # @PIC.ASSIGNED= UIC UOC UPC UTC MIC MOC MPC MTC # @PREFIX=zip_alt_uic @INT.UIC.WIRE= @INT.UIC.PIC=altpic @INT.UIC.ID=0 ## @PREFIX=zip_alt_uoc @INT.UOC.WIRE= @INT.UOC.PIC=altpic @INT.UOC.ID=1 ## @PREFIX=zip_alt_upc @INT.UPC.WIRE= @INT.UPC.PIC=altpic @INT.UPC.ID=2 ## @PREFIX=zip_alt_utc @INT.UTC.WIRE= @INT.UTC.PIC=altpic @INT.UTC.ID=3 ## @PREFIX=zip_alt_mic @INT.MIC.WIRE= @INT.MIC.PIC=altpic @INT.MIC.ID=4 ## @PREFIX=zip_alt_moc @INT.MOC.WIRE= @INT.MOC.PIC=altpic @INT.MOC.ID=5 ## @PREFIX=zip_alt_mpc @INT.MPC.WIRE= @INT.MPC.PIC=altpic @INT.MPC.ID=6 ## @PREFIX=zip_alt_mtc @INT.MTC.WIRE= @INT.MTC.PIC=altpic @INT.MTC.ID=7 ## ## }}} ################################################################################ ================================================ FILE: demo-out/board.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: ../demo-out/board.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Computer Generated: This file is computer generated by AUTOFPGA. DO NOT EDIT. // DO NOT EDIT THIS FILE! // // CmdLine: ./autofpga -d -o ../demo-out -I ../auto-data allclocks.txt bkram.txt buserr.txt clkcheck.txt crossbus.txt ddr3.txt edidslvscope.txt edid.txt exconsole.txt flashcfg.txt flash.txt global.txt gpio.txt gps.txt hdmi.txt i2ccpu.txt i2cdma.txt i2saudio.txt icape.txt meganet.txt mdio.txt pic.txt pwrcount.txt rtcdate.txt rtcgps.txt spio.txt sdio.txt vadj33.txt version.txt wboledbw.txt wbpmic.txt wbuarbiter.txt wbubus.txt zipcpu.txt zipmaster.txt // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef BOARD_H #define BOARD_H // And, so that we can know what is and isn't defined // from within our main.v file, let's include: #include #include #ifndef UDP_DBGPORT #define UDP_DBGPORT 6784 #define UDP_DATAPORT 6785 #endif //////////////////////////////////////////////////////////////////////////////// // // ZipCPU defines and macros // {{{ #include #define _HAVE_ZIPSYS #define PIC _zip->z_pic #ifdef INCLUDE_ZIPCPU #ifdef INCLUDE_DMA_CONTROLLER #define _HAVE_ZIPSYS_DMA #endif // INCLUDE_DMA_CONTROLLER #ifdef INCLUDE_ACCOUNTING_COUNTERS #define _HAVE_ZIPSYS_PERFORMANCE_COUNTERS #endif // INCLUDE_ACCOUNTING_COUNTERS #endif // INCLUDE_ZIPCPU // }}} #define SYSPIC(A) (1<<(A)) #define ALTPIC(A) (1<<(A)) //////////////////////////////////////////////////////////////////////// // // I2C CPU data structures // {{{ //////////////////////////////////////////////////////////////////////// // // #ifndef I2CCPU_H #define I2CCPU_H #define I2CC_WAITING 0x00800000 // True if waiting for synch signal #define I2CC_HALT 0x00400000 // Halt request #define I2CC_ABORT 0x00200000 // Abort #define I2CC_ERROR 0x00100000 #define I2CC_HARDHALT 0x00080000 #define I2CC_SCL 0x00000200 #define I2CC_SDA 0x00000100 #define I2CC_STOPPED I2CC_HARDHALT #define I2CC_FAULT (I2CC_ERROR | I2CC_ABORT) #define I2CC_CLEAR (I2CC_FAULT | I2CC_HALT) // For the manual port #define I2CC_MANSCL 0x00008000 #define I2CC_MANSDA 0x00004000 #define I2CC_MANUAL 0x00000800 #define I2CC_TVALID 0x00000200 #define I2CC_TLAST 0x00000100 typedef struct I2CCPU_S { volatile unsigned ic_control, ic_override, ic_address, ic_clkcount; } I2CCPU; #endif // I2CCPU_H // }}} #ifndef WBUART_H #define WBUART_H #define UART_PARITY_NONE 0 #define UART_HWFLOW_OFF 0x40000000 #define UART_PARITY_ODD 0x04000000 #define UART_PARITY_EVEN 0x05000000 #define UART_PARITY_SPACE 0x06000000 #define UART_PARITY_MARK 0x07000000 #define UART_STOP_ONEBIT 0 #define UART_STOP_TWOBITS 0x08000000 #define UART_DATA_8BITS 0 #define UART_DATA_7BITS 0x10000000 #define UART_DATA_6BITS 0x20000000 #define UART_DATA_5BITS 0x30000000 #define UART_RX_BREAK 0x0800 #define UART_RX_FRAMEERR 0x0400 #define UART_RX_PARITYERR 0x0200 #define UART_RX_NOTREADY 0x0100 #define UART_RX_ERR (-256) #define UART_TX_BUSY 0x0100 #define UART_TX_BREAK 0x0200 typedef struct WBUART_S { unsigned u_setup; unsigned u_fifo; unsigned u_rx, u_tx; } WBUART; #endif // WBUART_H #ifndef VIDPIPE_H #define VIDPIPE_H #define VIDPIPE_RESET 0x000001 #define VIDPIPE_RXPLLCK 0x000002 #define VIDPIPE_LOCALCK 0x000000 #define VIDPIPE_RXCLOCK 0x000020 #define VIDPIPE_LCLSRC 0x000000 #define VIDPIPE_RXSRC 0x000040 #define VIDPIPE_RXSYNCD 0x010000 #define VIDPIPE_OVLYERR 0x020000 #define VIDCMAP_BW 0x000000 #define VIDCMAP_2GRAY 0x000100 #define VIDCMAP_4CMAP 0x000200 #define VIDCMAP_8CMAP 0x000300 #define VIDCMAP_8CLR 0x000400 #define VIDCMAP_16CLR 0x000500 #define VIDCMAP_24CLR 0x000600 #define VIDCMAP_32CLR 0x000700 typedef struct __attribute__((packed)) VIDMODE_S { uint16_t m_height, m_width; uint16_t m_vporch, m_hporch; uint16_t m_vsync, m_hsync; uint16_t m_raw_height, m_raw_width; } VIDMODE; typedef struct __attribute__((packed)) VIDPIPE_S { uint32_t v_control, v_hdmifreq, v_sifreq, v_pxfreq; VIDMODE v_in, v_src; const char *v_overlay; uint16_t v_ovheight, v_ovwidth; uint16_t v_ovypos, v_ovhpos; unsigned v_fps; uint32_t v_capture; const char *v_capbase; uint32_t v_capwords, v_capposn, v_capsize; unsigned v_ovwords; unsigned v_unused2[2]; unsigned v_syncword; uint32_t v_unused[512-25]; uint32_t v_clrmap[256]; } VIDPIPE; #endif // VIDPIPE_H #ifndef WBSCOPE_H #define WBSCOPE_H #define WBSCOPE_NO_RESET 0x80000000u #define WBSCOPE_STOPPED 0x40000000u #define WBSCOPE_TRIGGERED 0x20000000u #define WBSCOPE_PRIMED 0x10000000u #define WBSCOPE_TRIGGER (WBSCOPE_NO_RESET|0x08000000u) #define WBSCOPE_MANUAL (WBSCOPE_TRIGGER) #define WBSCOPE_DISABLE 0x04000000u typedef struct WBSCOPE_S { volatile unsigned s_ctrl, s_data; } WBSCOPE; #endif // Offsets for the ICAPE2 interface #define CFG_CRC 0 #define CFG_FAR 1 #define CFG_FDRI 2 #define CFG_FDRO 3 #define CFG_CMD 4 #define CFG_CTL0 5 #define CFG_MASK 6 #define CFG_STAT 7 #define CFG_LOUT 8 #define CFG_COR0 9 #define CFG_MFWR 10 #define CFG_CBC 11 #define CFG_IDCODE 12 #define CFG_AXSS 13 #define CFG_COR1 14 #define CFG_WBSTAR 16 #define CFG_TIMER 17 #define CFG_BOOTSTS 22 #define CFG_CTL1 24 #define CFG_BSPI 31 typedef struct DDR3_PHY_S { unsigned ph_something; } DDR3_PHY; #ifndef I2CDMA_H #define I2CDMA_H //////////////////////////////////////////////////////////////////////// // // I2C DMA data structures // {{{ //////////////////////////////////////////////////////////////////////// // // typedef struct I2CDMA_S { unsigned id_control, id_current, id_base, id_memlen; } I2CDMA; #endif // I2CDMA_H // }}} typedef struct GPSTB_S { unsigned tb_maxcount, tb_jump; unsigned long tb_err, tb_count, tb_step; } GPSTB; // Network stream/packet interface // {{{ #ifndef ENETSTREAM_H #define ENETSTREAM_H typedef struct ENETSTREAM_S { unsigned n_rxcmd, n_txcmd; unsigned long n_mac; unsigned n_ipaddr; unsigned n_rxmiss, n_rxerr, n_rxcrc; // unsigned n_rxpkt, n_rxarp, n_rxicmp; unsigned n_txpkt, n_txarp, n_txicmp; unsigned n_data, n_aborts; unsigned n_rxdbg, n_txdbg; } ENETSTREAM; #endif // }}} typedef struct RTCLIGHT_S { unsigned r_clock, r_stopwatch, r_timer, r_alarm; } RTCLIGHT; #define SPIO_BTNC 0x01000 #define SPIO_BTND 0x00800 #define SPIO_BTNL 0x00400 #define SPIO_BTNR 0x00200 #define SPIO_BTNU 0x00100 // // GPIO input wires // #define GPIO_HDMIRX_CEC 0x000010000 #define GPIO_HDMITX_CEC 0x000020000 #define GPIO_SD_DETECTED 0x000080000 #define GPIO_HDMITX_DETECT 0x000100000 #define GPIO_GPS_3DF 0x000200000 #define GPIO_SYSCLK_LOCKED 0x000400000 #define GPIO_VIDCLK_LOCKED 0x000800000 // // GPIO output wires // #define GPIO_SET(WIRE) (((WIRE)<<16)|(WIRE)) #define GPIO_CLR(WIRE) ((WIRE)<<16) // #define GPIO_HDMIRX_CEC_SET 0x000010001 #define GPIO_HDMIRX_CEC_CLR 0x000010000 #define GPIO_HDMITX_CEC_SET 0x000020002 #define GPIO_HDMITX_CEC_CLR 0x000020000 // #define GPIO_HDMIRX_TXEN 0x000000004 #define GPIO_HDMIRX_HPA 0x000000008 #define GPIO_SD_RESET 0x000000010 #define GPIO_OLED_RESET 0x000000020 #define GPIO_OLED_PANELEN 0x000000040 #define GPIO_OLED_LOGICEN 0x000000080 #define GPIO_TRACE 0x000000100 #define GPIO_TESTHALT 0x000000200 // #define GPIO_EDID_SCL_SET GPIO_SET(GPIO_EDID_SCL) #define GPIO_EDID_SCL_CLR GPIO_CLR(GPIO_EDID_SCL) #define GPIO_EDID_SDA_SET GPIO_SET(GPIO_EDID_SDA) #define GPIO_EDID_SDA_CLR GPIO_CLR(GPIO_EDID_SDA) #define GPIO_HDMIRX_HPA_SET GPIO_SET(GPIO_HDMIRX_HPA) #define GPIO_HDMIRX_HPA_CLR GPIO_CLR(GPIO_HDMIRX_HPA) #define GPIO_SD_RESET_SET GPIO_SET(GPIO_SD_RESET) #define GPIO_SD_RESET_CLR GPIO_CLR(GPIO_SD_RESET) #define GPIO_HDMIRX_TXEN_SET GPIO_SET(GPIO_HDMIRX_TXEN) #define GPIO_HDMIRX_TXEN_CLR GPIO_CLR(GPIO_HDMIRX_TXEN) #define OLED_RESET GPIO_SET(GPIO_OLED_RESET) #define OLED_RUN GPIO_CLR(GPIO_OLED_RESET) #define OLED_PANELEN GPIO_SET(GPIO_OLED_PANELEN) #define OLED_PANELDIS GPIO_CLR(GPIO_OLED_PANELEN) #define OLED_LOGICEN GPIO_SET(GPIO_OLED_LOGICEN) #define OLED_LOGICDIS GPIO_CLR(GPIO_OLED_LOGICEN) #define GPIO_TRACE_SET GPIO_SET(GPIO_TRACE) #define GPIO_TRACE_CLR GPIO_CLR(GPIO_TRACE) #define GPIO_HALT_SET GPIO_SET(GPIO_TESTHALT) #define GPIO_HALT_CLR GPIO_CLR(GPIO_TESTHALT) //////////////////////////////////////////////////////////////////////////////// // // SDIO SD Card constants // {{{ //////////////////////////////////////////////////////////////////////////////// // // // These will be defined in sdiodrv.h for the SDIO controller struct SDIO_S; // }}} #define BUSPIC(X) (1< for a copy. * * License: GPL, v3, as defined and found on www.gnu.org, * http://www.gnu.org/licenses/gpl.html * * /******************************************************************************* * * */ ENTRY(_start) MEMORY { /* To be listed here, a slave must be of type MEMORY. If the slave * has a defined name in its @LD.NAME tag, it will be listed here * under that name. The permissions are given by the @LD.PERM tag. * If no permission tag exists, a permission of 'r' will be assumed. */ bkram(wx) : ORIGIN = 0x00c00000, LENGTH = 0x00100000 flash(rx) : ORIGIN = 0x01000000, LENGTH = 0x01000000 } /* For each defined memory peripheral, we also define a pointer to that * memory. The name of this pointer is given by the @LD.NAME tag within * the memory peripheral's configuration */ _bkram = ORIGIN(bkram); _flash = ORIGIN(flash); SECTIONS { .rocode 32'h01400000 : ALIGN(4) { _boot_address = .; *(.start) *(.boot) } > flash _kernel_image_start = . ; _kernel_image_end = . ; _ram_image_start = . ; .ramcode : ALIGN_WITH_INPUT { *(.kernel) *(.text.startup) *(.text) *(.rodata) *(.strings) *(.data) *(COMMON) }> bkram AT> flash _ram_image_end = . ; .bss : ALIGN_WITH_INPUT { *(.bss) _bss_image_end = . ; }> bkram _top_of_heap = .; } ================================================ FILE: demo-out/build.xdc ================================================ ================================================ FILE: demo-out/iscachable.v ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: ../demo-out/iscachable.v // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Computer Generated: This file is computer generated by AUTOFPGA. DO NOT EDIT. // DO NOT EDIT THIS FILE! // // CmdLine: ./autofpga -d -o ../demo-out -I ../auto-data allclocks.txt bkram.txt buserr.txt clkcheck.txt crossbus.txt ddr3.txt edidslvscope.txt edid.txt exconsole.txt flashcfg.txt flash.txt global.txt gpio.txt gps.txt hdmi.txt i2ccpu.txt i2cdma.txt i2saudio.txt icape.txt meganet.txt mdio.txt pic.txt pwrcount.txt rtcdate.txt rtcgps.txt spio.txt sdio.txt vadj33.txt version.txt wboledbw.txt wbpmic.txt wbuarbiter.txt wbubus.txt zipcpu.txt zipmaster.txt // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} `default_nettype none // module iscachable( // {{{ input wire [31-1:0] i_addr, output reg o_cachable // }}} ); always @(*) begin o_cachable = 1'b0; // Bus master: wbwide // Bus master: wbflash // flash if ((i_addr[30:0] & 31'h79000000) == 31'h01000000) o_cachable = 1'b1; // Bus master: wb32 // Bus master: wb32_dio // Bus master: wb32_sio // bkram if ((i_addr[30:0] & 31'h78000000) == 31'h10000000) o_cachable = 1'b1; // ddr3 if ((i_addr[30:0] & 31'h40000000) == 31'h40000000) o_cachable = 1'b1; end endmodule ================================================ FILE: demo-out/main.v ================================================ `timescale 1ps / 1ps //////////////////////////////////////////////////////////////////////////////// // // Filename: ../demo-out/main.v // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Computer Generated: This file is computer generated by AUTOFPGA. DO NOT EDIT. // DO NOT EDIT THIS FILE! // // CmdLine: ./autofpga -d -o ../demo-out -I ../auto-data allclocks.txt bkram.txt buserr.txt clkcheck.txt crossbus.txt ddr3.txt edidslvscope.txt edid.txt exconsole.txt flashcfg.txt flash.txt global.txt gpio.txt gps.txt hdmi.txt i2ccpu.txt i2cdma.txt i2saudio.txt icape.txt meganet.txt mdio.txt pic.txt pwrcount.txt rtcdate.txt rtcgps.txt spio.txt sdio.txt vadj33.txt version.txt wboledbw.txt wbpmic.txt wbuarbiter.txt wbubus.txt zipcpu.txt zipmaster.txt // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} `default_nettype none //////////////////////////////////////////////////////////////////////////////// // // Macro defines // {{{ // // // Here is a list of defines which may be used, post auto-design // (not post-build), to turn particular peripherals (and bus masters) // on and off. In particular, to turn off support for a particular // design component, just comment out its respective `define below. // // These lines are taken from the respective @ACCESS tags for each of our // components. If a component doesn't have an @ACCESS tag, it will not // be listed here. // // First, the independent access fields for any bus masters `define EXBUS_MASTER `define ALLCLOCKS_PRESENT `define VADJ_ACCESS // And then for the independent peripherals `define FLASH_ACCESS `define I2CCPU_ACCESS `define EDID_ACCESS `define GPSUART_ACCESS `define VIDPIPE_ACCESS `define EDIDSLVSCOPE_SCOPC `define CFG_ACCESS `define BKRAM_ACCESS `define SDRAM_ACCESS `define DDR3_PHY_ACCESS `define I2CDMA_ACCESS `define PWRCOUNT_ACCESS `define MEGANET_ACCESS `define RTC_ACCESS `define SPIO_ACCESS `define GPIO_ACCESS `define SDIO_ACCESS `define BUSPIC_ACCESS `define GPSTRK_ACCESS `define NETCTRL_ACCESS `define VERSION_ACCESS `define OLEDBW_ACCESS `define MICROPHONE_ACCESS `define INCLUDE_ZIPCPU // // // The list of those things that have @DEPENDS tags // // // // Dependencies // Any core with both an @ACCESS and a @DEPENDS tag will show up here. // The @DEPENDS tag will turn into a series of ifdef's, with the @ACCESS // being defined only if all of the ifdef's are true// // Deplist for @$(PREFIX)=rtcdate `ifdef RTC_ACCESS `define RTCDATE_ACCESS `endif // RTC_ACCESS // Deplist for @$(PREFIX)=flashcfg `ifdef FLASH_ACCESS `define FLASHCFG_ACCESS `endif // FLASH_ACCESS // Deplist for @$(PREFIX)=txclk `ifdef ALLCLOCKS_PRESENT `define TXCLK `endif // ALLCLOCKS_PRESENT // Deplist for @$(PREFIX)=adcclk `ifdef ALLCLOCKS_PRESENT `define ADCCLK `endif // ALLCLOCKS_PRESENT // Deplist for @$(PREFIX)=i2saudio // Deplist for @$(PREFIX)=rxeth0ck `ifdef MEGANET_ACCESS `define RXETH0CK `endif // MEGANET_ACCESS // Deplist for @$(PREFIX)=i2saudio // // The following macros have unmet dependencies. They are listed // here for reference, but their dependencies cannot be met. // Unmet Dependency list for @$(PREFIX)=i2saudio `ifdef ARBITRARY_CLOCK_GENERATOR_ACCESS // This value is unknown `define I2SAUDIO `endif // // End of dependency list // // // }}} //////////////////////////////////////////////////////////////////////////////// // // Any include files // {{{ // These are drawn from anything with a MAIN.INCLUDE definition. `include "builddate.v" // }}} // // Finally, we define our main module itself. We start with the list of // I/O ports, or wires, passed into (or out of) the main function. // // These fields are copied verbatim from the respective I/O port lists, // from the fields given by @MAIN.PORTLIST // module main(i_clk, i_reset, // {{{ // The Universal QSPI Flash o_flash_cs_n, o_flash_sck, o_flash_dat, i_flash_dat, o_flash_mod, i_i2c_sda, i_i2c_scl, o_i2c_sda, o_i2c_scl, // UART/host to wishbone interface i_wbu_uart_rx, o_wbu_uart_tx, i_edid_sda, i_edid_scl, o_edid_sda, o_edid_scl, // The GPS-UART i_gpsu_rx, o_gpsu_tx, // HDMI control ports `ifndef VERILATOR i_hdmiclk, `endif i_pixclk, i_hdmi_red, i_hdmi_grn, i_hdmi_blu, o_hdmi_red, o_hdmi_grn, o_hdmi_blu, o_hdmi_iodelay, i_hdmi_iodelay, o_pix_reset_n, i_pxpll_locked, o_hdmirx_reset_n, o_pxclk_cksel, // EDID RX definitions i_edidslv_scl, i_edidslv_sda, o_edidslv_scl, o_edidslv_sda, // DDR3 Controller Interface i_ddr3_iserdes_data, i_ddr3_iserdes_dqs, i_ddr3_iserdes_bitslip_reference, i_ddr3_idelayctrl_rdy, o_ddr3_cmd, o_ddr3_dqs_tri_control, o_ddr3_dq_tri_control, o_ddr3_toggle_dqs, o_ddr3_data, o_ddr3_dm, o_ddr3_odelay_data_cntvaluein, o_ddr3_odelay_dqs_cntvaluein, o_ddr3_idelay_data_cntvaluein, o_ddr3_idelay_dqs_cntvaluein, o_ddr3_odelay_data_ld, o_ddr3_odelay_dqs_ld, o_ddr3_idelay_data_ld, o_ddr3_idelay_dqs_ld, o_ddr3_bitslip, o_ddr3_leveling_calib, o_ddr3_reset, o_i2s_lrclk, o_i2s_bclk, o_i2s_mclk, o_i2s_dac, i_i2s_adc, o_pxclk_cyc, o_pxclk_stb, o_pxclk_we, o_pxclk_addr, o_pxclk_data, o_pxclk_sel, i_pxclk_stall, i_pxclk_ack, i_pxclk_idata, // Ethernet control (packets) lines o_net_reset_n, // eth_int_b // Interrupt, leave floating // eth_pme_b // Power management event, leave floating i_net_rx_clk, i_net_rx_dv, i_net_rx_err, i_net_rxd, o_net_tx_clk, o_net_tx_ctl, o_net_txd, // SPIO interface i_sw, i_btnc, i_btnd, i_btnl, i_btnr, i_btnu, o_led, // GPIO ports `ifdef VERILATOR o_trace, o_halt, `endif i_gpio, o_gpio, // SDIO SD Card i_sdio_detect, // o_sdio_cfg_ddr, o_sdio_cfg_ds, o_sdio_cfg_dscmd, o_sdio_cfg_sample_shift, o_sdio_cmd_tristate, o_sdio_data_tristate, // o_sdio_sdclk, o_sdio_cmd_en, o_sdio_cmd_data, o_sdio_data_en, o_sdio_rx_en, o_sdio_tx_data, // i_sdio_cmd_strb, i_sdio_cmd_data, i_sdio_cmd_collision, i_sdio_crcack, i_sdio_crcnak, i_sdio_card_busy, i_sdio_rx_strb, i_sdio_rx_data, // i_sdio_ac_valid, i_sdio_ac_data, i_sdio_ad_valid, i_sdio_ad_data, o_sdio_hwreset_n, o_sdio_1p8v, i_sdio_debug, // Extra clocks i_clk_125mhz, // The GPS 1PPS signal port i_gps_pps, // The ethernet MDIO wires o_mdclk, o_mdio, o_mdwe, i_mdio, // OLED control interface (roughly SPI) o_oled_sck, o_oled_mosi, o_oled_dcn, // The PMic3 microphone wires o_mic_csn, o_mic_sck, i_mic_din, // Veri1ator only interface cpu_sim_cyc, cpu_sim_stb, cpu_sim_we, cpu_sim_addr, cpu_sim_data, cpu_sim_stall, cpu_sim_ack, cpu_sim_idata, `ifdef VERILATOR cpu_prof_stb, cpu_prof_addr, cpu_prof_ticks, `endif i_cpu_reset // }}} ); //////////////////////////////////////////////////////////////////////////////// // // Any parameter definitions // {{{ // These are drawn from anything with a MAIN.PARAM definition. // As they aren't connected to the toplevel at all, it would // be best to use localparam over parameter, but here we don't // check //////////////////////////////////////////////////////////////////////// // // EXBUS parameters // {{{ // Baudrate : 1000000 // Clock : 100000000 localparam [23:0] BUSUART = 24'h64; // 1000000 baud localparam DBGBUSBITS = $clog2(BUSUART); // }}} localparam ICAPE_LGDIV=3; localparam real SDRAMCONTROLLER_CLK_PERIOD = 10_000, //ps, clock period of the controller interface DDR3_CLK_PERIOD = 2_500; //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD) localparam SDRAMROW_BITS = 14, // width of row address SDRAMCOL_BITS = 10, // width of column address SDRAMBA_BITS = 3, // width of bank address SDRAMDQ_BITS = 8, // Size of one octet SDRAMBYTE_LANES = 2, //8 lanes of DQ SDRAMAUX_WIDTH = 4, //width of aux line (must be >= 4) SDRAMSERDES_RATIO = $rtoi(SDRAMCONTROLLER_CLK_PERIOD/DDR3_CLK_PERIOD), //4 is the width of a single ddr3 command {cs_n, ras_n, cas_n, we_n} plus 3 (ck_en, odt, reset_n) plus bank bits plus row bits SDRAMCMD_LEN = 4 + 3 + SDRAMBA_BITS + SDRAMROW_BITS; parameter [15:0] UDP_DBGPORT = 6784; localparam [47:0] DEF_HWMAC = 48'h82_33_48_02_e1_c8; localparam [31:0] DEF_IPADDR = { 8'd192, 8'd168, 8'd15, 8'd29 }; localparam [31:0] GPSCLOCK_DEFAULT_STEP = 32'haabcc771; //////////////////////////////////////////////////////////////////////// // // Variables/definitions/parameters used by the ZipCPU bus master // {{{ // // A 32-bit address indicating where the ZipCPU should start running // from `ifdef BKROM_ACCESS localparam RESET_ADDRESS = @$(/bkrom.BASE); `else `ifdef FLASH_ACCESS localparam RESET_ADDRESS = 23068672; `else localparam RESET_ADDRESS = 268435456; `endif // FLASH_ACCESS `endif // BKROM_ACCESS // // The number of valid bits on the bus localparam ZIP_ADDRESS_WIDTH = 27; // Zip-CPU address width // // Number of ZipCPU interrupts localparam ZIP_INTS = 16; // // ZIP_START_HALTED // // A boolean, indicating whether or not the ZipCPU be halted on startup? `ifdef BKROM_ACCESS localparam ZIP_START_HALTED=1'b0; `else localparam ZIP_START_HALTED=1'b1; `endif // }}} // }}} //////////////////////////////////////////////////////////////////////////////// // // Port declarations // {{{ // The next step is to declare all of the various ports that were just // listed above. // // The following declarations are taken from the values of the various // @MAIN.IODECL keys. // input wire i_clk; // verilator lint_off UNUSED input wire i_reset; // verilator lint_on UNUSED // The Universal QSPI flash output wire o_flash_cs_n, o_flash_sck; output wire [3:0] o_flash_dat; input wire [3:0] i_flash_dat; output wire [1:0] o_flash_mod; // I2C Port declarations // {{{ input wire i_i2c_sda, i_i2c_scl; output wire o_i2c_sda, o_i2c_scl; // }}} input wire i_wbu_uart_rx; output wire o_wbu_uart_tx; // I2C Port declarations // {{{ input wire i_edid_sda, i_edid_scl; output wire o_edid_sda, o_edid_scl; // }}} input wire i_gpsu_rx; output wire o_gpsu_tx; // hdmi declarations // {{{ `ifndef VERILATOR input wire i_hdmiclk; `endif input wire i_pixclk; input wire [9:0] i_hdmi_red, i_hdmi_grn, i_hdmi_blu; output wire [9:0] o_hdmi_red, o_hdmi_grn, o_hdmi_blu; output wire [14:0] o_hdmi_iodelay; input wire [14:0] i_hdmi_iodelay; output wire o_pix_reset_n, o_hdmirx_reset_n; input wire i_pxpll_locked; output wire [1:0] o_pxclk_cksel; // }}} // EDID RX definitions input wire i_edidslv_scl, i_edidslv_sda; output wire o_edidslv_scl, o_edidslv_sda; // DDR3 Controller I/O declarations // {{{ input wire [SDRAMDQ_BITS*SDRAMBYTE_LANES*8-1:0] i_ddr3_iserdes_data; input wire [SDRAMBYTE_LANES*8-1:0] i_ddr3_iserdes_dqs; input wire [SDRAMBYTE_LANES*8-1:0] i_ddr3_iserdes_bitslip_reference; input wire i_ddr3_idelayctrl_rdy; output wire [SDRAMCMD_LEN*SDRAMSERDES_RATIO-1:0] o_ddr3_cmd; output wire o_ddr3_dqs_tri_control, o_ddr3_dq_tri_control; output wire o_ddr3_toggle_dqs; output wire [SDRAMDQ_BITS*SDRAMBYTE_LANES*8-1:0] o_ddr3_data; output wire [(SDRAMDQ_BITS*SDRAMBYTE_LANES*8)/8-1:0] o_ddr3_dm; output wire [4:0] o_ddr3_odelay_data_cntvaluein, o_ddr3_odelay_dqs_cntvaluein; output wire [4:0] o_ddr3_idelay_data_cntvaluein, o_ddr3_idelay_dqs_cntvaluein; output wire [SDRAMBYTE_LANES-1:0] o_ddr3_odelay_data_ld, o_ddr3_odelay_dqs_ld; output wire [SDRAMBYTE_LANES-1:0] o_ddr3_idelay_data_ld, o_ddr3_idelay_dqs_ld; output wire [SDRAMBYTE_LANES-1:0] o_ddr3_bitslip; output wire o_ddr3_leveling_calib; output wire o_ddr3_reset; // }}} output wire o_i2s_lrclk, o_i2s_bclk, o_i2s_mclk, o_i2s_dac; input wire i_i2s_adc; output wire o_pxclk_cyc, o_pxclk_stb, o_pxclk_we; output wire [6:0] o_pxclk_addr; output wire [31:0] o_pxclk_data; output wire [3:0] o_pxclk_sel; input wire i_pxclk_stall, i_pxclk_ack; input wire [31:0] i_pxclk_idata; // Ethernet (RGMII) control // {{{ // Verilator lint_off SYNCASYNCNET output wire o_net_reset_n; // Verilator lint_on SYNCASYNCNET input wire i_net_rx_clk, i_net_rx_dv, i_net_rx_err; input wire [7:0] i_net_rxd; output wire [1:0] o_net_tx_clk; output wire o_net_tx_ctl; output wire [7:0] o_net_txd; // }}} // SPIO interface input wire [8-1:0] i_sw; input wire i_btnc, i_btnd, i_btnl, i_btnr, i_btnu; output wire [8-1:0] o_led; localparam NGPI = 8, NGPO=10; // GPIO ports `ifdef VERILATOR output wire o_trace; output wire o_halt; `endif input [(NGPI-1):0] i_gpio; output wire [(NGPO-1):0] o_gpio; // SDIO SD Card declarations // {{{ input wire i_sdio_detect; // output wire o_sdio_cfg_ddr; output wire o_sdio_cfg_ds; output wire o_sdio_cfg_dscmd; output wire [4:0] o_sdio_cfg_sample_shift; output wire o_sdio_cmd_tristate; output wire o_sdio_data_tristate; // output wire [7:0] o_sdio_sdclk; output wire o_sdio_cmd_en; output wire [1:0] o_sdio_cmd_data; output wire o_sdio_data_en; output wire o_sdio_rx_en; output wire [31:0] o_sdio_tx_data; // input wire [1:0] i_sdio_cmd_strb; input wire [1:0] i_sdio_cmd_data; input wire i_sdio_cmd_collision; input wire i_sdio_crcack; input wire i_sdio_crcnak; input wire i_sdio_card_busy; input wire [1:0] i_sdio_rx_strb; input wire [15:0] i_sdio_rx_data; // input wire i_sdio_ac_valid; input wire [1:0] i_sdio_ac_data; input wire i_sdio_ad_valid; input wire [31:0] i_sdio_ad_data; output wire o_sdio_hwreset_n, o_sdio_1p8v; // Verilator lint_off UNUSED input wire [31:0] i_sdio_debug; // Verilator lint_on UNUSED // }}} // Extra clocks // Verilator lint_off UNUSED input wire i_clk_125mhz; // Verilator lint_on UNUSED //The GPS Clock input wire i_gps_pps; // Ethernet control (MDIO) output wire o_mdclk, o_mdio, o_mdwe; input wire i_mdio; // OLEDBW interface output wire o_oled_sck, o_oled_mosi, o_oled_dcn; output wire o_mic_csn, o_mic_sck; input wire i_mic_din; input wire cpu_sim_cyc, cpu_sim_stb; input wire cpu_sim_we; input wire [6:0] cpu_sim_addr; input wire [31:0] cpu_sim_data; // output wire cpu_sim_stall, cpu_sim_ack; output wire [31:0] cpu_sim_idata; // `ifdef VERILATOR output wire cpu_prof_stb; output wire [27+$clog2(128/8)-1:0] cpu_prof_addr; output wire [31:0] cpu_prof_ticks; `endif input wire i_cpu_reset; // }}} // Make Verilator happy // {{{ // Defining bus wires for lots of components often ends up with unused // wires lying around. We'll turn off Ver1lator's lint warning // here that checks for unused wires. // }}} // verilator lint_off UNUSED //////////////////////////////////////////////////////////////////////// // // Declaring interrupt lines // {{{ // These declarations come from the various components values // given under the @INT..WIRE key. // wire i2c_int; // i2c.INT.I2C.WIRE wire edid_int; // edid.INT.EDID.WIRE wire gpsurxf_int; // gpsu.INT.GPSRXF.WIRE wire gpsutxf_int; // gpsu.INT.GPSTXF.WIRE wire gpsutx_int; // gpsu.INT.GPSTX.WIRE wire gpsurx_int; // gpsu.INT.GPSRX.WIRE wire hdmi_int; // hdmi.INT.VIDFRAME.WIRE wire edidslvscope_int; // edidslvscope.INT.EDIDSLVSCOPE.WIRE wire rtc_int; // rtc.INT.RTC.WIRE wire spio_int; // spio.INT.SPIO.WIRE wire gpio_int; // gpio.INT.GPIO.WIRE wire sdio_int; // sdio.INT.SDCARD.WIRE wire w_bus_int; // buspic.INT.BUS.WIRE wire gck_pps; // gck.INT.PPS.WIRE wire oled_int; // oled.INT.OLED.WIRE wire pmic_int; // pmic.INT.MIC.WIRE wire zip_cpu_int; // zip.INT.ZIP.WIRE // }}} //////////////////////////////////////////////////////////////////////// // // Component declarations // {{{ // These declarations come from the @MAIN.DEFNS keys found in the // various components comprising the design. // // Definitions for the flash debug port // Verilator lint_off UNUSED wire flash_dbg_trigger; wire [31:0] flash_debug; // Verilator lint_on UNUSED // I2C Controller // {{{ // Verilator lint_off UNUSED localparam I2CCPU_WIDTH=(2 == 0) ? 1 : 2; wire i2c_valid, i2c_ready, i2c_last; wire [7:0] i2c_data; wire [I2CCPU_WIDTH-1:0] i2c_id; wire [31:0] i2c_debug; // Verilator lint_on UNUSED // }}} reg [30-1:0] r_buserr_addr; `ifndef GPSTRK_ACCESS reg [31:0] r_subseconds_data; `endif reg r_adcclk_ack; //////////////////////////////////////////////////////////////////////// // // EXBUS: USB-UART interface declarations // {{{ // wire [7:0] wbu_rx_data, wbu_tx_data; wire wbu_rx_stb; wire wbu_tx_stb, wbu_tx_busy; // Verilator lint_off UNUSED wire [0:0] ex_reset; wire [1:0] ex_gpio; // Verilator lint_on UNUSED // }}} // I2C Controller // {{{ // Verilator lint_off UNUSED localparam EDID_WIDTH=(2 == 0) ? 1 : 2; wire edid_valid, edid_ready, edid_last; wire [7:0] edid_data; wire [EDID_WIDTH-1:0] edid_id; wire [31:0] edid_debug; // Verilator lint_on UNUSED // }}} wire w_gpsu_cts_n, w_gpsu_rts_n; assign w_gpsu_cts_n=1'b1; // Verilator lint_off UNUSED `ifdef VERILATOR wire i_hdmiclk; `endif wire hdmidbg_ce, hdmidbg_trigger; wire [31:0] hdmiclr_debug; // Verilator lint_on UNUSED // Verilator lint_off UNUSED wire [31:0] edidslv_dbg; // Verilator lint_on UNUSED reg r_txclk_ack; reg r_rxeth0ck_ack; // Verilator lint_off UNUSED reg rtc_pps; reg [26:0] rtc_pps_counter; // Verilator lint_on UNUSED // Verilator lint_off UNUSED wire [SDRAMAUX_WIDTH-1:0] ddr3_aux_out; wire [31:0] ddr3_debug; // Verilator lint_on UNUSED wire i2cdma_ready; reg [31:0] r_pwrcount_data; //////////////////////////////////////////////////////////////////////// // // I2S Audio signal definitions // {{{ wire w_i2saudio_en; // Verilator lint_off UNUSED // // These wires may or may not be connected to anything ... wire w_audio_out_valid, w_audio_out_ready, w_audio_out_last; wire [23:0] w_audio_out_data; // // w_audio_in... comes from the microphone (if present) wire w_audio_in_valid, w_audio_in_ready, w_audio_in_last; wire [23:0] w_audio_in_data; wire [31:0] w_i2saudio_debug; // Verilator lint_on UNUSED // }}} wire tb_pps; // Ethernet (RGMII) control // {{{ // Verilator lint_off UNUSED wire [47:0] net_hwmac, net_last_ping_hwmac; wire [31:0] net_ip_addr, net_last_ping_ipaddr; wire netcpurx_valid, netcpurx_ready; wire [31:0] netcpurx_data; wire [1:0] netcpurx_bytes; wire netcpurx_last, netcpurx_abort; wire netcputx_valid, netcputx_ready, netcputx_last, netcputx_abort; wire [31:0] netcputx_data; wire [1:0] netcputx_bytes; wire net_dbg_valid, net_dbg_ready, net_dbg_last; wire [31:0] net_dbg_data; wire [1:0] net_dbg_bytes; wire net_high_speed; wire net_debug_clk; wire [31:0] net_debug; wire ign_rxpkt_net_ready; // Verilator lint_on UNUSED // }}} // Definitions in support of the GPS driven RTC // This clock step is designed to match 100000000 Hz localparam [31:0] RTC_CLKSTEP = 32'h002af31d; wire rtc_ppd; wire rtc_pps; wire [5-1:0] w_btn; wire [8-1:0] w_led; wire sd_reset; // SDIO SD Card definitions // Verilator lint_off UNUSED wire [31:0] w_sdio_sdwb_debug; wire s_sdio_ready, m_sdio_valid, m_sdio_last; reg [31:0] sdio_debug; wire [31:0] m_sdio_data; // assign sdio_debug = i_sdio_debug; // Verilator lint_on UNUSED wire i_net_tx_clk; wire ck_pps; wire gps_pps, gps_led, gps_locked, gps_tracking; wire [63:0] gps_now, gps_err, gps_step; wire [1:0] gps_dbg_tick; // Verilator lint_off UNUSED wire[31:0] mdio_debug; // Verilator lint_on UNUSED // BUILDTIME doesnt need to include builddate.v a second time // `include "builddate.v" // OLEDBW // {{{ // Verilator lint_off UNUSED wire [1:0] w_oled_csn; wire ign_oled_valid, ign_oled_last, ign_oled_id; wire [7:0] ign_oled_data; wire [31:0] oled_debug; // Verilator lint_on UNUSED // }}} //////////////////////////////////////////////////////////////////////// // // ZipSystem/ZipCPU connection definitions // {{{ `ifndef VERILATOR wire cpu_prof_stb; wire [27+$clog2(128/8)-1:0] cpu_prof_addr; wire [31:0] cpu_prof_ticks; `endif // All we define here is a set of scope wires // Verilator lint_off UNUSED wire raw_cpu_dbg_stall, raw_cpu_dbg_ack; wire [31:0] zip_debug; wire zip_trigger; // Verilator lint_on UNUSED wire [ZIP_INTS-1:0] zip_int_vector; // }}} // }}} //////////////////////////////////////////////////////////////////////// // // Declaring interrupt vector wires // {{{ // These declarations come from the various components having // PIC and PIC.MAX keys. // wire [14:0] sys_int_vector; wire [14:0] alt_int_vector; wire [14:0] bus_int_vector; // }}} //////////////////////////////////////////////////////////////////////// // // Declare bus signals // {{{ //////////////////////////////////////////////////////////////////////// // Bus wbwide // {{{ // Wishbone definitions for bus wbwide, component i2c // Verilator lint_off UNUSED wire wbwide_i2cm_cyc, wbwide_i2cm_stb, wbwide_i2cm_we; wire [26:0] wbwide_i2cm_addr; wire [127:0] wbwide_i2cm_data; wire [15:0] wbwide_i2cm_sel; wire wbwide_i2cm_stall, wbwide_i2cm_ack, wbwide_i2cm_err; wire [127:0] wbwide_i2cm_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component edid // Verilator lint_off UNUSED wire wbwide_edidm_cyc, wbwide_edidm_stb, wbwide_edidm_we; wire [26:0] wbwide_edidm_addr; wire [127:0] wbwide_edidm_data; wire [15:0] wbwide_edidm_sel; wire wbwide_edidm_stall, wbwide_edidm_ack, wbwide_edidm_err; wire [127:0] wbwide_edidm_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component hdmi // Verilator lint_off UNUSED wire wbwide_hdmi_cyc, wbwide_hdmi_stb, wbwide_hdmi_we; wire [26:0] wbwide_hdmi_addr; wire [127:0] wbwide_hdmi_data; wire [15:0] wbwide_hdmi_sel; wire wbwide_hdmi_stall, wbwide_hdmi_ack, wbwide_hdmi_err; wire [127:0] wbwide_hdmi_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component i2cdma // Verilator lint_off UNUSED wire wbwide_i2cdma_cyc, wbwide_i2cdma_stb, wbwide_i2cdma_we; wire [26:0] wbwide_i2cdma_addr; wire [127:0] wbwide_i2cdma_data; wire [15:0] wbwide_i2cdma_sel; wire wbwide_i2cdma_stall, wbwide_i2cdma_ack, wbwide_i2cdma_err; wire [127:0] wbwide_i2cdma_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component sdio // Verilator lint_off UNUSED wire wbwide_sdio_cyc, wbwide_sdio_stb, wbwide_sdio_we; wire [26:0] wbwide_sdio_addr; wire [127:0] wbwide_sdio_data; wire [15:0] wbwide_sdio_sel; wire wbwide_sdio_stall, wbwide_sdio_ack, wbwide_sdio_err; wire [127:0] wbwide_sdio_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component oled // Verilator lint_off UNUSED wire wbwide_oledm_cyc, wbwide_oledm_stb, wbwide_oledm_we; wire [26:0] wbwide_oledm_addr; wire [127:0] wbwide_oledm_data; wire [15:0] wbwide_oledm_sel; wire wbwide_oledm_stall, wbwide_oledm_ack, wbwide_oledm_err; wire [127:0] wbwide_oledm_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component wbu_arbiter // Verilator lint_off UNUSED wire wbwide_wbu_arbiter_cyc, wbwide_wbu_arbiter_stb, wbwide_wbu_arbiter_we; wire [26:0] wbwide_wbu_arbiter_addr; wire [127:0] wbwide_wbu_arbiter_data; wire [15:0] wbwide_wbu_arbiter_sel; wire wbwide_wbu_arbiter_stall, wbwide_wbu_arbiter_ack, wbwide_wbu_arbiter_err; wire [127:0] wbwide_wbu_arbiter_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component zip // Verilator lint_off UNUSED wire wbwide_zip_cyc, wbwide_zip_stb, wbwide_zip_we; wire [26:0] wbwide_zip_addr; wire [127:0] wbwide_zip_data; wire [15:0] wbwide_zip_sel; wire wbwide_zip_stall, wbwide_zip_ack, wbwide_zip_err; wire [127:0] wbwide_zip_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component crossflash // Verilator lint_off UNUSED wire wbwide_crossflash_cyc, wbwide_crossflash_stb, wbwide_crossflash_we; wire [26:0] wbwide_crossflash_addr; wire [127:0] wbwide_crossflash_data; wire [15:0] wbwide_crossflash_sel; wire wbwide_crossflash_stall, wbwide_crossflash_ack, wbwide_crossflash_err; wire [127:0] wbwide_crossflash_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component crossbus // Verilator lint_off UNUSED wire wbwide_crossbus_cyc, wbwide_crossbus_stb, wbwide_crossbus_we; wire [26:0] wbwide_crossbus_addr; wire [127:0] wbwide_crossbus_data; wire [15:0] wbwide_crossbus_sel; wire wbwide_crossbus_stall, wbwide_crossbus_ack, wbwide_crossbus_err; wire [127:0] wbwide_crossbus_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component bkram // Verilator lint_off UNUSED wire wbwide_bkram_cyc, wbwide_bkram_stb, wbwide_bkram_we; wire [26:0] wbwide_bkram_addr; wire [127:0] wbwide_bkram_data; wire [15:0] wbwide_bkram_sel; wire wbwide_bkram_stall, wbwide_bkram_ack, wbwide_bkram_err; wire [127:0] wbwide_bkram_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbwide, component ddr3 // Verilator lint_off UNUSED wire wbwide_ddr3_cyc, wbwide_ddr3_stb, wbwide_ddr3_we; wire [26:0] wbwide_ddr3_addr; wire [127:0] wbwide_ddr3_data; wire [15:0] wbwide_ddr3_sel; wire wbwide_ddr3_stall, wbwide_ddr3_ack, wbwide_ddr3_err; wire [127:0] wbwide_ddr3_idata; // Verilator lint_on UNUSED // }}} // Bus wbflash // {{{ // Wishbone definitions for bus wbflash, component crossflash // Verilator lint_off UNUSED wire wbflash_crossflash_cyc, wbflash_crossflash_stb, wbflash_crossflash_we; wire [22:0] wbflash_crossflash_addr; wire [31:0] wbflash_crossflash_data; wire [3:0] wbflash_crossflash_sel; wire wbflash_crossflash_stall, wbflash_crossflash_ack, wbflash_crossflash_err; wire [31:0] wbflash_crossflash_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbflash, component sdio // Verilator lint_off UNUSED wire wbflash_sdio_cyc, wbflash_sdio_stb, wbflash_sdio_we; wire [22:0] wbflash_sdio_addr; wire [31:0] wbflash_sdio_data; wire [3:0] wbflash_sdio_sel; wire wbflash_sdio_stall, wbflash_sdio_ack, wbflash_sdio_err; wire [31:0] wbflash_sdio_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbflash, component flash // Verilator lint_off UNUSED wire wbflash_flash_cyc, wbflash_flash_stb, wbflash_flash_we; wire [22:0] wbflash_flash_addr; wire [31:0] wbflash_flash_data; wire [3:0] wbflash_flash_sel; wire wbflash_flash_stall, wbflash_flash_ack, wbflash_flash_err; wire [31:0] wbflash_flash_idata; // Verilator lint_on UNUSED // }}} // Bus wb32 // {{{ // Wishbone definitions for bus wb32, component crossbus // Verilator lint_off UNUSED wire wb32_crossbus_cyc, wb32_crossbus_stb, wb32_crossbus_we; wire [11:0] wb32_crossbus_addr; wire [31:0] wb32_crossbus_data; wire [3:0] wb32_crossbus_sel; wire wb32_crossbus_stall, wb32_crossbus_ack, wb32_crossbus_err; wire [31:0] wb32_crossbus_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component adcclk // Verilator lint_off UNUSED wire wb32_adcclk_cyc, wb32_adcclk_stb, wb32_adcclk_we; wire [11:0] wb32_adcclk_addr; wire [31:0] wb32_adcclk_data; wire [3:0] wb32_adcclk_sel; wire wb32_adcclk_stall, wb32_adcclk_ack, wb32_adcclk_err; wire [31:0] wb32_adcclk_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component buildtime // Verilator lint_off UNUSED wire wb32_buildtime_cyc, wb32_buildtime_stb, wb32_buildtime_we; wire [11:0] wb32_buildtime_addr; wire [31:0] wb32_buildtime_data; wire [3:0] wb32_buildtime_sel; wire wb32_buildtime_stall, wb32_buildtime_ack, wb32_buildtime_err; wire [31:0] wb32_buildtime_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component buserr // Verilator lint_off UNUSED wire wb32_buserr_cyc, wb32_buserr_stb, wb32_buserr_we; wire [11:0] wb32_buserr_addr; wire [31:0] wb32_buserr_data; wire [3:0] wb32_buserr_sel; wire wb32_buserr_stall, wb32_buserr_ack, wb32_buserr_err; wire [31:0] wb32_buserr_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component buspic // Verilator lint_off UNUSED wire wb32_buspic_cyc, wb32_buspic_stb, wb32_buspic_we; wire [11:0] wb32_buspic_addr; wire [31:0] wb32_buspic_data; wire [3:0] wb32_buspic_sel; wire wb32_buspic_stall, wb32_buspic_ack, wb32_buspic_err; wire [31:0] wb32_buspic_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component gpio // Verilator lint_off UNUSED wire wb32_gpio_cyc, wb32_gpio_stb, wb32_gpio_we; wire [11:0] wb32_gpio_addr; wire [31:0] wb32_gpio_data; wire [3:0] wb32_gpio_sel; wire wb32_gpio_stall, wb32_gpio_ack, wb32_gpio_err; wire [31:0] wb32_gpio_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component pwrcount // Verilator lint_off UNUSED wire wb32_pwrcount_cyc, wb32_pwrcount_stb, wb32_pwrcount_we; wire [11:0] wb32_pwrcount_addr; wire [31:0] wb32_pwrcount_data; wire [3:0] wb32_pwrcount_sel; wire wb32_pwrcount_stall, wb32_pwrcount_ack, wb32_pwrcount_err; wire [31:0] wb32_pwrcount_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component rtcdate // Verilator lint_off UNUSED wire wb32_rtcdate_cyc, wb32_rtcdate_stb, wb32_rtcdate_we; wire [11:0] wb32_rtcdate_addr; wire [31:0] wb32_rtcdate_data; wire [3:0] wb32_rtcdate_sel; wire wb32_rtcdate_stall, wb32_rtcdate_ack, wb32_rtcdate_err; wire [31:0] wb32_rtcdate_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component rxeth0ck // Verilator lint_off UNUSED wire wb32_rxeth0ck_cyc, wb32_rxeth0ck_stb, wb32_rxeth0ck_we; wire [11:0] wb32_rxeth0ck_addr; wire [31:0] wb32_rxeth0ck_data; wire [3:0] wb32_rxeth0ck_sel; wire wb32_rxeth0ck_stall, wb32_rxeth0ck_ack, wb32_rxeth0ck_err; wire [31:0] wb32_rxeth0ck_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component spio // Verilator lint_off UNUSED wire wb32_spio_cyc, wb32_spio_stb, wb32_spio_we; wire [11:0] wb32_spio_addr; wire [31:0] wb32_spio_data; wire [3:0] wb32_spio_sel; wire wb32_spio_stall, wb32_spio_ack, wb32_spio_err; wire [31:0] wb32_spio_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component subseconds // Verilator lint_off UNUSED wire wb32_subseconds_cyc, wb32_subseconds_stb, wb32_subseconds_we; wire [11:0] wb32_subseconds_addr; wire [31:0] wb32_subseconds_data; wire [3:0] wb32_subseconds_sel; wire wb32_subseconds_stall, wb32_subseconds_ack, wb32_subseconds_err; wire [31:0] wb32_subseconds_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component txclk // Verilator lint_off UNUSED wire wb32_txclk_cyc, wb32_txclk_stb, wb32_txclk_we; wire [11:0] wb32_txclk_addr; wire [31:0] wb32_txclk_data; wire [3:0] wb32_txclk_sel; wire wb32_txclk_stall, wb32_txclk_ack, wb32_txclk_err; wire [31:0] wb32_txclk_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(SIO), component version // Verilator lint_off UNUSED wire wb32_version_cyc, wb32_version_stb, wb32_version_we; wire [11:0] wb32_version_addr; wire [31:0] wb32_version_data; wire [3:0] wb32_version_sel; wire wb32_version_stall, wb32_version_ack, wb32_version_err; wire [31:0] wb32_version_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(DIO), component edid // Verilator lint_off UNUSED wire wb32_edids_cyc, wb32_edids_stb, wb32_edids_we; wire [11:0] wb32_edids_addr; wire [31:0] wb32_edids_data; wire [3:0] wb32_edids_sel; wire wb32_edids_stall, wb32_edids_ack, wb32_edids_err; wire [31:0] wb32_edids_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(DIO), component gck // Verilator lint_off UNUSED wire wb32_gck_cyc, wb32_gck_stb, wb32_gck_we; wire [11:0] wb32_gck_addr; wire [31:0] wb32_gck_data; wire [3:0] wb32_gck_sel; wire wb32_gck_stall, wb32_gck_ack, wb32_gck_err; wire [31:0] wb32_gck_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(DIO), component i2c // Verilator lint_off UNUSED wire wb32_i2cs_cyc, wb32_i2cs_stb, wb32_i2cs_we; wire [11:0] wb32_i2cs_addr; wire [31:0] wb32_i2cs_data; wire [3:0] wb32_i2cs_sel; wire wb32_i2cs_stall, wb32_i2cs_ack, wb32_i2cs_err; wire [31:0] wb32_i2cs_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(DIO), component i2cdma // Verilator lint_off UNUSED wire wb32_i2cdma_cyc, wb32_i2cdma_stb, wb32_i2cdma_we; wire [11:0] wb32_i2cdma_addr; wire [31:0] wb32_i2cdma_data; wire [3:0] wb32_i2cdma_sel; wire wb32_i2cdma_stall, wb32_i2cdma_ack, wb32_i2cdma_err; wire [31:0] wb32_i2cdma_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(DIO), component oled // Verilator lint_off UNUSED wire wb32_oled_cyc, wb32_oled_stb, wb32_oled_we; wire [11:0] wb32_oled_addr; wire [31:0] wb32_oled_data; wire [3:0] wb32_oled_sel; wire wb32_oled_stall, wb32_oled_ack, wb32_oled_err; wire [31:0] wb32_oled_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(DIO), component rtc // Verilator lint_off UNUSED wire wb32_rtc_cyc, wb32_rtc_stb, wb32_rtc_we; wire [11:0] wb32_rtc_addr; wire [31:0] wb32_rtc_data; wire [3:0] wb32_rtc_sel; wire wb32_rtc_stall, wb32_rtc_ack, wb32_rtc_err; wire [31:0] wb32_rtc_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(DIO), component gtb // Verilator lint_off UNUSED wire wb32_gtb_cyc, wb32_gtb_stb, wb32_gtb_we; wire [11:0] wb32_gtb_addr; wire [31:0] wb32_gtb_data; wire [3:0] wb32_gtb_sel; wire wb32_gtb_stall, wb32_gtb_ack, wb32_gtb_err; wire [31:0] wb32_gtb_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(DIO), component wb32_sio // Verilator lint_off UNUSED wire wb32_sio_cyc, wb32_sio_stb, wb32_sio_we; wire [11:0] wb32_sio_addr; wire [31:0] wb32_sio_data; wire [3:0] wb32_sio_sel; wire wb32_sio_stall, wb32_sio_ack, wb32_sio_err; wire [31:0] wb32_sio_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32(DIO), component edidslv // Verilator lint_off UNUSED wire wb32_edidslv_cyc, wb32_edidslv_stb, wb32_edidslv_we; wire [11:0] wb32_edidslv_addr; wire [31:0] wb32_edidslv_data; wire [3:0] wb32_edidslv_sel; wire wb32_edidslv_stall, wb32_edidslv_ack, wb32_edidslv_err; wire [31:0] wb32_edidslv_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component flashcfg // Verilator lint_off UNUSED wire wb32_flashcfg_cyc, wb32_flashcfg_stb, wb32_flashcfg_we; wire [11:0] wb32_flashcfg_addr; wire [31:0] wb32_flashcfg_data; wire [3:0] wb32_flashcfg_sel; wire wb32_flashcfg_stall, wb32_flashcfg_ack, wb32_flashcfg_err; wire [31:0] wb32_flashcfg_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component edidslvscope // Verilator lint_off UNUSED wire wb32_edidslvscope_cyc, wb32_edidslvscope_stb, wb32_edidslvscope_we; wire [11:0] wb32_edidslvscope_addr; wire [31:0] wb32_edidslvscope_data; wire [3:0] wb32_edidslvscope_sel; wire wb32_edidslvscope_stall, wb32_edidslvscope_ack, wb32_edidslvscope_err; wire [31:0] wb32_edidslvscope_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component pmic // Verilator lint_off UNUSED wire wb32_pmic_cyc, wb32_pmic_stb, wb32_pmic_we; wire [11:0] wb32_pmic_addr; wire [31:0] wb32_pmic_data; wire [3:0] wb32_pmic_sel; wire wb32_pmic_stall, wb32_pmic_ack, wb32_pmic_err; wire [31:0] wb32_pmic_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component gpsu // Verilator lint_off UNUSED wire wb32_gpsu_cyc, wb32_gpsu_stb, wb32_gpsu_we; wire [11:0] wb32_gpsu_addr; wire [31:0] wb32_gpsu_data; wire [3:0] wb32_gpsu_sel; wire wb32_gpsu_stall, wb32_gpsu_ack, wb32_gpsu_err; wire [31:0] wb32_gpsu_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component icape // Verilator lint_off UNUSED wire wb32_icape_cyc, wb32_icape_stb, wb32_icape_we; wire [11:0] wb32_icape_addr; wire [31:0] wb32_icape_data; wire [3:0] wb32_icape_sel; wire wb32_icape_stall, wb32_icape_ack, wb32_icape_err; wire [31:0] wb32_icape_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component net // Verilator lint_off UNUSED wire wb32_net_cyc, wb32_net_stb, wb32_net_we; wire [11:0] wb32_net_addr; wire [31:0] wb32_net_data; wire [3:0] wb32_net_sel; wire wb32_net_stall, wb32_net_ack, wb32_net_err; wire [31:0] wb32_net_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component ddr3_phy // Verilator lint_off UNUSED wire wb32_ddr3_phy_cyc, wb32_ddr3_phy_stb, wb32_ddr3_phy_we; wire [11:0] wb32_ddr3_phy_addr; wire [31:0] wb32_ddr3_phy_data; wire [3:0] wb32_ddr3_phy_sel; wire wb32_ddr3_phy_stall, wb32_ddr3_phy_ack, wb32_ddr3_phy_err; wire [31:0] wb32_ddr3_phy_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component pxclk // Verilator lint_off UNUSED wire wb32_pxclk_cyc, wb32_pxclk_stb, wb32_pxclk_we; wire [11:0] wb32_pxclk_addr; wire [31:0] wb32_pxclk_data; wire [3:0] wb32_pxclk_sel; wire wb32_pxclk_stall, wb32_pxclk_ack, wb32_pxclk_err; wire [31:0] wb32_pxclk_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component wb32_dio // Verilator lint_off UNUSED wire wb32_dio_cyc, wb32_dio_stb, wb32_dio_we; wire [11:0] wb32_dio_addr; wire [31:0] wb32_dio_data; wire [3:0] wb32_dio_sel; wire wb32_dio_stall, wb32_dio_ack, wb32_dio_err; wire [31:0] wb32_dio_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component hdmi // Verilator lint_off UNUSED wire wb32_hdmi_cyc, wb32_hdmi_stb, wb32_hdmi_we; wire [11:0] wb32_hdmi_addr; wire [31:0] wb32_hdmi_data; wire [3:0] wb32_hdmi_sel; wire wb32_hdmi_stall, wb32_hdmi_ack, wb32_hdmi_err; wire [31:0] wb32_hdmi_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wb32, component mdio // Verilator lint_off UNUSED wire wb32_mdio_cyc, wb32_mdio_stb, wb32_mdio_we; wire [11:0] wb32_mdio_addr; wire [31:0] wb32_mdio_data; wire [3:0] wb32_mdio_sel; wire wb32_mdio_stall, wb32_mdio_ack, wb32_mdio_err; wire [31:0] wb32_mdio_idata; // Verilator lint_on UNUSED // }}} // Bus wbu // {{{ // Wishbone definitions for bus wbu, component wbu // Verilator lint_off UNUSED wire wbu_cyc, wbu_stb, wbu_we; wire [29:0] wbu_addr; wire [31:0] wbu_data; wire [3:0] wbu_sel; wire wbu_stall, wbu_ack, wbu_err; wire [31:0] wbu_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbu, component wbu_arbiter // Verilator lint_off UNUSED wire wbu_wbu_arbiter_cyc, wbu_wbu_arbiter_stb, wbu_wbu_arbiter_we; wire [29:0] wbu_wbu_arbiter_addr; wire [31:0] wbu_wbu_arbiter_data; wire [3:0] wbu_wbu_arbiter_sel; wire wbu_wbu_arbiter_stall, wbu_wbu_arbiter_ack, wbu_wbu_arbiter_err; wire [31:0] wbu_wbu_arbiter_idata; // Verilator lint_on UNUSED // Wishbone definitions for bus wbu, component zip // Verilator lint_off UNUSED wire wbu_zip_cyc, wbu_zip_stb, wbu_zip_we; wire [29:0] wbu_zip_addr; wire [31:0] wbu_zip_data; wire [3:0] wbu_zip_sel; wire wbu_zip_stall, wbu_zip_ack, wbu_zip_err; wire [31:0] wbu_zip_idata; // Verilator lint_on UNUSED // }}} // }}} //////////////////////////////////////////////////////////////////////// // // Peripheral address decoding, bus handling // {{{ // // BUS-LOGIC for wbwide // {{{ // // No class SINGLE peripherals on the "wbwide" bus // // // No class DOUBLE peripherals on the "wbwide" bus // // info: @ERROR.WIRE for crossflash matches the buses error name, wbwide_crossflash_err // info: @ERROR.WIRE for crossbus matches the buses error name, wbwide_crossbus_err assign wbwide_bkram_err= 1'b0; assign wbwide_ddr3_err= 1'b0; // // Connect the wbwide bus components together using the wbxbar() // // wbxbar #( .NM(8), .NS(4), .AW(27), .DW(128), .SLAVE_ADDR({ // Address width = 27 // Address LSBs = 4 { 27'h4000000 }, // ddr3: 0x40000000 { 27'h1000000 }, // bkram: 0x10000000 { 27'h0800000 }, // crossbus: 0x08000000 { 27'h0000000 } // crossflash: 0x00000000 }), .SLAVE_MASK({ // Address width = 27 // Address LSBs = 4 { 27'h4000000 }, // ddr3 { 27'h7800000 }, // bkram { 27'h7800000 }, // crossbus { 27'h7800000 } // crossflash }), .OPT_DBLBUFFER(1'b1)) wbwide_xbar( .i_clk(i_clk), .i_reset(i_reset), .i_mcyc({ wbwide_zip_cyc, wbwide_wbu_arbiter_cyc, wbwide_oledm_cyc, wbwide_sdio_cyc, wbwide_i2cdma_cyc, wbwide_hdmi_cyc, wbwide_edidm_cyc, wbwide_i2cm_cyc }), .i_mstb({ wbwide_zip_stb, wbwide_wbu_arbiter_stb, wbwide_oledm_stb, wbwide_sdio_stb, wbwide_i2cdma_stb, wbwide_hdmi_stb, wbwide_edidm_stb, wbwide_i2cm_stb }), .i_mwe({ wbwide_zip_we, wbwide_wbu_arbiter_we, wbwide_oledm_we, wbwide_sdio_we, wbwide_i2cdma_we, wbwide_hdmi_we, wbwide_edidm_we, wbwide_i2cm_we }), .i_maddr({ wbwide_zip_addr, wbwide_wbu_arbiter_addr, wbwide_oledm_addr, wbwide_sdio_addr, wbwide_i2cdma_addr, wbwide_hdmi_addr, wbwide_edidm_addr, wbwide_i2cm_addr }), .i_mdata({ wbwide_zip_data, wbwide_wbu_arbiter_data, wbwide_oledm_data, wbwide_sdio_data, wbwide_i2cdma_data, wbwide_hdmi_data, wbwide_edidm_data, wbwide_i2cm_data }), .i_msel({ wbwide_zip_sel, wbwide_wbu_arbiter_sel, wbwide_oledm_sel, wbwide_sdio_sel, wbwide_i2cdma_sel, wbwide_hdmi_sel, wbwide_edidm_sel, wbwide_i2cm_sel }), .o_mstall({ wbwide_zip_stall, wbwide_wbu_arbiter_stall, wbwide_oledm_stall, wbwide_sdio_stall, wbwide_i2cdma_stall, wbwide_hdmi_stall, wbwide_edidm_stall, wbwide_i2cm_stall }), .o_mack({ wbwide_zip_ack, wbwide_wbu_arbiter_ack, wbwide_oledm_ack, wbwide_sdio_ack, wbwide_i2cdma_ack, wbwide_hdmi_ack, wbwide_edidm_ack, wbwide_i2cm_ack }), .o_mdata({ wbwide_zip_idata, wbwide_wbu_arbiter_idata, wbwide_oledm_idata, wbwide_sdio_idata, wbwide_i2cdma_idata, wbwide_hdmi_idata, wbwide_edidm_idata, wbwide_i2cm_idata }), .o_merr({ wbwide_zip_err, wbwide_wbu_arbiter_err, wbwide_oledm_err, wbwide_sdio_err, wbwide_i2cdma_err, wbwide_hdmi_err, wbwide_edidm_err, wbwide_i2cm_err }), // Slave connections .o_scyc({ wbwide_ddr3_cyc, wbwide_bkram_cyc, wbwide_crossbus_cyc, wbwide_crossflash_cyc }), .o_sstb({ wbwide_ddr3_stb, wbwide_bkram_stb, wbwide_crossbus_stb, wbwide_crossflash_stb }), .o_swe({ wbwide_ddr3_we, wbwide_bkram_we, wbwide_crossbus_we, wbwide_crossflash_we }), .o_saddr({ wbwide_ddr3_addr, wbwide_bkram_addr, wbwide_crossbus_addr, wbwide_crossflash_addr }), .o_sdata({ wbwide_ddr3_data, wbwide_bkram_data, wbwide_crossbus_data, wbwide_crossflash_data }), .o_ssel({ wbwide_ddr3_sel, wbwide_bkram_sel, wbwide_crossbus_sel, wbwide_crossflash_sel }), .i_sstall({ wbwide_ddr3_stall, wbwide_bkram_stall, wbwide_crossbus_stall, wbwide_crossflash_stall }), .i_sack({ wbwide_ddr3_ack, wbwide_bkram_ack, wbwide_crossbus_ack, wbwide_crossflash_ack }), .i_sdata({ wbwide_ddr3_idata, wbwide_bkram_idata, wbwide_crossbus_idata, wbwide_crossflash_idata }), .i_serr({ wbwide_ddr3_err, wbwide_bkram_err, wbwide_crossbus_err, wbwide_crossflash_err }) ); // End of bus logic for wbwide // }}} // // BUS-LOGIC for wbflash // {{{ // // No class SINGLE peripherals on the "wbflash" bus // // // No class DOUBLE peripherals on the "wbflash" bus // assign wbflash_sdio_err= 1'b0; assign wbflash_flash_err= 1'b0; // // Connect the wbflash bus components together using the wbxbar() // // wbxbar #( .NM(1), .NS(2), .AW(23), .DW(32), .SLAVE_ADDR({ // Address width = 23 // Address LSBs = 2 { 23'h400000 }, // flash: 0x1000000 { 23'h200000 } // sdio: 0x0800000 }), .SLAVE_MASK({ // Address width = 23 // Address LSBs = 2 { 23'h400000 }, // flash { 23'h600000 } // sdio }), .OPT_DBLBUFFER(1'b1)) wbflash_xbar( .i_clk(i_clk), .i_reset(i_reset), .i_mcyc({ wbflash_crossflash_cyc }), .i_mstb({ wbflash_crossflash_stb }), .i_mwe({ wbflash_crossflash_we }), .i_maddr({ wbflash_crossflash_addr }), .i_mdata({ wbflash_crossflash_data }), .i_msel({ wbflash_crossflash_sel }), .o_mstall({ wbflash_crossflash_stall }), .o_mack({ wbflash_crossflash_ack }), .o_mdata({ wbflash_crossflash_idata }), .o_merr({ wbflash_crossflash_err }), // Slave connections .o_scyc({ wbflash_flash_cyc, wbflash_sdio_cyc }), .o_sstb({ wbflash_flash_stb, wbflash_sdio_stb }), .o_swe({ wbflash_flash_we, wbflash_sdio_we }), .o_saddr({ wbflash_flash_addr, wbflash_sdio_addr }), .o_sdata({ wbflash_flash_data, wbflash_sdio_data }), .o_ssel({ wbflash_flash_sel, wbflash_sdio_sel }), .i_sstall({ wbflash_flash_stall, wbflash_sdio_stall }), .i_sack({ wbflash_flash_ack, wbflash_sdio_ack }), .i_sdata({ wbflash_flash_idata, wbflash_sdio_idata }), .i_serr({ wbflash_flash_err, wbflash_sdio_err }) ); // End of bus logic for wbflash // }}} // // BUS-LOGIC for wb32 // {{{ // // wb32 Bus logic to handle SINGLE slaves // reg r_wb32_sio_ack; reg [31:0] r_wb32_sio_data; assign wb32_sio_stall = 1'b0; initial r_wb32_sio_ack = 1'b0; always @(posedge i_clk) r_wb32_sio_ack <= (wb32_sio_stb); assign wb32_sio_ack = r_wb32_sio_ack; always @(posedge i_clk) casez( wb32_sio_addr[3:0] ) 4'h0: r_wb32_sio_data <= wb32_adcclk_idata; 4'h1: r_wb32_sio_data <= wb32_buildtime_idata; 4'h2: r_wb32_sio_data <= wb32_buserr_idata; 4'h3: r_wb32_sio_data <= wb32_buspic_idata; 4'h4: r_wb32_sio_data <= wb32_gpio_idata; 4'h5: r_wb32_sio_data <= wb32_pwrcount_idata; 4'h6: r_wb32_sio_data <= wb32_rtcdate_idata; 4'h7: r_wb32_sio_data <= wb32_rxeth0ck_idata; 4'h8: r_wb32_sio_data <= wb32_spio_idata; 4'h9: r_wb32_sio_data <= wb32_subseconds_idata; 4'ha: r_wb32_sio_data <= wb32_txclk_idata; 4'hb: r_wb32_sio_data <= wb32_version_idata; default: r_wb32_sio_data <= wb32_version_idata; endcase assign wb32_sio_idata = r_wb32_sio_data; // // Now to translate this logic to the various SIO slaves // // In this case, the SIO bus has the prefix wb32_sio // and all of the slaves have various wires beginning // with their own respective bus prefixes. // Our goal here is to make certain that all of // the slave bus inputs match the SIO bus wires assign wb32_adcclk_cyc = wb32_sio_cyc; assign wb32_adcclk_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h0); // 0x000 assign wb32_adcclk_we = wb32_sio_we; assign wb32_adcclk_data= wb32_sio_data; assign wb32_adcclk_sel = wb32_sio_sel; assign wb32_buildtime_cyc = wb32_sio_cyc; assign wb32_buildtime_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h1); // 0x004 assign wb32_buildtime_we = wb32_sio_we; assign wb32_buildtime_data= wb32_sio_data; assign wb32_buildtime_sel = wb32_sio_sel; assign wb32_buserr_cyc = wb32_sio_cyc; assign wb32_buserr_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h2); // 0x008 assign wb32_buserr_we = wb32_sio_we; assign wb32_buserr_data= wb32_sio_data; assign wb32_buserr_sel = wb32_sio_sel; assign wb32_buspic_cyc = wb32_sio_cyc; assign wb32_buspic_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h3); // 0x00c assign wb32_buspic_we = wb32_sio_we; assign wb32_buspic_data= wb32_sio_data; assign wb32_buspic_sel = wb32_sio_sel; assign wb32_gpio_cyc = wb32_sio_cyc; assign wb32_gpio_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h4); // 0x010 assign wb32_gpio_we = wb32_sio_we; assign wb32_gpio_data= wb32_sio_data; assign wb32_gpio_sel = wb32_sio_sel; assign wb32_pwrcount_cyc = wb32_sio_cyc; assign wb32_pwrcount_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h5); // 0x014 assign wb32_pwrcount_we = wb32_sio_we; assign wb32_pwrcount_data= wb32_sio_data; assign wb32_pwrcount_sel = wb32_sio_sel; assign wb32_rtcdate_cyc = wb32_sio_cyc; assign wb32_rtcdate_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h6); // 0x018 assign wb32_rtcdate_we = wb32_sio_we; assign wb32_rtcdate_data= wb32_sio_data; assign wb32_rtcdate_sel = wb32_sio_sel; assign wb32_rxeth0ck_cyc = wb32_sio_cyc; assign wb32_rxeth0ck_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h7); // 0x01c assign wb32_rxeth0ck_we = wb32_sio_we; assign wb32_rxeth0ck_data= wb32_sio_data; assign wb32_rxeth0ck_sel = wb32_sio_sel; assign wb32_spio_cyc = wb32_sio_cyc; assign wb32_spio_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h8); // 0x020 assign wb32_spio_we = wb32_sio_we; assign wb32_spio_data= wb32_sio_data; assign wb32_spio_sel = wb32_sio_sel; assign wb32_subseconds_cyc = wb32_sio_cyc; assign wb32_subseconds_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'h9); // 0x024 assign wb32_subseconds_we = wb32_sio_we; assign wb32_subseconds_data= wb32_sio_data; assign wb32_subseconds_sel = wb32_sio_sel; assign wb32_txclk_cyc = wb32_sio_cyc; assign wb32_txclk_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'ha); // 0x028 assign wb32_txclk_we = wb32_sio_we; assign wb32_txclk_data= wb32_sio_data; assign wb32_txclk_sel = wb32_sio_sel; assign wb32_version_cyc = wb32_sio_cyc; assign wb32_version_stb = wb32_sio_stb && (wb32_sio_addr[ 3: 0] == 4'hb); // 0x02c assign wb32_version_we = wb32_sio_we; assign wb32_version_data= wb32_sio_data; assign wb32_version_sel = wb32_sio_sel; // // wb32 Bus logic to handle 9 DOUBLE slaves // // reg [1:0] r_wb32_dio_ack; // # dlist = 9, nextlg(#dlist) = 4 reg [3:0] r_wb32_dio_bus_select; reg [31:0] r_wb32_dio_data; // DOUBLE peripherals are not allowed to stall. assign wb32_dio_stall = 1'b0; // DOUBLE peripherals return their acknowledgments in two // clocks--always, allowing us to collect this logic together // in a slave independent manner. Here, the acknowledgment // is treated as a two stage shift register, cleared on any // reset, or any time the cycle line drops. (Dropping the // cycle line aborts the transaction.) initial r_wb32_dio_ack = 0; always @(posedge i_clk) if (i_reset || !wb32_dio_cyc) r_wb32_dio_ack <= 0; else r_wb32_dio_ack <= { r_wb32_dio_ack[0], (wb32_dio_stb) }; assign wb32_dio_ack = r_wb32_dio_ack[1]; // Since it costs us two clocks to go through this // logic, we'll take one of those clocks here to set // a selection index, and then on the next clock we'll // use this index to select from among the vaious // possible bus return values always @(posedge i_clk) casez(wb32_dio_addr[6:2]) 5'b0_0000: r_wb32_dio_bus_select <= 4'd0; 5'b0_0001: r_wb32_dio_bus_select <= 4'd1; 5'b0_0010: r_wb32_dio_bus_select <= 4'd2; 5'b0_0011: r_wb32_dio_bus_select <= 4'd3; 5'b0_0100: r_wb32_dio_bus_select <= 4'd4; 5'b0_0101: r_wb32_dio_bus_select <= 4'd5; 5'b0_011?: r_wb32_dio_bus_select <= 4'd6; 5'b0_10??: r_wb32_dio_bus_select <= 4'd7; 5'b1_????: r_wb32_dio_bus_select <= 4'd8; default: r_wb32_dio_bus_select <= 0; endcase always @(posedge i_clk) casez(r_wb32_dio_bus_select) 4'd0: r_wb32_dio_data <= wb32_edids_idata; 4'd1: r_wb32_dio_data <= wb32_gck_idata; 4'd2: r_wb32_dio_data <= wb32_i2cs_idata; 4'd3: r_wb32_dio_data <= wb32_i2cdma_idata; 4'd4: r_wb32_dio_data <= wb32_oled_idata; 4'd5: r_wb32_dio_data <= wb32_rtc_idata; 4'd6: r_wb32_dio_data <= wb32_gtb_idata; 4'd7: r_wb32_dio_data <= wb32_sio_idata; 4'd8: r_wb32_dio_data <= wb32_edidslv_idata; default: r_wb32_dio_data <= wb32_edidslv_idata; endcase assign wb32_dio_idata = r_wb32_dio_data; assign wb32_edids_cyc = wb32_dio_cyc; assign wb32_edids_stb = wb32_dio_stb && ((wb32_dio_addr[ 6: 2] & 5'h1f) == 5'h00); // 0x000 - 0x00f assign wb32_edids_we = wb32_dio_we; assign wb32_edids_addr= wb32_dio_addr; assign wb32_edids_data= wb32_dio_data; assign wb32_edids_sel = wb32_dio_sel; assign wb32_gck_cyc = wb32_dio_cyc; assign wb32_gck_stb = wb32_dio_stb && ((wb32_dio_addr[ 6: 2] & 5'h1f) == 5'h01); // 0x010 - 0x01f assign wb32_gck_we = wb32_dio_we; assign wb32_gck_addr= wb32_dio_addr; assign wb32_gck_data= wb32_dio_data; assign wb32_gck_sel = wb32_dio_sel; assign wb32_i2cs_cyc = wb32_dio_cyc; assign wb32_i2cs_stb = wb32_dio_stb && ((wb32_dio_addr[ 6: 2] & 5'h1f) == 5'h02); // 0x020 - 0x02f assign wb32_i2cs_we = wb32_dio_we; assign wb32_i2cs_addr= wb32_dio_addr; assign wb32_i2cs_data= wb32_dio_data; assign wb32_i2cs_sel = wb32_dio_sel; assign wb32_i2cdma_cyc = wb32_dio_cyc; assign wb32_i2cdma_stb = wb32_dio_stb && ((wb32_dio_addr[ 6: 2] & 5'h1f) == 5'h03); // 0x030 - 0x03f assign wb32_i2cdma_we = wb32_dio_we; assign wb32_i2cdma_addr= wb32_dio_addr; assign wb32_i2cdma_data= wb32_dio_data; assign wb32_i2cdma_sel = wb32_dio_sel; assign wb32_oled_cyc = wb32_dio_cyc; assign wb32_oled_stb = wb32_dio_stb && ((wb32_dio_addr[ 6: 2] & 5'h1f) == 5'h04); // 0x040 - 0x04f assign wb32_oled_we = wb32_dio_we; assign wb32_oled_addr= wb32_dio_addr; assign wb32_oled_data= wb32_dio_data; assign wb32_oled_sel = wb32_dio_sel; assign wb32_rtc_cyc = wb32_dio_cyc; assign wb32_rtc_stb = wb32_dio_stb && ((wb32_dio_addr[ 6: 2] & 5'h1f) == 5'h05); // 0x050 - 0x05f assign wb32_rtc_we = wb32_dio_we; assign wb32_rtc_addr= wb32_dio_addr; assign wb32_rtc_data= wb32_dio_data; assign wb32_rtc_sel = wb32_dio_sel; assign wb32_gtb_cyc = wb32_dio_cyc; assign wb32_gtb_stb = wb32_dio_stb && ((wb32_dio_addr[ 6: 2] & 5'h1e) == 5'h06); // 0x060 - 0x07f assign wb32_gtb_we = wb32_dio_we; assign wb32_gtb_addr= wb32_dio_addr; assign wb32_gtb_data= wb32_dio_data; assign wb32_gtb_sel = wb32_dio_sel; assign wb32_sio_cyc = wb32_dio_cyc; assign wb32_sio_stb = wb32_dio_stb && ((wb32_dio_addr[ 6: 2] & 5'h1c) == 5'h08); // 0x080 - 0x0bf assign wb32_sio_we = wb32_dio_we; assign wb32_sio_addr= wb32_dio_addr; assign wb32_sio_data= wb32_dio_data; assign wb32_sio_sel = wb32_dio_sel; assign wb32_edidslv_cyc = wb32_dio_cyc; assign wb32_edidslv_stb = wb32_dio_stb && ((wb32_dio_addr[ 6: 2] & 5'h10) == 5'h10); // 0x100 - 0x1ff assign wb32_edidslv_we = wb32_dio_we; assign wb32_edidslv_addr= wb32_dio_addr; assign wb32_edidslv_data= wb32_dio_data; assign wb32_edidslv_sel = wb32_dio_sel; assign wb32_flashcfg_err= 1'b0; assign wb32_edidslvscope_err= 1'b0; assign wb32_pmic_err= 1'b0; assign wb32_gpsu_err= 1'b0; assign wb32_icape_err= 1'b0; assign wb32_net_err= 1'b0; assign wb32_ddr3_phy_err= 1'b0; assign wb32_pxclk_err= 1'b0; assign wb32_dio_err= 1'b0; assign wb32_hdmi_err= 1'b0; assign wb32_mdio_err= 1'b0; // // Connect the wb32 bus components together using the wbxbar() // // wbxbar #( .NM(1), .NS(11), .AW(12), .DW(32), .SLAVE_ADDR({ // Address width = 12 // Address LSBs = 2 { 12'hc00 }, // mdio: 0x3000 { 12'h800 }, // hdmi: 0x2000 { 12'h500 }, // wb32_dio: 0x1400 { 12'h480 }, // pxclk: 0x1200 { 12'h400 }, // ddr3_phy: 0x1000 { 12'h380 }, // net: 0x0e00 { 12'h300 }, // icape: 0x0c00 { 12'h280 }, // gpsu: 0x0a00 { 12'h200 }, // pmic: 0x0800 { 12'h180 }, // edidslvscope: 0x0600 { 12'h100 } // flashcfg: 0x0400 }), .SLAVE_MASK({ // Address width = 12 // Address LSBs = 2 { 12'hc00 }, // mdio { 12'hc00 }, // hdmi { 12'hf80 }, // wb32_dio { 12'hf80 }, // pxclk { 12'hf80 }, // ddr3_phy { 12'hf80 }, // net { 12'hf80 }, // icape { 12'hf80 }, // gpsu { 12'hf80 }, // pmic { 12'hf80 }, // edidslvscope { 12'hf80 } // flashcfg }), .OPT_DBLBUFFER(1'b1)) wb32_xbar( .i_clk(i_clk), .i_reset(i_reset), .i_mcyc({ wb32_crossbus_cyc }), .i_mstb({ wb32_crossbus_stb }), .i_mwe({ wb32_crossbus_we }), .i_maddr({ wb32_crossbus_addr }), .i_mdata({ wb32_crossbus_data }), .i_msel({ wb32_crossbus_sel }), .o_mstall({ wb32_crossbus_stall }), .o_mack({ wb32_crossbus_ack }), .o_mdata({ wb32_crossbus_idata }), .o_merr({ wb32_crossbus_err }), // Slave connections .o_scyc({ wb32_mdio_cyc, wb32_hdmi_cyc, wb32_dio_cyc, wb32_pxclk_cyc, wb32_ddr3_phy_cyc, wb32_net_cyc, wb32_icape_cyc, wb32_gpsu_cyc, wb32_pmic_cyc, wb32_edidslvscope_cyc, wb32_flashcfg_cyc }), .o_sstb({ wb32_mdio_stb, wb32_hdmi_stb, wb32_dio_stb, wb32_pxclk_stb, wb32_ddr3_phy_stb, wb32_net_stb, wb32_icape_stb, wb32_gpsu_stb, wb32_pmic_stb, wb32_edidslvscope_stb, wb32_flashcfg_stb }), .o_swe({ wb32_mdio_we, wb32_hdmi_we, wb32_dio_we, wb32_pxclk_we, wb32_ddr3_phy_we, wb32_net_we, wb32_icape_we, wb32_gpsu_we, wb32_pmic_we, wb32_edidslvscope_we, wb32_flashcfg_we }), .o_saddr({ wb32_mdio_addr, wb32_hdmi_addr, wb32_dio_addr, wb32_pxclk_addr, wb32_ddr3_phy_addr, wb32_net_addr, wb32_icape_addr, wb32_gpsu_addr, wb32_pmic_addr, wb32_edidslvscope_addr, wb32_flashcfg_addr }), .o_sdata({ wb32_mdio_data, wb32_hdmi_data, wb32_dio_data, wb32_pxclk_data, wb32_ddr3_phy_data, wb32_net_data, wb32_icape_data, wb32_gpsu_data, wb32_pmic_data, wb32_edidslvscope_data, wb32_flashcfg_data }), .o_ssel({ wb32_mdio_sel, wb32_hdmi_sel, wb32_dio_sel, wb32_pxclk_sel, wb32_ddr3_phy_sel, wb32_net_sel, wb32_icape_sel, wb32_gpsu_sel, wb32_pmic_sel, wb32_edidslvscope_sel, wb32_flashcfg_sel }), .i_sstall({ wb32_mdio_stall, wb32_hdmi_stall, wb32_dio_stall, wb32_pxclk_stall, wb32_ddr3_phy_stall, wb32_net_stall, wb32_icape_stall, wb32_gpsu_stall, wb32_pmic_stall, wb32_edidslvscope_stall, wb32_flashcfg_stall }), .i_sack({ wb32_mdio_ack, wb32_hdmi_ack, wb32_dio_ack, wb32_pxclk_ack, wb32_ddr3_phy_ack, wb32_net_ack, wb32_icape_ack, wb32_gpsu_ack, wb32_pmic_ack, wb32_edidslvscope_ack, wb32_flashcfg_ack }), .i_sdata({ wb32_mdio_idata, wb32_hdmi_idata, wb32_dio_idata, wb32_pxclk_idata, wb32_ddr3_phy_idata, wb32_net_idata, wb32_icape_idata, wb32_gpsu_idata, wb32_pmic_idata, wb32_edidslvscope_idata, wb32_flashcfg_idata }), .i_serr({ wb32_mdio_err, wb32_hdmi_err, wb32_dio_err, wb32_pxclk_err, wb32_ddr3_phy_err, wb32_net_err, wb32_icape_err, wb32_gpsu_err, wb32_pmic_err, wb32_edidslvscope_err, wb32_flashcfg_err }) ); // End of bus logic for wb32 // }}} // // BUS-LOGIC for wbu // {{{ // // No class SINGLE peripherals on the "wbu" bus // // // No class DOUBLE peripherals on the "wbu" bus // // info: @ERROR.WIRE for wbu_arbiter matches the buses error name, wbu_wbu_arbiter_err assign wbu_zip_err= 1'b0; // // Connect the wbu bus components together using the wbxbar() // // wbxbar #( .NM(1), .NS(2), .AW(30), .DW(32), .SLAVE_ADDR({ // Address width = 30 // Address LSBs = 2 { 30'h20000000 }, // zip: 0x80000000 { 30'h00000000 } // wbu_arbiter: 0x00000000 }), .SLAVE_MASK({ // Address width = 30 // Address LSBs = 2 { 30'h38000000 }, // zip { 30'h20000000 } // wbu_arbiter }), .OPT_DBLBUFFER(1'b1)) wbu_xbar( .i_clk(i_clk), .i_reset(i_reset), .i_mcyc({ wbu_cyc }), .i_mstb({ wbu_stb }), .i_mwe({ wbu_we }), .i_maddr({ wbu_addr }), .i_mdata({ wbu_data }), .i_msel({ wbu_sel }), .o_mstall({ wbu_stall }), .o_mack({ wbu_ack }), .o_mdata({ wbu_idata }), .o_merr({ wbu_err }), // Slave connections .o_scyc({ wbu_zip_cyc, wbu_wbu_arbiter_cyc }), .o_sstb({ wbu_zip_stb, wbu_wbu_arbiter_stb }), .o_swe({ wbu_zip_we, wbu_wbu_arbiter_we }), .o_saddr({ wbu_zip_addr, wbu_wbu_arbiter_addr }), .o_sdata({ wbu_zip_data, wbu_wbu_arbiter_data }), .o_ssel({ wbu_zip_sel, wbu_wbu_arbiter_sel }), .i_sstall({ wbu_zip_stall, wbu_wbu_arbiter_stall }), .i_sack({ wbu_zip_ack, wbu_wbu_arbiter_ack }), .i_sdata({ wbu_zip_idata, wbu_wbu_arbiter_idata }), .i_serr({ wbu_zip_err, wbu_wbu_arbiter_err }) ); // End of bus logic for wbu // }}} // }}} //////////////////////////////////////////////////////////////////////// // // Declare the interrupt busses // {{{ // Interrupt busses are defined by anything with a @PIC tag. // The @PIC.BUS tag defines the name of the wire bus below, // while the @PIC.MAX tag determines the size of the bus width. // // For your peripheral to be assigned to this bus, it must have an // @INT.NAME.WIRE= tag to define the wire name of the interrupt line, // and an @INT.NAME.PIC= tag matching the @PIC.BUS tag of the bus // your interrupt will be assigned to. If an @INT.NAME.ID tag also // exists, then your interrupt will be assigned to the position given // by the ID# in that tag. // assign sys_int_vector = { pmic_int, oled_int, gck_pps, sdio_int, gpio_int, hdmi_int, edid_int, i2c_int, w_bus_int, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0 }; assign alt_int_vector = { 1'b0, rtc_int, edidslvscope_int, gpsutxf_int, gpsurxf_int, gpsutx_int, gpsurx_int, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0 }; assign bus_int_vector = { 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, spio_int }; // }}} //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // // @MAIN.INSERT and @MAIN.ALT // {{{ //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // // // Now we turn to defining all of the parts and pieces of what // each of the various peripherals does, and what logic it needs. // // This information comes from the @MAIN.INSERT and @MAIN.ALT tags. // If an @ACCESS tag is available, an ifdef is created to handle // having the access and not. If the @ACCESS tag is `defined above // then the @MAIN.INSERT code is executed. If not, the @MAIN.ALT // code is exeucted, together with any other cleanup settings that // might need to take place--such as returning zeros to the bus, // or making sure all of the various interrupt wires are set to // zero if the component is not included. // `ifdef FLASH_ACCESS // {{{ //////////////////////////////////////////////////////////////////////// // // Flash controller // {{{ qflexpress #( // {{{ .LGFLASHSZ(24), .OPT_CLKDIV(1), .OPT_ENDIANSWAP(0), .NDUMMY(6), .RDDELAY(2), .OPT_STARTUP_FILE("spansion.hex"), `ifdef FLASHCFG_ACCESS .OPT_CFG(1'b1) `else .OPT_CFG(1'b0) `endif // }}} ) u_flash ( // {{{ .i_clk(i_clk), .i_reset(i_reset), // Primary memory reading inputs .i_wb_cyc(wbflash_flash_cyc), .i_wb_stb(wbflash_flash_stb), .i_wb_we(wbflash_flash_we), .i_wb_addr(wbflash_flash_addr[22-1:0]), .i_wb_data(wbflash_flash_data), // 32 bits wide .i_wb_sel(wbflash_flash_sel), // 32/8 bits wide .o_wb_stall(wbflash_flash_stall),.o_wb_ack(wbflash_flash_ack), .o_wb_data(wbflash_flash_idata), // Configuration bus ports .i_cfg_cyc(wb32_flashcfg_cyc), .i_cfg_stb(wb32_flashcfg_stb), .i_cfg_we(wb32_flashcfg_we), .i_cfg_data(wb32_flashcfg_data), // 32 bits wide .i_cfg_sel(wb32_flashcfg_sel), // 32/8 bits wide .o_cfg_stall(wb32_flashcfg_stall),.o_cfg_ack(wb32_flashcfg_ack), .o_cfg_data(wb32_flashcfg_idata), .o_qspi_sck(o_flash_sck), .o_qspi_cs_n(o_flash_cs_n), .o_qspi_mod(o_flash_mod), .o_qspi_dat(o_flash_dat), .i_qspi_dat(i_flash_dat), .o_dbg_trigger(flash_dbg_trigger), .o_debug(flash_debug) // }}} ); // }}} // }}} `else // FLASH_ACCESS // {{{ assign o_flash_sck = 1'b1; assign o_flash_cs_n = 1'b1; assign o_flash_mod = 2'b01; assign o_flash_dat = 4'b1111; // Verilator lint_off UNUSED wire flash_unused = &{ 1'b0, i_flash_dat }; // Verilator lint_on UNUSED // Null bus slave // {{{ // // In the case that there is no wbflash_flash peripheral // responding on the wbflash bus assign wbflash_flash_ack = 1'b0; assign wbflash_flash_err = (wbflash_flash_stb); assign wbflash_flash_stall = 0; assign wbflash_flash_idata = 0; // }}} // }}} `endif // FLASH_ACCESS `ifdef I2CCPU_ACCESS // {{{ //////////////////////////////////////////////////////////////////////// // // The I2C Controller // {{{ wbi2ccpu #( .ADDRESS_WIDTH(27), .DATA_WIDTH(128), .AXIS_ID_WIDTH(2) ) u_i2c ( // {{{ .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wb32_i2cs_cyc), .i_wb_stb(wb32_i2cs_stb), .i_wb_we(wb32_i2cs_we), .i_wb_addr(wb32_i2cs_addr[2-1:0]), .i_wb_data(wb32_i2cs_data), // 32 bits wide .i_wb_sel(wb32_i2cs_sel), // 32/8 bits wide .o_wb_stall(wb32_i2cs_stall),.o_wb_ack(wb32_i2cs_ack), .o_wb_data(wb32_i2cs_idata), .o_pf_cyc(wbwide_i2cm_cyc), .o_pf_stb(wbwide_i2cm_stb), .o_pf_we(wbwide_i2cm_we), .o_pf_addr(wbwide_i2cm_addr[27-1:0]), .o_pf_data(wbwide_i2cm_data), // 128 bits wide .o_pf_sel(wbwide_i2cm_sel), // 128/8 bits wide .i_pf_stall(wbwide_i2cm_stall), .i_pf_ack(wbwide_i2cm_ack), .i_pf_data(wbwide_i2cm_idata), .i_pf_err(wbwide_i2cm_err), .i_i2c_sda(i_i2c_sda), .i_i2c_scl(i_i2c_scl), .o_i2c_sda(o_i2c_sda), .o_i2c_scl(o_i2c_scl), .M_AXIS_TVALID(i2c_valid), .M_AXIS_TREADY(i2c_ready), .M_AXIS_TDATA(i2c_data), .M_AXIS_TLAST(i2c_last), .M_AXIS_TID(i2c_id), .i_sync_signal(rtc_pps), // .o_interrupt(i2c_int), .o_debug(i2c_debug) // }}} ); assign i2c_ready = (!i2c_valid) || (1'b0 || (i2c_id == 0) // NULL address || (i2c_id == 1) `ifdef I2CDMA_ACCESS || (i2c_id == 2 && i2cdma_ready) `else || (i2c_id == 2) `endif || (i2c_id > 2)); // }}} // }}} `else // I2CCPU_ACCESS // {{{ assign o_i2c_scl = 1'b1; assign o_i2c_sda = 1'b1; // Null bus master // {{{ // }}} // Null interrupt definitions // {{{ assign i2c_int = 1'b0; // i2c.INT.I2C.WIRE // }}} // }}} `endif // I2CCPU_ACCESS always @(posedge i_clk) if (wbwide_zip_err) begin r_buserr_addr <= 0; r_buserr_addr[27-1:0] <= wbwide_zip_addr[27-1:0]; end else if (wbu_err) begin r_buserr_addr <= 0; r_buserr_addr[30-1:0] <= wbu_addr[30-1:0]; end assign wb32_buserr_stall= 1'b0; assign wb32_buserr_ack = wb32_buserr_stb; assign wb32_buserr_idata = { {(30-30){1'b0}}, r_buserr_addr, 2'b00 }; `ifdef GPSTRK_ACCESS assign wb32_subseconds_idata = gps_now[31:0]; `else always @(posedge i_clk) if (wb32_subseconds_stb && wb32_subseconds_we) r_subseconds_data <= wb32_subseconds_data; else r_subseconds_data <= r_subseconds_data + { 16'h0, RTC_CLKSTEP[31:16] }; assign wb32_subseconds_idata = r_subseconds_data; `endif `ifdef ADCCLK // {{{ clkcounter #( .CLOCKFREQ_HZ(0) // We'll count PPS externally ) clkadcclkctr( .i_sys_clk(i_clk), .i_tst_clk(i_clk_200mhz), .i_sys_pps(rtc_pps), .o_sys_counts(wb32_adcclk_idata) ); initial r_adcclk_ack = 0; always @(posedge i_clk) r_adcclk_ack <= !i_reset && wb32_adcclk_stb; assign wb32_adcclk_ack = r_adcclk_ack; assign wb32_adcclk_stall = 1'b0; // }}} `else // ADCCLK // {{{ // }}} `endif // ADCCLK `ifdef EXBUS_MASTER // {{{ //////////////////////////////////////////////////////////////////////// // // EXBUS: USB-UART driven bus master and console // {{{ // The Host USB interface, to be used by the WB-UART bus rxuartlite #( // {{{ .TIMER_BITS(DBGBUSBITS), .CLOCKS_PER_BAUD(BUSUART[DBGBUSBITS-1:0]) // }}} ) rcv( // {{{ .i_clk( i_clk), .i_uart_rx(i_wbu_uart_rx), .o_wr( wbu_rx_stb), .o_data( wbu_rx_data) // }}} ); txuartlite #( // {{{ .TIMING_BITS(DBGBUSBITS[4:0]), .CLOCKS_PER_BAUD(BUSUART[DBGBUSBITS-1:0]) // }}} ) txv( // {{{ .i_clk( i_clk), .i_wr( wbu_tx_stb), .i_data( wbu_tx_data), .o_uart_tx(o_wbu_uart_tx), .o_busy( wbu_tx_busy) // }}} ); `ifndef BUSPIC_ACCESS wire w_bus_int; assign w_bus_int = 1'b0; `endif // Verilator lint_off UNUSED wire [29:0] wbu_tmp_addr; // Verilator lint_on UNUSED exbuswb #( // {{{ // .LGWATCHDOG(DBGBUSWATCHDOG) .ADDRESS_WIDTH(30) // }}} ) u_exbus( // {{{ .i_clk(i_clk), .i_reset(i_reset), .o_reset(ex_reset), .i_rx_stb(wbu_rx_stb), .i_rx_byte(wbu_rx_data), .o_tx_stb(wbu_tx_stb), .o_tx_byte(wbu_tx_data), .i_tx_busy(wbu_tx_busy), // .i_gpio(2'b00), .o_gpio(ex_gpio), // .i_console_stb(w_console_tx_stb), .i_console_byte(w_console_tx_data), .o_console_busy(w_console_busy), .o_console_stb(w_console_rx_stb), .o_console_byte(w_console_rx_data), // .o_wb_cyc(wbu_cyc), .o_wb_stb(wbu_stb), .o_wb_we(wbu_we), .o_wb_addr(wbu_addr), .o_wb_data(wbu_data), .o_wb_sel(wbu_sel), .i_wb_stall(wbu_stall), .i_wb_ack(wbu_ack), .i_wb_data(wbu_idata), .i_wb_err(wbu_err), .i_interrupt(w_bus_int) // }}} ); // }}} // }}} `else // EXBUS_MASTER // {{{ // Null bus master // {{{ // }}} // }}} `endif // EXBUS_MASTER `ifdef FLASHCFG_ACCESS // {{{ // The Flash control interface is defined by the flash instantiation // hence we don't need to do anything to define it here. // }}} `else // FLASHCFG_ACCESS // {{{ // Null bus slave // {{{ // // In the case that there is no wb32_flashcfg peripheral // responding on the wb32 bus assign wb32_flashcfg_ack = 1'b0; assign wb32_flashcfg_err = (wb32_flashcfg_stb); assign wb32_flashcfg_stall = 0; assign wb32_flashcfg_idata = 0; // }}} // }}} `endif // FLASHCFG_ACCESS `ifdef EDID_ACCESS // {{{ //////////////////////////////////////////////////////////////////////// // // The EDID I2C Controller // {{{ wbi2ccpu #( .ADDRESS_WIDTH(27), .DATA_WIDTH(128), .AXIS_ID_WIDTH(2) ) u_edid ( // {{{ .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wb32_edids_cyc), .i_wb_stb(wb32_edids_stb), .i_wb_we(wb32_edids_we), .i_wb_addr(wb32_edids_addr[2-1:0]), .i_wb_data(wb32_edids_data), // 32 bits wide .i_wb_sel(wb32_edids_sel), // 32/8 bits wide .o_wb_stall(wb32_edids_stall),.o_wb_ack(wb32_edids_ack), .o_wb_data(wb32_edids_idata), .o_pf_cyc(wbwide_edidm_cyc), .o_pf_stb(wbwide_edidm_stb), .o_pf_we(wbwide_edidm_we), .o_pf_addr(wbwide_edidm_addr[27-1:0]), .o_pf_data(wbwide_edidm_data), // 128 bits wide .o_pf_sel(wbwide_edidm_sel), // 128/8 bits wide .i_pf_stall(wbwide_edidm_stall), .i_pf_ack(wbwide_edidm_ack), .i_pf_data(wbwide_edidm_idata), .i_pf_err(wbwide_edidm_err), .i_i2c_sda(i_edid_sda), .i_i2c_scl(i_edid_scl), .o_i2c_sda(o_edid_sda), .o_i2c_scl(o_edid_scl), .M_AXIS_TVALID(edid_valid), .M_AXIS_TREADY(edid_ready), .M_AXIS_TDATA(edid_data), .M_AXIS_TLAST(edid_last), .M_AXIS_TID(edid_id), .i_sync_signal(rtc_pps), // .o_interrupt(edid_int), .o_debug(edid_debug) // }}} ); // }}} // }}} `else // EDID_ACCESS // {{{ assign o_edid_scl = 1'b1; assign o_edid_sda = 1'b1; // Null bus master // {{{ // }}} // Null interrupt definitions // {{{ assign edid_int = 1'b0; // edid.INT.EDID.WIRE // }}} // }}} `endif // EDID_ACCESS `ifdef GPSUART_ACCESS // {{{ wbuart #( .INITIAL_SETUP(31'h000028b0) ) u_gpsu_uart( i_clk, 1'b0, wb32_gpsu_cyc, wb32_gpsu_stb, wb32_gpsu_we, wb32_gpsu_addr[2-1:0], wb32_gpsu_data, // 32 bits wide wb32_gpsu_sel, // 32/8 bits wide wb32_gpsu_stall, wb32_gpsu_ack, wb32_gpsu_idata, i_gpsu_rx, o_gpsu_tx, w_gpsu_cts_n, w_gpsu_rts_n, gpsurx_int, gpsutx_int, gpsurxf_int, gpsutxf_int ); // }}} `else // GPSUART_ACCESS // {{{ assign o_gpsu_tx = 1'b1; assign w_gpsu_rts_n = 1'b0; // Null bus slave // {{{ // // In the case that there is no wb32_gpsu peripheral // responding on the wb32 bus assign wb32_gpsu_ack = 1'b0; assign wb32_gpsu_err = (wb32_gpsu_stb); assign wb32_gpsu_stall = 0; assign wb32_gpsu_idata = 0; // }}} // Null interrupt definitions // {{{ assign gpsurxf_int = 1'b0; // gpsu.INT.GPSRXF.WIRE assign gpsutxf_int = 1'b0; // gpsu.INT.GPSTXF.WIRE assign gpsutx_int = 1'b0; // gpsu.INT.GPSTX.WIRE assign gpsurx_int = 1'b0; // gpsu.INT.GPSRX.WIRE // }}} // }}} `endif // GPSUART_ACCESS `ifdef VIDPIPE_ACCESS // {{{ //////////////////////////////////////////////////////////////////////// // // HDMI Video processing pipeline // {{{ `ifdef VERILATOR assign i_hdmiclk = i_pixclk; `endif vidpipe #( .AW(27), .DW(128) ) u_hdmi ( .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wb32_hdmi_cyc), .i_wb_stb(wb32_hdmi_stb), .i_wb_we(wb32_hdmi_we), .i_wb_addr(wb32_hdmi_addr[10-1:0]), .i_wb_data(wb32_hdmi_data), // 32 bits wide .i_wb_sel(wb32_hdmi_sel), // 32/8 bits wide .o_wb_stall(wb32_hdmi_stall),.o_wb_ack(wb32_hdmi_ack), .o_wb_data(wb32_hdmi_idata), .i_hdmiclk(i_hdmiclk), .i_altclk(i_pixclk), .i_pixclk(i_pixclk), .i_hdmi_red(i_hdmi_red), .i_hdmi_grn(i_hdmi_grn), .i_hdmi_blu(i_hdmi_blu), .o_dma_cyc(wbwide_hdmi_cyc), .o_dma_stb(wbwide_hdmi_stb), .o_dma_we(wbwide_hdmi_we), .o_dma_addr(wbwide_hdmi_addr[27-1:0]), .o_dma_data(wbwide_hdmi_data), // 128 bits wide .o_dma_sel(wbwide_hdmi_sel), // 128/8 bits wide .i_dma_stall(wbwide_hdmi_stall), .i_dma_ack(wbwide_hdmi_ack), .i_dma_data(wbwide_hdmi_idata), .i_dma_err(wbwide_hdmi_err), .o_hdmi_red(o_hdmi_red), .o_hdmi_grn(o_hdmi_grn), .o_hdmi_blu(o_hdmi_blu), .o_pix_reset_n(o_pix_reset_n), .i_pxpll_locked(i_pxpll_locked), .o_hdmirx_reset_n(o_hdmirx_reset_n), .o_pxclk_sel(o_pxclk_cksel), .o_iodelay(o_hdmi_iodelay), .i_iodelay(i_hdmi_iodelay), .o_interrupt(hdmi_int), // .o_dbg_ce(hdmidbg_ce), .o_dbg_trigger(hdmidbg_trigger), .o_pixdebug(hdmiclr_debug) ); // }}} // }}} `else // VIDPIPE_ACCESS // {{{ // Null bus master // {{{ // }}} // Null bus slave // {{{ // // In the case that there is no wb32_hdmi peripheral // responding on the wb32 bus assign wb32_hdmi_ack = 1'b0; assign wb32_hdmi_err = (wb32_hdmi_stb); assign wb32_hdmi_stall = 0; assign wb32_hdmi_idata = 0; // }}} // Null interrupt definitions // {{{ assign hdmi_int = 1'b0; // hdmi.INT.VIDFRAME.WIRE // }}} // }}} `endif // VIDPIPE_ACCESS //////////////////////////////////////////////////////////////////////// // // EDIDRX // {{{ wbi2cslave #( .AXIS_SUPPORT(1'b1), .SLAVE_ADDRESS(7'h50) ) u_edidslv ( .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wb32_edidslv_cyc), .i_wb_stb(wb32_edidslv_stb), .i_wb_we(wb32_edidslv_we), .i_wb_addr(wb32_edidslv_addr[6-1:0]), .i_wb_data(wb32_edidslv_data), // 32 bits wide .i_wb_sel(wb32_edidslv_sel), // 32/8 bits wide .o_wb_stall(wb32_edidslv_stall),.o_wb_ack(wb32_edidslv_ack), .o_wb_data(wb32_edidslv_idata), .s_valid(edid_valid), .s_ready(edid_ready), .s_data(edid_data), .s_last(edid_last), .i_i2c_scl(i_edidslv_scl), .i_i2c_sda(i_edidslv_sda), .o_i2c_scl(o_edidslv_scl), .o_i2c_sda(o_edidslv_sda), .o_dbg(edidslv_dbg) ); // }}} `ifdef EDIDSLVSCOPE_SCOPC // {{{ wbscopc #( // {{{ .LGMEM(13), .SYNCHRONOUS(1), .DEFAULT_HOLDOFF(0) // }}} ) u_edidslvscope ( // {{{ .i_data_clk(i_clk), .i_ce(1'b1), .i_trigger(edidslv_dbg[31]), .i_data(edidslv_dbg[30:0]), .i_wb_clk(i_clk), .i_wb_cyc(wb32_edidslvscope_cyc), .i_wb_stb(wb32_edidslvscope_stb), .i_wb_we(wb32_edidslvscope_we), .i_wb_addr(wb32_edidslvscope_addr[1-1:0]), .i_wb_data(wb32_edidslvscope_data), // 32 bits wide .i_wb_sel(wb32_edidslvscope_sel), // 32/8 bits wide .o_wb_stall(wb32_edidslvscope_stall),.o_wb_ack(wb32_edidslvscope_ack), .o_wb_data(wb32_edidslvscope_idata), .o_interrupt(edidslvscope_int) // }}} ); // }}} `else // EDIDSLVSCOPE_SCOPC // {{{ // Null bus slave // {{{ // // In the case that there is no wb32_edidslvscope peripheral // responding on the wb32 bus assign wb32_edidslvscope_ack = 1'b0; assign wb32_edidslvscope_err = (wb32_edidslvscope_stb); assign wb32_edidslvscope_stall = 0; assign wb32_edidslvscope_idata = 0; // }}} // Null interrupt definitions // {{{ assign edidslvscope_int = 1'b0; // edidslvscope.INT.EDIDSLVSCOPE.WIRE // }}} // }}} `endif // EDIDSLVSCOPE_SCOPC wbdown #( // {{{ // Slave bus address width: 27 // Slave address width : 21 // Master address width : 23 .ADDRESS_WIDTH(21+$clog2(128/8)), .WIDE_DW(128), .SMALL_DW(32), .OPT_LITTLE_ENDIAN(1'b0), .OPT_LOWLOGIC(1'b0) // }}} ) u_crossflash ( // {{{ .i_clk(i_clk), .i_reset(i_reset), // Slave/incoming // {{{ .i_wcyc( wbwide_crossflash_cyc), .i_wstb( wbwide_crossflash_stb), .i_wwe( wbwide_crossflash_we), .i_waddr( wbwide_crossflash_addr[21-1:0]), .i_wdata( wbwide_crossflash_data), .i_wsel( wbwide_crossflash_sel), .o_wstall(wbwide_crossflash_stall), .o_wack( wbwide_crossflash_ack), .o_wdata( wbwide_crossflash_idata), .o_werr( wbwide_crossflash_err), // }}} // Master/down-range/outgoing // {{{ .o_scyc( wbflash_crossflash_cyc), .o_sstb( wbflash_crossflash_stb), .o_swe( wbflash_crossflash_we), .o_saddr( wbflash_crossflash_addr[23-1:0]), .o_sdata( wbflash_crossflash_data), .o_ssel( wbflash_crossflash_sel), .i_sstall(wbflash_crossflash_stall), .i_sack( wbflash_crossflash_ack), .i_sdata( wbflash_crossflash_idata), .i_serr( wbflash_crossflash_err) // }}} // }}} ); `ifdef CFG_ACCESS // {{{ //////////////////////////////////////////////////////////////////////// // // ICAPE2 driver/controller // {{{ //////////////////////////////////////////////////////////////////////// // // `ifdef VERILATOR reg r_icape_ack; initial r_icape_ack = 1'b0; always @(posedge i_clk) r_icape_ack <= wb32_icape_stb; assign wb32_icape_ack = r_icape_ack; assign wb32_icape_stall = 1'b0; assign wb32_icape_idata = 32'h00; `else wbicapetwo #( .LGDIV(ICAPE_LGDIV) ) u_icape ( // {{{ .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wb32_icape_cyc), .i_wb_stb(wb32_icape_stb), .i_wb_we(wb32_icape_we), .i_wb_addr(wb32_icape_addr[5-1:0]), .i_wb_data(wb32_icape_data), // 32 bits wide .i_wb_sel(wb32_icape_sel), // 32/8 bits wide .o_wb_stall(wb32_icape_stall),.o_wb_ack(wb32_icape_ack), .o_wb_data(wb32_icape_idata) // }}} ); `endif // }}} // }}} `else // CFG_ACCESS // {{{ // Null bus slave // {{{ // // In the case that there is no wb32_icape peripheral // responding on the wb32 bus assign wb32_icape_ack = 1'b0; assign wb32_icape_err = (wb32_icape_stb); assign wb32_icape_stall = 0; assign wb32_icape_idata = 0; // }}} // }}} `endif // CFG_ACCESS `ifdef TXCLK // {{{ clkcounter #( .CLOCKFREQ_HZ(0) // We'll count PPS externally ) clktxclkctr( .i_sys_clk(i_clk), .i_tst_clk(i_net_tx_clk), .i_sys_pps(rtc_pps), .o_sys_counts(wb32_txclk_idata) ); initial r_txclk_ack = 0; always @(posedge i_clk) r_txclk_ack <= !i_reset && wb32_txclk_stb; assign wb32_txclk_ack = r_txclk_ack; assign wb32_txclk_stall = 1'b0; // }}} `else // TXCLK // {{{ // }}} `endif // TXCLK `ifdef RXETH0CK // {{{ clkcounter #( .CLOCKFREQ_HZ(0) // We'll count PPS externally ) clkrxeth0ckctr( .i_sys_clk(i_clk), .i_tst_clk(i_eth0_rx_clk), .i_sys_pps(rtc_pps), .o_sys_counts(wb32_rxeth0ck_idata) ); initial r_rxeth0ck_ack = 0; always @(posedge i_clk) r_rxeth0ck_ack <= !i_reset && wb32_rxeth0ck_stb; assign wb32_rxeth0ck_ack = r_rxeth0ck_ack; assign wb32_rxeth0ck_stall = 1'b0; // }}} `else // RXETH0CK // {{{ // }}} `endif // RXETH0CK initial rtc_pps = 1'b0; initial rtc_pps_counter = 0; always @(posedge i_clk) if (rtc_pps_counter > 0) begin rtc_pps_counter <= rtc_pps_counter - 1; rtc_pps <= 1'b0; end else begin rtc_pps_counter <= 27'd100_000_000 - 1; rtc_pps <= 1'b1; end `ifdef BKRAM_ACCESS // {{{ memdev #( .LGMEMSZ(20), .DW(128), .EXTRACLOCK(1) ) u_bkram ( .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wbwide_bkram_cyc), .i_wb_stb(wbwide_bkram_stb), .i_wb_we(wbwide_bkram_we), .i_wb_addr(wbwide_bkram_addr[16-1:0]), .i_wb_data(wbwide_bkram_data), // 128 bits wide .i_wb_sel(wbwide_bkram_sel), // 128/8 bits wide .o_wb_stall(wbwide_bkram_stall),.o_wb_ack(wbwide_bkram_ack), .o_wb_data(wbwide_bkram_idata) ); // }}} `else // BKRAM_ACCESS // {{{ // Null bus slave // {{{ // // In the case that there is no wbwide_bkram peripheral // responding on the wbwide bus assign wbwide_bkram_ack = 1'b0; assign wbwide_bkram_err = (wbwide_bkram_stb); assign wbwide_bkram_stall = 0; assign wbwide_bkram_idata = 0; // }}} // }}} `endif // BKRAM_ACCESS wbdown #( // {{{ // Slave bus address width: 27 // Slave address width : 10 // Master address width : 12 .ADDRESS_WIDTH(10+$clog2(128/8)), .WIDE_DW(128), .SMALL_DW(32), .OPT_LITTLE_ENDIAN(1'b0), .OPT_LOWLOGIC(1'b0) // }}} ) u_crossbus ( // {{{ .i_clk(i_clk), .i_reset(i_reset), // Slave/incoming // {{{ .i_wcyc( wbwide_crossbus_cyc), .i_wstb( wbwide_crossbus_stb), .i_wwe( wbwide_crossbus_we), .i_waddr( wbwide_crossbus_addr[10-1:0]), .i_wdata( wbwide_crossbus_data), .i_wsel( wbwide_crossbus_sel), .o_wstall(wbwide_crossbus_stall), .o_wack( wbwide_crossbus_ack), .o_wdata( wbwide_crossbus_idata), .o_werr( wbwide_crossbus_err), // }}} // Master/down-range/outgoing // {{{ .o_scyc( wb32_crossbus_cyc), .o_sstb( wb32_crossbus_stb), .o_swe( wb32_crossbus_we), .o_saddr( wb32_crossbus_addr[12-1:0]), .o_sdata( wb32_crossbus_data), .o_ssel( wb32_crossbus_sel), .i_sstall(wb32_crossbus_stall), .i_sack( wb32_crossbus_ack), .i_sdata( wb32_crossbus_idata), .i_serr( wb32_crossbus_err) // }}} // }}} ); `ifdef SDRAM_ACCESS // {{{ //////////////////////////////////////////////////////////////////////// // // DDR3 Controller instantiation // {{{ ddr3_controller #( // {{{ .CONTROLLER_CLK_PERIOD(SDRAMCONTROLLER_CLK_PERIOD), //ps, clock period of the controller interface .DDR3_CLK_PERIOD(DDR3_CLK_PERIOD), //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD) .ROW_BITS(SDRAMROW_BITS), //width of row address .COL_BITS(SDRAMCOL_BITS), //width of column address .BA_BITS(SDRAMBA_BITS), //width of bank address .DQ_BITS(SDRAMDQ_BITS), //width of DQ .LANES(SDRAMBYTE_LANES), // byte lanes .AUX_WIDTH(SDRAMAUX_WIDTH), //width of aux line (must be >= 4) .WB2_ADDR_BITS(7), //width of 2nd wishbone address bus .WB2_DATA_BITS(32), //width of 2nd wishbone data bus .MICRON_SIM(0), //simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW) .ODELAY_SUPPORTED(1), //set to 1 when ODELAYE2 is supported .SECOND_WISHBONE(1) //set to 1 if 2nd wishbone is needed // }}} ) u_ddr3 ( // {{{ .i_controller_clk(i_clk), //i_controller_clk has period of CONTROLLER_CLK_PERIOD .i_rst_n(!i_reset), //200MHz input clock // Wishbone 1 (Controller) .i_wb_cyc(wbwide_ddr3_cyc), .i_wb_stb(wbwide_ddr3_stb), .i_wb_we(wbwide_ddr3_we), .i_wb_addr(wbwide_ddr3_addr[26-1:0]), .i_wb_data(wbwide_ddr3_data), // 128 bits wide .i_wb_sel(wbwide_ddr3_sel), // 128/8 bits wide .o_wb_stall(wbwide_ddr3_stall),.o_wb_ack(wbwide_ddr3_ack), .o_wb_data(wbwide_ddr3_idata), .i_aux(0), .o_aux(ddr3_aux_out), // Leaving this empty would've caused a Verilator warning // Wishbone 2 (PHY) .i_wb2_cyc(wb32_ddr3_phy_cyc), .i_wb2_stb(wb32_ddr3_phy_stb), .i_wb2_we(wb32_ddr3_phy_we), .i_wb2_addr(wb32_ddr3_phy_addr[7-1:0]), .i_wb2_data(wb32_ddr3_phy_data), // 32 bits wide .i_wb2_sel(wb32_ddr3_phy_sel), // 32/8 bits wide .o_wb2_stall(wb32_ddr3_phy_stall),.o_wb2_ack(wb32_ddr3_phy_ack), .o_wb2_data(wb32_ddr3_phy_idata), // // PHY interface .i_phy_iserdes_data(i_ddr3_iserdes_data), .i_phy_iserdes_dqs(i_ddr3_iserdes_dqs), .i_phy_iserdes_bitslip_reference(i_ddr3_iserdes_bitslip_reference), .i_phy_idelayctrl_rdy(i_ddr3_idelayctrl_rdy), .o_phy_cmd(o_ddr3_cmd), .o_phy_dqs_tri_control(o_ddr3_dqs_tri_control), .o_phy_dq_tri_control(o_ddr3_dq_tri_control), .o_phy_toggle_dqs(o_ddr3_toggle_dqs), .o_phy_data(o_ddr3_data), .o_phy_dm(o_ddr3_dm), .o_phy_odelay_data_cntvaluein(o_ddr3_odelay_data_cntvaluein), .o_phy_odelay_dqs_cntvaluein(o_ddr3_odelay_dqs_cntvaluein), .o_phy_idelay_data_cntvaluein(o_ddr3_idelay_data_cntvaluein), .o_phy_idelay_dqs_cntvaluein(o_ddr3_idelay_dqs_cntvaluein), .o_phy_odelay_data_ld(o_ddr3_odelay_data_ld), .o_phy_odelay_dqs_ld(o_ddr3_odelay_dqs_ld), .o_phy_idelay_data_ld(o_ddr3_idelay_data_ld), .o_phy_idelay_dqs_ld(o_ddr3_idelay_dqs_ld), .o_phy_bitslip(o_ddr3_bitslip), .o_phy_write_leveling_calib(o_ddr3_leveling_calib), .o_phy_reset(o_ddr3_reset), // Debug port .o_debug1(ddr3_debug), // Verilator lint_off PINCONNECTEMPTY .o_debug2(), .o_debug3() // Verilator lint_on PINCONNECTEMPTY // }}} ); // }}} // }}} `else // SDRAM_ACCESS // {{{ // Null bus slave // {{{ // // In the case that there is no wbwide_ddr3 peripheral // responding on the wbwide bus assign wbwide_ddr3_ack = 1'b0; assign wbwide_ddr3_err = (wbwide_ddr3_stb); assign wbwide_ddr3_stall = 0; assign wbwide_ddr3_idata = 0; // }}} // }}} `endif // SDRAM_ACCESS `ifdef I2CDMA_ACCESS // {{{ wbi2cdma #( .AW(27), .DW(128), .SW(8), .OPT_LITTLE_ENDIAN(1'b0) ) u_i2cdma ( // {{{ .i_clk(i_clk), .i_reset(i_reset), // .i_wb_cyc(wb32_i2cdma_cyc), .i_wb_stb(wb32_i2cdma_stb), .i_wb_we(wb32_i2cdma_we), .i_wb_addr(wb32_i2cdma_addr[2-1:0]), .i_wb_data(wb32_i2cdma_data), // 32 bits wide .i_wb_sel(wb32_i2cdma_sel), // 32/8 bits wide .o_wb_stall(wb32_i2cdma_stall),.o_wb_ack(wb32_i2cdma_ack), .o_wb_data(wb32_i2cdma_idata), .S_VALID(i2c_valid && i2c_id == 2), .S_READY(i2cdma_ready), .S_DATA(i2c_data), .S_LAST(i2c_last), .o_dma_cyc(wbwide_i2cdma_cyc), .o_dma_stb(wbwide_i2cdma_stb), .o_dma_we(wbwide_i2cdma_we), .o_dma_addr(wbwide_i2cdma_addr[27-1:0]), .o_dma_data(wbwide_i2cdma_data), // 128 bits wide .o_dma_sel(wbwide_i2cdma_sel), // 128/8 bits wide .i_dma_stall(wbwide_i2cdma_stall), .i_dma_ack(wbwide_i2cdma_ack), .i_dma_data(wbwide_i2cdma_idata), .i_dma_err(wbwide_i2cdma_err) // }}} ); // }}} `else // I2CDMA_ACCESS // {{{ assign i2cdma_ready = 1'b0; // Null bus master // {{{ // }}} // }}} `endif // I2CDMA_ACCESS `ifdef PWRCOUNT_ACCESS // {{{ initial r_pwrcount_data = 32'h0; always @(posedge i_clk) if (r_pwrcount_data[31]) r_pwrcount_data[30:0] <= r_pwrcount_data[30:0] + 1'b1; else r_pwrcount_data[31:0] <= r_pwrcount_data[31:0] + 1'b1; assign wb32_pwrcount_stall = 1'b0; assign wb32_pwrcount_ack = wb32_pwrcount_stb; assign wb32_pwrcount_idata = r_pwrcount_data; // }}} `else // PWRCOUNT_ACCESS // {{{ // }}} `endif // PWRCOUNT_ACCESS `ifdef I2SAUDIO // {{{ //////////////////////////////////////////////////////////////////////// // // I2S Audio signal handler // {{{ assign o_i2s_mclk = i_genclk_clk; assign w_i2saudio_en = 1'b1; axisi2s #( .BDIV(4'h1) ) u_i2saudio ( // {{{ .S_AXI_ACLK(i_clk), .S_AXI_ARESETN(!i_reset), // // Inputs to drive the speakers .S_AXIS_TVALID(w_audio_out_valid), .S_AXIS_TREADY(w_audio_out_ready), .S_AXIS_TDATA(w_audio_out_data), .S_AXIS_TLAST(w_audio_out_last), // // Outputs from the microphone .M_AXIS_TVALID(w_audio_in_valid), .M_AXIS_TREADY(w_audio_in_ready), .M_AXIS_TDATA(w_audio_in_data), .M_AXIS_TLAST(w_audio_in_last), // .i_mclk(o_i2s_mclk), .i_clken(w_i2saudio_en), .o_lrclk(o_i2s_lrclk), .o_bclk(o_i2s_bclk), .i_adc(i_i2s_adc), .o_dac(o_i2s_dac), .o_debug(w_i2saudio_debug) // }}} ); `ifndef AUDIOSINK_ACCESS assign w_audio_out_valid = 0; assign w_audio_out_data = 0; assign w_audio_out_last = 0; `endif `ifndef AUDIOSOURCE_ACCESS assign w_audio_in_ready = 1; `endif // }}} // }}} `else // I2SAUDIO // {{{ //////////////////////////////////////////////////////////////////////// // // (No) I2S Audio signal handler (option) // {{{ `ifndef AUDIOSINK_ACCESS assign w_audio_out_valid = 0; assign w_audio_out_data = 0; assign w_audio_out_last = 0; `endif assign w_audio_out_ready = 0; assign w_audio_in_valid = 0; assign w_audio_in_data = 0; assign w_audio_in_last = 0; `ifndef AUDIOSOURCE_ACCESS assign w_audio_in_ready = 0; `endif // }}} // }}} `endif // I2SAUDIO // Generate a PPS signal independent of the GPS--useful for testing gpsclock_tb #( .CLOCK_FREQUENCY_HZ(100000000) ) ppstb( .i_clk(i_clk), .i_lcl_pps(ck_pps), .o_pps(tb_pps), .i_wb_cyc(wb32_gtb_cyc), .i_wb_stb(wb32_gtb_stb), .i_wb_we(wb32_gtb_we), .i_wb_addr(wb32_gtb_addr[3-1:0]), .i_wb_data(wb32_gtb_data), // 32 bits wide .i_wb_sel(wb32_gtb_sel), // 32/8 bits wide .o_wb_stall(wb32_gtb_stall),.o_wb_ack(wb32_gtb_ack), .o_wb_data(wb32_gtb_idata), .i_err(gps_err), .i_count(gps_now), .i_step(gps_step) ); assign gps_pps = tb_pps; assign o_pxclk_cyc = wb32_pxclk_cyc; assign o_pxclk_stb = wb32_pxclk_stb; assign o_pxclk_we = wb32_pxclk_we; assign o_pxclk_addr = wb32_pxclk_addr[6:0]; assign o_pxclk_data = wb32_pxclk_data; assign o_pxclk_sel = wb32_pxclk_sel; assign wb32_pxclk_stall = i_pxclk_stall; assign wb32_pxclk_ack = i_pxclk_ack; assign wb32_pxclk_idata = i_pxclk_idata; `ifdef MEGANET_ACCESS // {{{ //////////////////////////////////////////////////////////////////////// // // MegaNET MEGANET // {{{ //////////////////////////////////////////////////////////////////////// // // meganet #( // {{{ .DEF_HWMAC(DEF_HWMAC), .DEF_IPADDR(DEF_IPADDR), .UDP_DBGPORT(UDP_DBGPORT) // }}} ) u_net ( // {{{ .S_AXI_ACLK(i_clk), .S_AXI_ARESETN(!i_reset), // .o_hwmac(net_hwmac), .o_ipaddr(net_ip_addr), .o_ping_hwmac(net_last_ping_hwmac), .o_ping_ipaddr(net_last_ping_ipaddr), // Wishbone port // {{{ .i_wb_cyc(wb32_net_cyc), .i_wb_stb(wb32_net_stb), .i_wb_we(wb32_net_we), .i_wb_addr(wb32_net_addr[5-1:0]), .i_wb_data(wb32_net_data), // 32 bits wide .i_wb_sel(wb32_net_sel), // 32/8 bits wide .o_wb_stall(wb32_net_stall),.o_wb_ack(wb32_net_ack), .o_wb_data(wb32_net_idata), // }}} // ifdef MEGANETCPUTX_ACCESS // {{{ .S_CPU_VALID(netcputx_valid), .S_CPU_READY(netcputx_ready), .S_CPU_DATA(netcputx_data), .S_CPU_BYTES(netcputx_bytes), .S_CPU_LAST(netcputx_last), .S_CPU_ABORT(netcputx_abort), // }}} `ifdef NETBUS_ACCESS // {{{ .S_DBG_VALID(netbus_valid), .S_DBG_READY(netbus_ready), .S_DBG_DATA(netbus_pkdata), // .S_DBG_BYTES(netbus_bytes), .S_DBG_LAST(netbus_last), `else .S_DBG_VALID(1'b0), .S_DBG_READY(net_dbg_ready), .S_DBG_DATA(32'h0), .S_DBG_LAST(1'b1), `endif // }}} // Data interface // {{{ .S_DATA_VALID(1'b0), .S_DATA_READY(ign_rxpkt_net_ready), .S_DATA_DATA(32'h0), .S_DATA_BYTES(2'h0), .S_DATA_LAST(1'b1), // }}} // ifdef MEGANETCPURX_ACCESS // {{{ .M_CPU_VALID(netcpurx_valid), .M_CPU_READY(netcpurx_ready), .M_CPU_DATA(netcpurx_data), .M_CPU_BYTES(netcpurx_bytes), .M_CPU_LAST(netcpurx_last), .M_CPU_ABORT(netcpurx_abort), // }}} // Debug IP/UDP RX packets // {{{ .M_DBG_VALID(net_dbg_valid), .M_DBG_READY(net_dbg_ready), .M_DBG_DATA( net_dbg_data), .M_DBG_BYTES(net_dbg_bytes), .M_DBG_LAST( net_dbg_last), // }}} // Interface to top-level IOs // {{{ .o_net_reset_n(o_net_reset_n), .i_net_rx_clk(i_net_rx_clk), .i_net_rx_dv(i_net_rx_dv), .i_net_rx_err(i_net_rx_err), .i_net_rxd(i_net_rxd), // .i_net_tx_clk(i_net_tx_clk), .o_net_tx_ck(o_net_tx_clk), .o_net_tx_ctl(o_net_tx_ctl), .o_net_txd(o_net_txd), // }}} .o_debug_clk(net_debug_clk), .o_debug(net_debug) // }}} ); `ifndef NETBUS_ACCESS // {{{ assign net_dbg_ready = 1'b1; // Verilator lint_off UNUSED wire unused_net_dbgrx; assign unused_net_dbgrx = &{ 1'b0, net_dbg_valid, net_dbg_data, net_dbg_bytes, net_dbg_last }; // Verilator lint_on UNUSED // }}} `endif `ifndef MEGANETCPURX_ACCESS // {{{ assign netcpurx_ready = 1'b1; // Verilator lint_off UNUSED wire unused_net_cpu_rx; assign unused_net_cpu_rx = &{ 1'b0, netcpurx_valid, netcpurx_data, netcpurx_bytes, netcpurx_abort, netcpurx_last }; // Verilator lint_on UNUSED // }}} `endif `ifndef MEGANETCPUTX_ACCESS // {{{ assign netcputx_valid = 1'b0; assign netcputx_data = 32'h0; assign netcputx_bytes = 2'h0; assign netcputx_last = 1'b1; assign netcputx_abort = 1'b0; // }}} `endif // }}} // }}} `else // MEGANET_ACCESS // {{{ // Null bus slave // {{{ // // In the case that there is no wb32_net peripheral // responding on the wb32 bus assign wb32_net_ack = 1'b0; assign wb32_net_err = (wb32_net_stb); assign wb32_net_stall = 0; assign wb32_net_idata = 0; // }}} // }}} `endif // MEGANET_ACCESS `ifdef RTCDATE_ACCESS // {{{ // // The Calendar DATE // rtcdate #( .INITIAL_DATE(`DATESTAMP) ) u_rtcdate( .i_clk(i_clk), .i_ppd(rtc_ppd), .i_wb_cyc(wb32_rtcdate_cyc), .i_wb_stb(wb32_rtcdate_stb), .i_wb_we(wb32_rtcdate_we), .i_wb_data(wb32_rtcdate_data), // 32 bits wide .i_wb_sel(wb32_rtcdate_sel), // 32/8 bits wide .o_wb_stall(wb32_rtcdate_stall),.o_wb_ack(wb32_rtcdate_ack), .o_wb_data(wb32_rtcdate_idata) ); // }}} `else // RTCDATE_ACCESS // {{{ // }}} `endif // RTCDATE_ACCESS `ifdef RTC_ACCESS // {{{ `ifdef GPSTRK_ACCESS rtcgps #( .DEFAULT_SPEED(RTC_CLKSTEP) ) u_rtc( .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wb32_rtc_cyc), .i_wb_stb(wb32_rtc_stb), .i_wb_we(wb32_rtc_we), .i_wb_addr(wb32_rtc_addr[2-1:0]), .i_wb_data(wb32_rtc_data), // 32 bits wide .i_wb_sel(wb32_rtc_sel), // 32/8 bits wide .o_wb_stall(wb32_rtc_stall),.o_wb_ack(wb32_rtc_ack), .o_wb_data(wb32_rtc_idata), .o_interrupt(rtc_int), .o_ppd(rtc_ppd), .i_gps_valid(gps_tracking), .i_gps_pps(ck_pps), .i_gps_ckspeed(gps_step[47:16]), .o_rtc_pps(rtc_pps) ); `else rtclight #( .DEFAULT_SPEED(32'h2af31d) ) u_rtc( .i_clk(i_clk), .i_reset(i_reset), // Can't use the ANSIPORTLIST tag, because the address widths // don't match .i_wb_cyc(wb32_rtc_cyc), .i_wb_stb(wb32_rtc_stb), .i_wb_we(wb32_rtc_we), .i_wb_addr({ 1'b0, wb32_rtc_addr[1:0] }), .i_wb_data(wb32_rtc_data), .i_wb_sel(wb32_rtc_sel), .o_wb_stall(wb32_rtc_stall), .o_wb_ack(wb32_rtc_ack), .o_wb_data(wb32_rtc_idata), .o_interrupt(rtc_int), .o_pps(rtc_pps), .o_ppd(rtc_ppd) ); // Verilator lint_off UNUSED wire unused_rtc; assign unused_rtc = &{ 1'b0, i_gps_pps }; // Verilator lint_on UNUSED `endif // }}} `else // RTC_ACCESS // {{{ `ifdef GPSTRK_ACCESS assign rtc_pps = ck_pps; `endif assign rtc_ppd = 1'b0; // Null interrupt definitions // {{{ assign rtc_int = 1'b0; // rtc.INT.RTC.WIRE // }}} // }}} `endif // RTC_ACCESS `ifdef SPIO_ACCESS // {{{ // // Special purpose I/O driver (buttons, LEDs, and switches) // assign w_btn = { i_btnc, i_btnd, i_btnl, i_btnr, i_btnu }; spio #( .NBTN(5), .NLEDS(8), .NSW(8) ) u_spio ( .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wb32_spio_cyc), .i_wb_stb(wb32_spio_stb), .i_wb_we(wb32_spio_we), .i_wb_data(wb32_spio_data), // 32 bits wide .i_wb_sel(wb32_spio_sel), // 32/8 bits wide .o_wb_stall(wb32_spio_stall),.o_wb_ack(wb32_spio_ack), .o_wb_data(wb32_spio_idata), .i_sw(i_sw), .i_btn(w_btn), .o_led(w_led), .o_int(spio_int) ); assign o_led = w_led; // }}} `else // SPIO_ACCESS // {{{ assign w_btn = 0; assign o_led = 0; // Null interrupt definitions // {{{ assign spio_int = 1'b0; // spio.INT.SPIO.WIRE // }}} // }}} `endif // SPIO_ACCESS `ifdef GPIO_ACCESS // {{{ //////////////////////////////////////////////////////////////////////// // // GPIO // {{{ // This interface should allow us to control up to 16 GPIO inputs, // and another 16 GPIO outputs. The interrupt trips when any of // the inputs changes. (Sorry, which input isn't (yet) selectable.) // localparam [NGPO-1:0] INITIAL_GPIO = 10'h13; wbgpio #( .NIN(NGPI), .NOUT(NGPO), .DEFAULT(INITIAL_GPIO) ) u_gpio ( // {{{ .i_clk(i_clk), .i_wb_cyc(wb32_gpio_cyc), .i_wb_stb(wb32_gpio_stb), .i_wb_we(wb32_gpio_we), .i_wb_data(wb32_gpio_data), // 32 bits wide .i_wb_sel(wb32_gpio_sel), // 32/8 bits wide .o_wb_stall(wb32_gpio_stall),.o_wb_ack(wb32_gpio_ack), .o_wb_data(wb32_gpio_idata), .i_gpio(i_gpio), .o_gpio(o_gpio), .o_int(gpio_int) // }}} ); `ifdef SDIO_ACCESS // This bit is used by the SDSPI controller, not the SDIO controller. assign sd_reset = !o_sdio_hwreset_n; `else assign sd_reset = o_gpio[3]; `endif `ifdef VERILATOR wire verilator_halt; assign o_trace = o_gpio[8]; assign verilator_halt = o_gpio[9]; assign o_halt = verilator_halt; always @(posedge verilator_halt) $finish; `endif // }}} // }}} `else // GPIO_ACCESS // {{{ // Null interrupt definitions // {{{ assign gpio_int = 1'b0; // gpio.INT.GPIO.WIRE // }}} // }}} `endif // GPIO_ACCESS `ifdef SDIO_ACCESS // {{{ //////////////////////////////////////////////////////////////////////// // // SDIO SD Card handling // {{{ //////////////////////////////////////////////////////////////////////// // // always @(*) begin sdio_debug = i_sdio_debug; sdio_debug = w_sdio_sdwb_debug; end sdio #( // {{{ .LGFIFO(10), .NUMIO(4), .MW(32), .ADDRESS_WIDTH(27+$clog2(128/8)), .DMA_DW(128), .OPT_SERDES(1'b1), .OPT_EMMC(1'b0), .OPT_DMA(1'b1), .OPT_DDR(1'b1), .OPT_HWRESET(1'b0), .OPT_CARD_DETECT(1'b1), .OPT_CRCTOKEN(1), .OPT_1P8V(1'b0), `ifdef VERILATOR .LGTIMEOUT(18), `else .LGTIMEOUT(26), `endif .OPT_ISTREAM(1'b0), .OPT_OSTREAM(1'b0) // }}} ) u_sdio( // {{{ .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wbflash_sdio_cyc), .i_wb_stb(wbflash_sdio_stb), .i_wb_we(wbflash_sdio_we), .i_wb_addr(wbflash_sdio_addr[3-1:0]), .i_wb_data(wbflash_sdio_data), // 32 bits wide .i_wb_sel(wbflash_sdio_sel), // 32/8 bits wide .o_wb_stall(wbflash_sdio_stall),.o_wb_ack(wbflash_sdio_ack), .o_wb_data(wbflash_sdio_idata), .o_dma_cyc(wbwide_sdio_cyc), .o_dma_stb(wbwide_sdio_stb), .o_dma_we(wbwide_sdio_we), .o_dma_addr(wbwide_sdio_addr[27-1:0]), .o_dma_data(wbwide_sdio_data), // 128 bits wide .o_dma_sel(wbwide_sdio_sel), // 128/8 bits wide .i_dma_stall(wbwide_sdio_stall), .i_dma_ack(wbwide_sdio_ack), .i_dma_data(wbwide_sdio_idata), .i_dma_err(wbwide_sdio_err), // (Unused) DMA Stream assignments // {{{ .s_valid(1'b0), .s_ready(s_sdio_ready), .s_data(32'h0), // .m_valid(m_sdio_valid), .m_ready(1'b1), .m_data(m_sdio_data), .m_last(m_sdio_last), // }}} .i_card_detect(i_sdio_detect), .o_hwreset_n(o_sdio_hwreset_n), .o_1p8v(o_sdio_1p8v), .o_int(sdio_int), // .o_cfg_ddr(o_sdio_cfg_ddr), .o_cfg_ds(o_sdio_cfg_ds), .o_cfg_dscmd(o_sdio_cfg_dscmd), .o_cfg_sample_shift(o_sdio_cfg_sample_shift), .o_cmd_tristate(o_sdio_cmd_tristate), .o_data_tristate(o_sdio_data_tristate), // .o_sdclk( o_sdio_sdclk), .o_cmd_en( o_sdio_cmd_en), .o_cmd_data(o_sdio_cmd_data), .o_data_en( o_sdio_data_en), .o_rx_en( o_sdio_rx_en), .o_tx_data( o_sdio_tx_data), // .i_cmd_strb( i_sdio_cmd_strb), .i_cmd_data( i_sdio_cmd_data), .i_cmd_collision( i_sdio_cmd_collision), .i_crcack( i_sdio_crcack), .i_crcnak( i_sdio_crcnak), .i_card_busy(i_sdio_card_busy), .i_rx_strb( i_sdio_rx_strb), .i_rx_data( i_sdio_rx_data), // .S_AC_VALID(i_sdio_ac_valid), .S_AC_DATA( i_sdio_ac_data), .S_AD_VALID(i_sdio_ad_valid), .S_AD_DATA( i_sdio_ad_data), // .o_debug(w_sdio_sdwb_debug) // }}} ); // }}} // }}} `else // SDIO_ACCESS // {{{ // Null bus master // {{{ // }}} // Null bus slave // {{{ // // In the case that there is no wbflash_sdio peripheral // responding on the wbflash bus assign wbflash_sdio_ack = 1'b0; assign wbflash_sdio_err = (wbflash_sdio_stb); assign wbflash_sdio_stall = 0; assign wbflash_sdio_idata = 0; // }}} // Null interrupt definitions // {{{ assign sdio_int = 1'b0; // sdio.INT.SDCARD.WIRE // }}} // }}} `endif // SDIO_ACCESS assign i_net_tx_clk = i_clk_125mhz; `ifdef BUSPIC_ACCESS // {{{ // // The BUS Interrupt controller // icontrol #(15) u_buspic ( .i_clk(i_clk), .i_reset(1'b0), .i_wb_cyc(wb32_buspic_cyc), .i_wb_stb(wb32_buspic_stb), .i_wb_we(wb32_buspic_we), .i_wb_data(wb32_buspic_data), // 32 bits wide .i_wb_sel(wb32_buspic_sel), // 32/8 bits wide .o_wb_stall(wb32_buspic_stall),.o_wb_ack(wb32_buspic_ack), .o_wb_data(wb32_buspic_idata), .i_brd_ints(bus_int_vector), .o_interrupt(w_bus_int) ); // }}} `else // BUSPIC_ACCESS // {{{ // Null interrupt definitions // {{{ assign w_bus_int = 1'b0; // buspic.INT.BUS.WIRE // }}} // }}} `endif // BUSPIC_ACCESS `ifdef GPSTRK_ACCESS // {{{ // Verilator lint_off UNUSED wire [1:0] ck_dbg; // Verilator lint_on UNUSED gpsclock #( .DEFAULT_STEP(GPSCLOCK_DEFAULT_STEP) ) ppsck ( .i_clk(i_clk), .i_rst(1'b0), .i_pps(gps_pps), .o_pps(ck_pps), .o_led(gps_led), .i_wb_cyc(wb32_gck_cyc), .i_wb_stb(wb32_gck_stb), .i_wb_we(wb32_gck_we), .i_wb_addr(wb32_gck_addr[2-1:0]), .i_wb_data(wb32_gck_data), // 32 bits wide .i_wb_sel(wb32_gck_sel), // 32/8 bits wide .o_wb_stall(wb32_gck_stall),.o_wb_ack(wb32_gck_ack), .o_wb_data(wb32_gck_idata), .o_tracking(gps_tracking), .o_count(gps_now), .o_step(gps_step), .o_err(gps_err), .o_locked(gps_locked), .o_dbg(ck_dbg) ); assign gck_pps = ck_pps; // }}} `else // GPSTRK_ACCESS // {{{ reg r_ck_pps; reg [63:0] r_gps_now; reg [31:0] r_gps_prior; wire [47:0] pre_step; assign pre_step = { 16'h00, (({GPSCLOCK_DEFAULT_STEP[27:0],20'h00}) >>GPSCLOCK_DEFAULT_STEP[31:28]) }; initial { r_ck_pps, r_gps_prior } = 33'h0; always @(posedge i_clk) { r_ck_pps, r_gps_prior[31:0] } <= r_gps_prior + pre_step[31:0]; initial r_gps_now = 64'h0; always @(posedge i_clk) begin r_gps_now[63:32] <= r_gps_now[63:32]+(r_ck_pps ? 32'h1:32'h0); r_gps_now[31:0] <= r_gps_prior; end assign ck_pps = r_ck_pps; assign gps_now = r_gps_now; assign gps_err = 64'h0; assign gps_step = pre_step; assign gps_led = 1'b0; assign gps_locked = 1'b0; // Null interrupt definitions // {{{ assign gck_pps = 1'b0; // gck.INT.PPS.WIRE // }}} // }}} `endif // GPSTRK_ACCESS `ifdef NETCTRL_ACCESS // {{{ enetctrl #( .CLKBITS(6) ) u_mdio ( .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wb32_mdio_cyc), .i_wb_stb(wb32_mdio_stb), .i_wb_we(wb32_mdio_we), .i_wb_addr(wb32_mdio_addr[10-1:0]), .i_wb_data(wb32_mdio_data), // 32 bits wide .i_wb_sel(wb32_mdio_sel), // 32/8 bits wide .o_wb_stall(wb32_mdio_stall),.o_wb_ack(wb32_mdio_ack), .o_wb_data(wb32_mdio_idata), .o_mdclk(o_mdclk), .o_mdio(o_mdio), .i_mdio(i_mdio), .o_mdwe(o_mdwe), .o_debug(mdio_debug) ); // }}} `else // NETCTRL_ACCESS // {{{ assign o_mdclk = 1'b1; assign o_mdio = 1'b1; assign o_mdwe = 1'b0; // Null bus slave // {{{ // // In the case that there is no wb32_mdio peripheral // responding on the wb32 bus assign wb32_mdio_ack = 1'b0; assign wb32_mdio_err = (wb32_mdio_stb); assign wb32_mdio_stall = 0; assign wb32_mdio_idata = 0; // }}} // }}} `endif // NETCTRL_ACCESS assign wb32_buildtime_idata = `BUILDTIME; assign wb32_buildtime_ack = wb32_buildtime_stb; assign wb32_buildtime_stall = 1'b0; `ifdef VERSION_ACCESS // {{{ assign wb32_version_idata = `DATESTAMP; assign wb32_version_ack = wb32_version_stb; assign wb32_version_stall = 1'b0; // }}} `else // VERSION_ACCESS // {{{ // }}} `endif // VERSION_ACCESS `ifdef OLEDBW_ACCESS // {{{ spicpu #( // {{{ .ADDRESS_WIDTH(27), .DATA_WIDTH(128), .NCE(2), .OPT_MANUAL(1'b1), .OPT_LITTLE_ENDIAN(1'b0), .OPT_START_HALTED(1'b1), .OPT_SHARED_MISO(1'b1) // }}} ) u_oled ( // {{{ .i_clk(i_clk), .i_reset(i_reset), .i_wb_cyc(wb32_oled_cyc), .i_wb_stb(wb32_oled_stb), .i_wb_we(wb32_oled_we), .i_wb_addr(wb32_oled_addr[2-1:0]), .i_wb_data(wb32_oled_data), // 32 bits wide .i_wb_sel(wb32_oled_sel), // 32/8 bits wide .o_wb_stall(wb32_oled_stall),.o_wb_ack(wb32_oled_ack), .o_wb_data(wb32_oled_idata), .o_pf_cyc(wbwide_oledm_cyc), .o_pf_stb(wbwide_oledm_stb), .o_pf_we(wbwide_oledm_we), .o_pf_addr(wbwide_oledm_addr[27-1:0]), .o_pf_data(wbwide_oledm_data), // 128 bits wide .o_pf_sel(wbwide_oledm_sel), // 128/8 bits wide .i_pf_stall(wbwide_oledm_stall), .i_pf_ack(wbwide_oledm_ack), .i_pf_data(wbwide_oledm_idata), .i_pf_err(wbwide_oledm_err), .o_spi_csn(w_oled_csn), .o_spi_sck(o_oled_sck), .o_spi_mosi(o_oled_mosi), .i_spi_miso(1'b0), .M_AXIS_TVALID(ign_oled_valid), .M_AXIS_TREADY(1'b1), .M_AXIS_TDATA( ign_oled_data), .M_AXIS_TLAST( ign_oled_last), .M_AXIS_TID( ign_oled_id), // .o_interrupt(oled_int), .i_sync_signal(rtc_pps), .o_debug(oled_debug) // }}} ); assign o_oled_dcn = w_oled_csn[0]; // }}} `else // OLEDBW_ACCESS // {{{ assign o_oled_sck = 1'b1; assign o_oled_mosi = 1'b1; assign o_oled_dcn = 1'b1; // Null bus master // {{{ // }}} // Null interrupt definitions // {{{ assign oled_int = 1'b0; // oled.INT.OLED.WIRE // }}} // }}} `endif // OLEDBW_ACCESS `ifdef MICROPHONE_ACCESS // {{{ wbmic #(.DEFAULT_RELOAD(@$.CLKSPERSAMPLE)) microphone(i_clk, 1'b0, wb32_pmic_cyc, wb32_pmic_stb, wb32_pmic_we, wb32_pmic_addr[1-1:0], wb32_pmic_data, // 32 bits wide wb32_pmic_sel, // 32/8 bits wide wb32_pmic_stall, wb32_pmic_ack, wb32_pmic_idata, o_mic_csn, o_mic_sck, i_mic_din, pmic_int); // }}} `else // MICROPHONE_ACCESS // {{{ assign o_mic_csn = 1'b1; assign o_mic_sck = 1'b1; // Null bus slave // {{{ // // In the case that there is no wb32_pmic peripheral // responding on the wb32 bus assign wb32_pmic_ack = 1'b0; assign wb32_pmic_err = (wb32_pmic_stb); assign wb32_pmic_stall = 0; assign wb32_pmic_idata = 0; // }}} // Null interrupt definitions // {{{ assign pmic_int = 1'b0; // pmic.INT.MIC.WIRE // }}} // }}} `endif // MICROPHONE_ACCESS //////////////////////////////////////////////////////////////////////// // // WBUBUS "wbu_arbiter" master->slave connection // {{{ wbupsz #( // {{{ // Slave bus address width : 30 // Slave address width : 29 // Master bus address width: 27 .ADDRESS_WIDTH(27+$clog2(128/8)), .SMALL_DW(32), .WIDE_DW(128), .OPT_LITTLE_ENDIAN(1'b0) // }}} ) u_wbu_wbwide_downsz ( // {{{ .i_clk(i_clk), .i_reset(i_reset), .i_scyc(wbu_wbu_arbiter_cyc), .i_sstb(wbu_wbu_arbiter_stb), .i_swe(wbu_wbu_arbiter_we), .i_saddr(wbu_wbu_arbiter_addr[29-1:0]), .i_sdata(wbu_wbu_arbiter_data), // 32 bits wide .i_ssel(wbu_wbu_arbiter_sel), // 32/8 bits wide .o_sstall(wbu_wbu_arbiter_stall),.o_sack(wbu_wbu_arbiter_ack), .o_sdata(wbu_wbu_arbiter_idata), .o_serr(wbu_wbu_arbiter_err), .o_wcyc(wbwide_wbu_arbiter_cyc), .o_wstb(wbwide_wbu_arbiter_stb), .o_wwe(wbwide_wbu_arbiter_we), .o_waddr(wbwide_wbu_arbiter_addr[27-1:0]), .o_wdata(wbwide_wbu_arbiter_data), // 128 bits wide .o_wsel(wbwide_wbu_arbiter_sel), // 128/8 bits wide .i_wstall(wbwide_wbu_arbiter_stall), .i_wack(wbwide_wbu_arbiter_ack), .i_wdata(wbwide_wbu_arbiter_idata), .i_werr(wbwide_wbu_arbiter_err) // }}} ); // }}} `ifdef INCLUDE_ZIPCPU // {{{ //////////////////////////////////////////////////////////////////////// // // The ZipCPU/ZipSystem BUS master // {{{ // assign zip_int_vector = { alt_int_vector[14:8], sys_int_vector[14:6] }; zipsystem #( // {{{ .RESET_ADDRESS(RESET_ADDRESS), .ADDRESS_WIDTH(ZIP_ADDRESS_WIDTH + $clog2(128/8)), .BUS_WIDTH(128), .OPT_LGICACHE(12), .OPT_LGDCACHE(12), .START_HALTED(ZIP_START_HALTED), .RESET_DURATION(20), .OPT_PIPELINED(1), `ifdef VERILATOR .OPT_PROFILER(1'b1), `else .OPT_PROFILER(1'b0), `endif `ifdef ZIPSCOPE_SCOPE .OPT_TRACE_PORT(1'b1), `else .OPT_TRACE_PORT(1'b0), `endif .OPT_DISTRIBUTED_REGS(1), .EXTERNAL_INTERRUPTS(ZIP_INTS) // }}} ) swic( // {{{ .i_clk(i_clk), .i_reset(i_reset || i_cpu_reset), // Zipsys wishbone interface .o_wb_cyc(wbwide_zip_cyc), .o_wb_stb(wbwide_zip_stb), .o_wb_we(wbwide_zip_we), .o_wb_addr(wbwide_zip_addr[27-1:0]), .o_wb_data(wbwide_zip_data), // 128 bits wide .o_wb_sel(wbwide_zip_sel), // 128/8 bits wide .i_wb_stall(wbwide_zip_stall), .i_wb_ack(wbwide_zip_ack), .i_wb_data(wbwide_zip_idata), .i_wb_err(wbwide_zip_err), .i_ext_int(zip_int_vector), .o_ext_int(zip_cpu_int), // Debug wishbone interface .i_dbg_cyc(wbu_zip_cyc || cpu_sim_cyc), .i_dbg_stb(cpu_sim_cyc ? cpu_sim_stb : wbu_zip_stb), .i_dbg_we( cpu_sim_cyc ? cpu_sim_we : wbu_zip_we), .i_dbg_addr(cpu_sim_cyc? cpu_sim_addr : wbu_zip_addr[6:0]), .i_dbg_data (cpu_sim_cyc? cpu_sim_data : wbu_zip_data), .i_dbg_sel (cpu_sim_cyc? 4'hf : wbu_zip_sel), .o_dbg_stall(raw_cpu_dbg_stall), .o_dbg_ack (raw_cpu_dbg_ack), .o_dbg_data (wbu_zip_idata), // .o_cpu_debug(zip_debug), .o_prof_stb(cpu_prof_stb), .o_prof_addr(cpu_prof_addr), .o_prof_ticks(cpu_prof_ticks) // }}} ); assign zip_trigger = zip_debug[31]; assign wbu_zip_stall = cpu_sim_cyc || raw_cpu_dbg_stall; assign wbu_zip_ack = !cpu_sim_cyc && raw_cpu_dbg_ack; assign cpu_sim_stall = !cpu_sim_cyc || raw_cpu_dbg_stall; assign cpu_sim_ack = cpu_sim_cyc && raw_cpu_dbg_ack; assign cpu_sim_idata = wbu_zip_idata; // Keep Verilator happy // {{{ // Verilator lint_off UNUSED wire zip_unused; assign zip_unused = &{ 1'b0, alt_int_vector[7:0], sys_int_vector[5:0]}; // Verilator lint_on UNUSED // }}} // }}} // }}} `else // INCLUDE_ZIPCPU // {{{ // Null bus master // {{{ // }}} // Null bus slave // {{{ // // In the case that there is no wbu_zip peripheral // responding on the wbu bus assign wbu_zip_ack = 1'b0; assign wbu_zip_err = (wbu_zip_stb); assign wbu_zip_stall = 0; assign wbu_zip_idata = 0; // }}} // Null interrupt definitions // {{{ assign zip_cpu_int = 1'b0; // zip.INT.ZIP.WIRE // }}} // }}} `endif // INCLUDE_ZIPCPU // }}} endmodule // main.v ================================================ FILE: demo-out/main_tb.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: ../demo-out/main_tb.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Computer Generated: This file is computer generated by AUTOFPGA. DO NOT EDIT. // DO NOT EDIT THIS FILE! // // CmdLine: ./autofpga -d -o ../demo-out -I ../auto-data allclocks.txt bkram.txt buserr.txt clkcheck.txt crossbus.txt ddr3.txt edidslvscope.txt edid.txt exconsole.txt flashcfg.txt flash.txt global.txt gpio.txt gps.txt hdmi.txt i2ccpu.txt i2cdma.txt i2saudio.txt icape.txt meganet.txt mdio.txt pic.txt pwrcount.txt rtcdate.txt rtcgps.txt spio.txt sdio.txt vadj33.txt version.txt wboledbw.txt wbpmic.txt wbuarbiter.txt wbubus.txt zipcpu.txt zipmaster.txt // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} // // SIM.INCLUDE // // Any SIM.INCLUDE tags you define will be pasted here. // This is useful for guaranteeing any include functions // your simulation needs are called. // #include "verilated.h" #include "Vmain.h" #define BASECLASS Vmain #include "design.h" #include "regdefs.h" #include "testb.h" #include "flashsim.h" #include "dbluartsim.h" #include "uartsim.h" #include "hdmisource.h" #include "hdmisim.h" #include "byteswap.h" #include "netsim.h" #include "sdiosim.h" #include "enetctrlsim.h" #include "zipelf.h" // // SIM.DEFINES // // This tag is useful fr pasting in any #define values that // might then control the simulation following. // #ifndef VVAR #ifdef ROOT_VERILATOR #include "Vmain___024root.h" #define VVAR(A) rootp->main__DOT_ ## A #elif defined(NEW_VERILATOR) #define VVAR(A) main__DOT_ ## A #else #define VVAR(A) v__DOT_ ## A #endif #endif #define block_ram rootp->main__DOT__u_bkram__DOT__mem.m_storage //////////////////////////////////////////////////////////////////////////////// // // ZipCPU simulation defines // {{{ #ifndef VVAR #ifdef ROOT_VERILATOR #include "Vmain___024root.h" #define VVAR(A) rootp->main__DOT_ ## A #elif defined(NEW_VERILATOR) #define VVAR(A) main__DOT_ ## A #else #define VVAR(A) v__DOT_ ## A #endif #endif #define OPT_PIPELINED #define CPUVAR(A) VVAR(_swic__DOT__thecpu__DOT__core__DOT_ ## A) #define cpu_break VVAR(_swic__DOT__cpu_break) // }}} class MAINTB : public TESTB { public: // SIM.DEFNS // // If you have any simulation components, create a // SIM.DEFNS tag to have those components defined here // as part of the main_tb.cpp function. #ifdef FLASH_ACCESS FLASHSIM *m_flash; #endif // FLASH_ACCESS DBLUARTSIM *m_wbu; #ifdef GPSUART_ACCESS UARTSIM *m_gpsu; #endif // GPSUART_ACCESS #ifdef VIDPIPE_ACCESS HDMISOURCE *m_hdmirx; HDMIWIN *m_hdmitx; #endif // VIDPIPE_ACCESS NETSIM *m_net; SDIOSIM *m_sdio; #ifdef NETCTRL_ACCESS ENETCTRLSIM *m_mdio; #endif // NETCTRL_ACCESS int m_cpu_bombed; MAINTB(void) { // SIM.INIT // // If your simulation components need to be initialized, // create a SIM.INIT tag. That tag's value will be pasted // here. // // From flash #ifdef FLASH_ACCESS m_flash = new FLASHSIM(FLASHLGLEN, false, 2, 6); #endif // FLASH_ACCESS // From wbu m_wbu = new DBLUARTSIM(); m_wbu->setup(100); // From gpsu #ifdef GPSUART_ACCESS m_gpsu = new UARTSIM(FPGAPORT+2); m_gpsu->setup(0x000028b0); #endif // GPSUART_ACCESS // From hdmi #ifdef VIDPIPE_ACCESS m_hdmirx = NULL; m_hdmitx = NULL; if (gbl_use_gui) { m_hdmirx = new HDMISOURCE(800, 600); m_hdmitx = new HDMIWIN(800, 600); } #endif // VIDPIPE_ACCESS // From net // Network init // {{{ m_net = new NETSIM(); // DBGPORT: 6784, DATAPORT: 6785; m_net->external_mac[0] = 0xde; m_net->external_mac[1] = 0xad; m_net->external_mac[2] = 0xbe; m_net->external_mac[3] = 0xef; m_net->external_mac[4] = 0xda; m_net->external_mac[5] = 0xd0 | (200 & 0x0f); m_net->external_ip[0] = 127; m_net->external_ip[1] = 0; m_net->external_ip[2] = 0; m_net->external_ip[3] = 1; m_net->local_mac[0] = 0x82 & 0x0ff; m_net->local_mac[1] = 0x33 & 0x0ff; m_net->local_mac[2] = 0x48 & 0x0ff; m_net->local_mac[3] = 0x02 & 0x0ff; m_net->local_mac[4] = 0xe1 & 0x0ff; m_net->local_mac[5] = 0xc8 & 0x0ff; m_net->local_ip[0] = 0xc0 & 0x0ff; // 192 m_net->local_ip[1] = 0xa8 & 0x0ff; // 168 m_net->local_ip[2] = 0x0f & 0x0ff; // 15 m_net->local_ip[3] = 0x1d & 0x0ff; // 29 m_net->local_ipu = 0xc0a80f1d; // }}} // From sdio #ifdef SDIO_ACCESS m_sdio = new SDIOSIM("sdcard.img"); m_core->i_sdio_detect = 1; m_core->i_sdio_crcack = 0; m_core->i_sdio_crcnak = 0; #endif // From mdio #ifdef NETCTRL_ACCESS m_mdio = new ENETCTRLSIM; #endif // NETCTRL_ACCESS // From zip m_cpu_bombed = 0; } void reset(void) { // SIM.SETRESET // If your simulation component needs logic before the // tick with reset set, that logic can be placed into // the SIM.SETRESET tag and thus pasted here. // m_core->i_cpu_reset = 1; TESTB::reset(); // SIM.CLRRESET // If your simulation component needs logic following the // reset tick, that logic can be placed into the // SIM.CLRRESET tag and thus pasted here. // m_core->i_cpu_reset = 0; } void trace(const char *vcd_trace_file_name) { fprintf(stderr, "Opening TRACE(%s)\n", vcd_trace_file_name); opentrace(vcd_trace_file_name); m_time_ps = 0; } void close(void) { m_done = true; } void tick(void) { TESTB::tick(); // Clock.size = 4 } // Evaluating clock clk // sim_clk_tick() will be called from TESTB::tick() // following any falling edge of clock clk virtual void sim_clk_tick(void) { // Default clock tick // // SIM.TICK tags go here for SIM.CLOCK=clk // // SIM.TICK from flash #ifdef FLASH_ACCESS m_core->i_flash_dat = m_flash->simtick( m_core->o_flash_cs_n, m_core->o_flash_sck, m_core->o_flash_dat, m_core->o_flash_mod); #endif // FLASH_ACCESS // SIM.TICK from i2c m_core->i_i2c_scl = m_core->o_i2c_scl; m_core->i_i2c_sda = m_core->o_i2c_sda; // SIM.TICK from wbu m_core->i_wbu_uart_rx = (*m_wbu)(m_core->o_wbu_uart_tx); // SIM.TICK from edid m_core->i_edid_scl = m_core->o_edid_scl; m_core->i_edid_sda = m_core->o_edid_sda; // SIM.TICK from pxclk m_core->i_pxclk_stall = 0; m_core->i_pxclk_ack = m_core->o_pxclk_stb; m_core->i_pxclk_idata = m_core->o_pxclk_data; // SIM.TICK from sdio #ifdef SDIO_ACCESS { unsigned tmp, tmp_async; m_sdio->apply( (unsigned)m_core->o_sdio_sdclk, (unsigned)m_core->o_sdio_cfg_ddr, (unsigned)m_core->o_sdio_cmd_en, (unsigned)m_core->o_sdio_cmd_data, (unsigned)m_core->o_sdio_data_en, (unsigned)m_core->o_sdio_rx_en, (unsigned)m_core->o_sdio_tx_data, tmp, tmp_async, m_core->i_sdio_ad_data); m_core->i_sdio_cmd_strb = (tmp >> 30) & 3; m_core->i_sdio_cmd_data = (tmp >> 28) & 3; m_core->i_sdio_rx_strb = (tmp >> 24) & 3; m_core->i_sdio_rx_data = tmp & 0x0ffff; m_core->i_sdio_ac_valid = (tmp_async & 2) ? 1:0; m_core->i_sdio_ad_valid = tmp_async & 1; m_core->i_sdio_detect = 1; m_core->i_sdio_card_busy = m_sdio->card_busy() ? 1:0; m_core->i_sdio_crcack = m_sdio->crctoken(); m_core->i_sdio_crcnak = (m_core->i_sdio_crcack & 2)?1:0; m_core->i_sdio_crcack &= 1; if (!m_core->o_sdio_cfg_dscmd) { m_core->i_sdio_ac_valid = 0; m_core->i_sdio_ac_data = 0; } if (!m_core->o_sdio_cfg_ds) { m_core->i_sdio_ad_valid = 0; m_core->i_sdio_ad_data = 0; } } #endif // SIM.TICK from mdio #ifdef NETCTRL_ACCESS m_core->i_mdio = (*m_mdio)((m_core->i_reset)?1:0, m_core->o_mdclk, ((m_core->o_mdwe)&&(!m_core->o_mdio))?0:1); #else m_core->i_mdio = ((m_core->o_mdwe)&&(!m_core->o_mdio))?0:1; #endif // NETCTRL_ACCESS // SIM.TICK from zip #ifdef INCLUDE_ZIPCPU // ZipCPU Sim instruction support // {{{ if (m_cpu_bombed) { if (m_cpu_bombed++ > 12) m_done = true; } else if (m_core->cpu_break) { printf("\n\nBOMB : CPU BREAK RECEIVED\n"); m_cpu_bombed++; } // }}} #endif // INCLUDE_ZIPCPU } // Evaluating clock pixclk // sim_pixclk_tick() will be called from TESTB::tick() // following any falling edge of clock pixclk virtual void sim_pixclk_tick(void) { // // SIM.TICK tags go here for SIM.CLOCK=pixclk // // SIM.TICK from hdmi #ifdef VIDPIPE_ACCESS // Simulate both an external HDMI source and monitor if (gbl_use_gui) { int r, g, b; // HDMI input received by the design (*m_hdmirx)(b, g, r); m_core->i_hdmi_blu = b; m_core->i_hdmi_grn = g; m_core->i_hdmi_red = r; m_core->i_pxpll_locked = 1; // HDMI output, transmitted from the design (*m_hdmitx)(m_core->o_hdmi_blu, m_core->o_hdmi_grn, m_core->o_hdmi_red); } #endif // VIDPIPE_ACCESS } // Evaluating clock net_rx_clk // sim_net_rx_clk_tick() will be called from TESTB::tick() // following any falling edge of clock net_rx_clk virtual void sim_net_rx_clk_tick(void) { // // SIM.TICK tags go here for SIM.CLOCK=net_rx_clk // // SIM.TICK from net // Simulate the network // {{{ { unsigned rxtmp = (*m_net)(m_core->o_net_reset_n, m_core->o_net_tx_ctl, m_core->o_net_txd); m_core->i_net_rx_err = 0; if (rxtmp & 0x0100) { m_core->i_net_rx_dv = 1; m_core->i_net_rxd = rxtmp & 0x0ff; } else { m_core->i_net_rx_dv = 0; m_core->i_net_rxd = 0x044; } } // }}} } // Evaluating clock clk_125mhz // sim_clk_125mhz_tick() will be called from TESTB::tick() // following any falling edge of clock clk_125mhz virtual void sim_clk_125mhz_tick(void) { // // SIM.TICK tags go here for SIM.CLOCK=clk_125mhz // // No SIM.TICK tags defined m_changed = false; } // // Step until clock clk ticks // virtual void tick_clk(void) { // Advance until the default clock ticks do { tick(); } while(!m_clk.rising_edge()); } // // Step until clock pixclk ticks // virtual void tick_pixclk(void) { do { tick(); } while(!m_pixclk.rising_edge()); } // // Step until clock net_rx_clk ticks // virtual void tick_net_rx_clk(void) { do { tick(); } while(!m_net_rx_clk.rising_edge()); } // // Step until clock clk_125mhz ticks // virtual void tick_clk_125mhz(void) { do { tick(); } while(!m_clk_125mhz.rising_edge()); } // // The load function // // This function is required by designs that need the flash or memory // set prior to run time. The test harness should be able to call // this function to load values into any (memory-type) location // on the bus. // bool load(uint32_t addr, const char *buf, uint32_t len) { uint32_t start, offset, wlen, base, adrln; // // Loading the flash component // base = 0x01000000; // in octets adrln = 0x01000000; if ((addr >= base)&&(addr < base + adrln)) { // If the start access is in flash start = (addr > base) ? (addr-base) : 0; offset = (start + base) - addr; wlen = (len-offset > adrln - start) ? (adrln - start) : len - offset; #ifdef FLASH_ACCESS // FROM flash.SIM.LOAD m_flash->load(start, &buf[offset], wlen); // AUTOFPGA::Now clean up anything else // Was there more to write than we wrote? if (addr + len > base + adrln) return load(base + adrln, &buf[offset+wlen], len-wlen); return true; #else // FLASH_ACCESS return false; #endif // FLASH_ACCESS // // End of components with a SIM.LOAD tag, and a // non-zero number of addresses (NADDR) // } // // Loading the bkram component // base = 0x10000000; // in octets adrln = 0x00100000; if ((addr >= base)&&(addr < base + adrln)) { // If the start access is in bkram start = (addr > base) ? (addr-base) : 0; offset = (start + base) - addr; wlen = (len-offset > adrln - start) ? (adrln - start) : len - offset; #ifdef BKRAM_ACCESS // FROM bkram.SIM.LOAD start = start & (-4); wlen = (wlen+3)&(-4); // Need to byte swap data to get it into the memory if (128 == 32) { char *bswapd = new char[len+8]; memcpy(bswapd, &buf[offset], wlen); byteswapbuf(len>>2, (uint32_t *)bswapd); memcpy(&m_core->block_ram[start], bswapd, wlen); delete[] bswapd; } else { for(unsigned jk=0; jkblock_ram[word_addr]; cp = (char *)wp; subword_addr = start+jk; subword_addr = ~subword_addr; subword_addr &= 128/8-1; // subword_addr = 128/8-subword_addr; cp[subword_addr] = buf[offset+jk]; } } // AUTOFPGA::Now clean up anything else // Was there more to write than we wrote? if (addr + len > base + adrln) return load(base + adrln, &buf[offset+wlen], len-wlen); return true; #else // BKRAM_ACCESS return false; #endif // BKRAM_ACCESS // // End of components with a SIM.LOAD tag, and a // non-zero number of addresses (NADDR) // } return false; } // // KYSIM.METHODS // // If your simulation code will need to call any of its own function // define this tag by those functions (or other sim code), and // it will be pasated here. // void connect_idler(void) { Glib::signal_idle().connect( sigc::mem_fun((*this),&MAINTB::on_tick)); } bool on_tick(void) { for(int i=0; i<15; i++) tick(); return true; } #ifdef INCLUDE_ZIPCPU // ZipCPU Access functions // {{{ void loadelf(const char *elfname) { // {{{ ELFSECTION **secpp, *secp; uint32_t entry; elfread(elfname, entry, secpp); for(int s=0; secpp[s]->m_len; s++) { bool successful_load; secp = secpp[s]; successful_load = load(secp->m_start, secp->m_data, secp->m_len); if (!successful_load) { printf("Could not load section " "from %08x to %08x--no such address\n", secp->m_start, secp->m_start+secp->m_len); } } free(secpp); } // }}} void cpu_dbg_write(const uint32_t addr, const uint32_t data) { // {{{ // printf("CPU-DBG-WRITE(@0x%08x, 0x%08x);\n", addr, data); m_core->cpu_sim_cyc = 1; m_core->cpu_sim_stb = 1; m_core->cpu_sim_we = 1; m_core->cpu_sim_addr = addr >> 2; m_core->cpu_sim_data = data; do { tick_clk(); } while(m_core->cpu_sim_stall); m_core->cpu_sim_stb = 0; while(!m_core->cpu_sim_ack) tick_clk(); m_core->cpu_sim_cyc = 0; m_core->cpu_sim_we = 0; m_core->cpu_sim_addr = 0; m_core->cpu_sim_data = 0; tick_clk(); } // }}} uint32_t cpu_dbg_read(const uint32_t addr) { // {{{ unsigned result; // printf("CPU-DBG-WRITE(@0x%08x, 0x%08x);\n", addr, data); m_core->cpu_sim_cyc = 1; m_core->cpu_sim_stb = 1; m_core->cpu_sim_we = 0; m_core->cpu_sim_addr = addr >> 2; m_core->cpu_sim_data = 0; do { tick_clk(); } while(m_core->cpu_sim_stall); m_core->cpu_sim_stb = 0; while(!m_core->cpu_sim_ack) tick_clk(); result = m_core->cpu_sim_idata; m_core->cpu_sim_cyc = 0; m_core->cpu_sim_we = 0; m_core->cpu_sim_addr = 0; m_core->cpu_sim_data = 0; tick_clk(); return result; } // }}} // }}} #endif // INCLUDE_ZIPCPU }; ================================================ FILE: demo-out/regdefs.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: ../demo-out/regdefs.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Computer Generated: This file is computer generated by AUTOFPGA. DO NOT EDIT. // DO NOT EDIT THIS FILE! // // CmdLine: ./autofpga -d -o ../demo-out -I ../auto-data allclocks.txt bkram.txt buserr.txt clkcheck.txt crossbus.txt ddr3.txt edidslvscope.txt edid.txt exconsole.txt flashcfg.txt flash.txt global.txt gpio.txt gps.txt hdmi.txt i2ccpu.txt i2cdma.txt i2saudio.txt icape.txt meganet.txt mdio.txt pic.txt pwrcount.txt rtcdate.txt rtcgps.txt spio.txt sdio.txt vadj33.txt version.txt wboledbw.txt wbpmic.txt wbuarbiter.txt wbubus.txt zipcpu.txt zipmaster.txt // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include "regdefs.h" const REGNAME raw_bregs[] = { { R_SDIO_CTRL , "SDCARD" }, { R_SDIO_DATA , "SDDATA" }, { R_SDIO_FIFOA , "SDFIFOA" }, { R_SDIO_FIFOA , "SDFIF0" }, { R_SDIO_FIFOA , "SDFIFA" }, { R_SDIO_FIFOB , "SDFIFOB" }, { R_SDIO_FIFOB , "SDFIF1" }, { R_SDIO_FIFOB , "SDFIFB" }, { R_SDIO_PHY , "SDPHY" }, { R_FLASH , "FLASH" }, { R_FLASHCFG , "FLASHCFG" }, { R_FLASHCFG , "QSPIC" }, { R_EDIDSLVSCOPE , "EDIDSLVSCOPE" }, { R_EDIDSLVSCOPED , "EDIDSLVSCOPED" }, { R_MIC_DATA , "MICD" }, { R_MIC_CTRL , "MICC" }, { R_GPSU_SETUP , "GPSSETUP" }, { R_GPSU_FIFO , "GPSFIFO" }, { R_GPSU_UARTRX , "GPSRX" }, { R_GPSU_UARTTX , "GPSTX" }, { R_CFG_CRC , "FPGACRC" }, { R_CFG_FAR , "FPGAFAR" }, { R_CFG_FDRI , "FPGAFDRI" }, { R_CFG_FDRO , "FPGAFDRO" }, { R_CFG_CMD , "FPGACMD" }, { R_CFG_CTL0 , "FPGACTL0" }, { R_CFG_MASK , "FPGAMASK" }, { R_CFG_STAT , "FPGASTAT" }, { R_CFG_LOUT , "FPGALOUT" }, { R_CFG_COR0 , "FPGACOR0" }, { R_CFG_MFWR , "FPGAMFWR" }, { R_CFG_CBC , "FPGACBC" }, { R_CFG_IDCODE , "FPGAIDCODE" }, { R_CFG_AXSS , "FPGAAXSS" }, { R_CFG_COR1 , "FPGACOR1" }, { R_CFG_WBSTAR , "WBSTAR" }, { R_CFG_TIMER , "CFGTIMER" }, { R_CFG_BOOTSTS , "BOOTSTS" }, { R_CFG_CTL1 , "FPGACTL1" }, { R_CFG_BSPI , "FPGABSPI" }, { R_MEGANET_RXCMD , "MEGANETRX" }, { R_MEGANET_TXCMD , "MEGANETTX" }, { R_MEGANET_MACHI , "MEGANETMACHI" }, { R_MEGANET_MACLO , "MEGANETMACLO" }, { R_MEGANET_IPADDR , "MEGANETIPADDR" }, { R_MEGANET_IPADDR , "MEGANETIP" }, { R_MEGANET_RXMISS , "MEGANETMISS" }, { R_MEGANET_RXERR , "MEGANETERR" }, { R_MEGANET_RXCRC , "MEGANETCRCER" }, { R_MEGANET_DBGSEL , "MEGANETDBGSL" }, { R_MEGANET_RXPKTS , "MEGANETRXPKT" }, { R_MEGANET_ARPRX , "MEGANETARPRX" }, { R_MEGANET_ICMPRX , "MEGANETICMRX" }, { R_MEGANET_TXPKTS , "MEGANETTXPKT" }, { R_MEGANET_ARPTX , "MEGANETARPTX" }, { R_MEGANET_ICMPTX , "MEGANETICMTX" }, { R_MEGANET_DATATX , "MEGANETDATTX" }, { R_MEGANET_TXABORTS, "MEGANETABRTS" }, { R_MEGANET_DBGRX , "MEGANETDBGRX" }, { R_MEGANET_DBGTX , "MEGANETDBGTX" }, { R_DDR3_PHY , "DDR3_PHY" }, { R_DDR3_PHY , "DPHYSTAT0" }, { R_DDR3_PHYSTAT1 , "DDR3_PHYSTAT1" }, { R_DDR3_PHYSTAT1 , "DPHYSTAT1" }, { R_DDR3_PHYSTAT2 , "DDR3_PHYSTAT2" }, { R_DDR3_PHYSTAT2 , "DPHYSTAT2" }, { R_DDR3_PHYSTAT3 , "DDR3_PHYSTAT3" }, { R_DDR3_PHYSTAT3 , "DPHYSTAT3" }, { R_DDR3_PHYCTRLSTAT, "DDR3_PHYCTRLSTAT" }, { R_DDR3_PHYCTRLSTAT, "DCTRLSTAT" }, { R_DDR3_PHYRESET , "DDR3_PHYRESET" }, { R_DDR3_PHYRESET , "DCTRLRESET" }, { R_DDR3_PHYDBGSEL , "DDR3_PHYDBGSEL" }, { R_DDR3_PHYDBGSEL , "DCTRLDBG" }, { R_PXPLL , "PXPLL" }, { R_EDID , "EDID" }, { R_EDID , "EDID_CTRL" }, { R_EDID , "EDIDCTRL" }, { R_EDID_OVW , "EDID_OVW" }, { R_EDID_OVW , "EDID_OVERRIDE" }, { R_EDID_ADDR , "EDID_ADDR" }, { R_EDID_ADDR , "EDID_ADDRESS" }, { R_EDID_CKCOUNT , "EDIDCLK" }, { R_EDID_CKCOUNT , "EDID_CKCOUNT" }, { R_GPS_ALPHA , "ALPHA" }, { R_GPS_BETA , "BETA" }, { R_GPS_GAMMA , "GAMMA" }, { R_GPS_STEP , "STEP" }, { R_I2CCPU , "I2CCPU" }, { R_I2CCPU , "I2CCPU_CTRL" }, { R_I2CCPU , "I2CCPUCTRL" }, { R_I2CCPU_OVW , "I2CCPU_OVW" }, { R_I2CCPU_OVW , "I2CCPU_OVERRIDE" }, { R_I2CCPU_ADDR , "I2CCPU_ADDR" }, { R_I2CCPU_ADDR , "I2CCPU_ADDRESS" }, { R_I2CCPU_CKCOUNT , "I2CCPUCLK" }, { R_I2CCPU_CKCOUNT , "I2CCPU_CKCOUNT" }, { R_I2CDMA , "I2CDMA" }, { R_I2CDMA_ADDR , "I2CDMAADDR" }, { R_I2CDMA_BASE , "I2CDMABASE" }, { R_I2CDMA_LEN , "I2CDMALEN" }, { R_OLED , "OLED" }, { R_OLED_OV , "OLEDOV" }, { R_OLED_ADDR , "OLEDADDR" }, { R_OLED_CLK , "OLEDCLK" }, { R_CLOCK , "CLOCK" }, { R_TIMER , "TIMER" }, { R_STOPWATCH , "STOPWATCH" }, { R_CKALARM , "ALARM" }, { R_CKALARM , "CKALARM" }, { R_GPSTB_FREQ , "GPSFREQ" }, { R_GPSTB_JUMP , "GPSJUMP" }, { R_GPSTB_ERRHI , "ERRHI" }, { R_GPSTB_ERRLO , "ERRLO" }, { R_GPSTB_COUNTHI , "CNTHI" }, { R_GPSTB_COUNTLO , "CNTLO" }, { R_GPSTB_STEPHI , "STEPHI" }, { R_GPSTB_STEPLO , "STEPLO" }, { R_ADCCLK , "ADCCLK" }, { R_BUILDTIME , "BUILDTIME" }, { R_BUILDTIME , "BUILDTIME" }, { R_BUSERR , "BUSERR" }, { R_PIC , "PIC" }, { R_GPIO , "GPIO" }, { R_GPIO , "GPI" }, { R_GPIO , "GPO" }, { R_PWRCOUNT , "PWRCOUNT" }, { R_RTCDATE , "RTCDATE" }, { R_RTCDATE , "DATE" }, { R_RXETH0CK , "RXETH0CK" }, { R_SPIO , "SPIO" }, { R_SUBSECONDS , "SUBSECONDS" }, { R_TXCLK , "TXCLK" }, { R_VERSION , "VERSION" }, { R_EDIDRX , "EDIDRX" }, { R_VIDPIPE , "VIDPIPE" }, { R_VIDPIPE , "VIDCTRL" }, { R_HDMIFREQ , "HDMIFREQ" }, { R_SIFREQ , "SIFREQ" }, { R_PXFREQ , "PXFREQ" }, { R_INSIZE , "INSIZE" }, { R_INPORCH , "INPORCH" }, { R_INSYNC , "INSYNC" }, { R_INRAW , "INRAW" }, { R_HDMISIZE , "HDMISIZE" }, { R_HDMIPORCH , "HDMIPORCH" }, { R_HDMISYNC , "HDMISYNC" }, { R_HDMIRAW , "HDMIRAW" }, { R_OVADDR , "OVADDR" }, { R_OVSIZE , "OVSIZE" }, { R_OVOFFSET , "OVOFFSET" }, { R_FPS , "FPS" }, { R_CAPTURE , "VCAPTURE" }, { R_CAPBASE , "VCAPBASE" }, { R_CAPWORDS , "VCAPWORDS" }, { R_CAPPOSN , "VCAPPOSN" }, { R_CAPSIZE , "VCAPSIZE" }, { R_SYNCWORD , "VSYNCWORD" }, { R_CMAP , "CMAP" }, { R_MDIO_BMCR , "BMCR" }, { R_MDIO_BMSR , "BMSR" }, { R_MDIO_PHYIDR1 , "PHYIDR1" }, { R_MDIO_PHYIDR2 , "PHYIDR2" }, { R_MDIO_ANAR , "ANAR" }, { R_MDIO_ANLPAR , "ANLPAR" }, { R_MDIO_ANER , "ANER" }, { R_MDIO_ANNPTR , "ANNPTR" }, { R_MDIO_ANNPRR , "ANNPRR" }, { R_MDIO_GBCR , "GBCR" }, { R_MDIO_GBSR , "GBSR" }, { R_MDIO_MACR , "MACR" }, { R_MDIO_MAADR , "MAADR" }, { R_MDIO_GBESR , "GBESR" }, { R_MDIO_PHYCR , "PHYCR" }, { R_MDIO_PHYSR , "PHYSR" }, { R_MDIO_INER , "INER" }, { R_MDIO_INSR , "INSR" }, { R_MDIO_RXERC , "RXERC" }, { R_MDIO_LDPSR , "LDPSR" }, { R_MDIO_EPAGSR , "EPAGSR" }, { R_MDIO_PAGSEL , "PAGSEL" }, { R_XMDIO_PC1R , "XPC1R" }, { R_XMDIO_PS1R , "XPS1R" }, { R_XMDIO_EEECR , "XEEECR" }, { R_XMDIO_EEEWER , "XEEEWER" }, { R_XMDIO_EEEAR , "XEEEAR" }, { R_XMDIO_EEELPAR , "XEEELPAR" }, { R_XMDIO_LACR , "XLACR" }, { R_XMDIO_LCR , "XLCR" }, { R_BKRAM , "RAM" }, { R_SDRAM , "SDRAM" }, { R_ZIPCTRL , "CPU" }, { R_ZIPCTRL , "ZIPCTRL" }, { R_ZIPREGS , "ZIPREGS" }, { R_ZIPS0 , "SR0" }, { R_ZIPS1 , "SR1" }, { R_ZIPS2 , "SR2" }, { R_ZIPS3 , "SR3" }, { R_ZIPS4 , "SR4" }, { R_ZIPS5 , "SR5" }, { R_ZIPS6 , "SR6" }, { R_ZIPS7 , "SR7" }, { R_ZIPS8 , "SR8" }, { R_ZIPS9 , "SR9" }, { R_ZIPS10 , "SR10" }, { R_ZIPS11 , "SR11" }, { R_ZIPS12 , "SR12" }, { R_ZIPSSP , "SSP" }, { R_ZIPSSP , "SR13" }, { R_ZIPCC , "ZIPCC" }, { R_ZIPCC , "CC" }, { R_ZIPCC , "SCC" }, { R_ZIPCC , "SR14" }, { R_ZIPPC , "ZIPPC" }, { R_ZIPPC , "PC" }, { R_ZIPPC , "SPC" }, { R_ZIPPC , "SR15" }, { R_ZIPUSER , "ZIPUSER" }, { R_ZIPU0 , "UR0" }, { R_ZIPU1 , "UR1" }, { R_ZIPU2 , "UR2" }, { R_ZIPU3 , "UR3" }, { R_ZIPU4 , "UR4" }, { R_ZIPU5 , "UR5" }, { R_ZIPU6 , "UR6" }, { R_ZIPU7 , "UR7" }, { R_ZIPU8 , "UR8" }, { R_ZIPU9 , "UR9" }, { R_ZIPU10 , "SR10" }, { R_ZIPU11 , "SR11" }, { R_ZIPU12 , "SR12" }, { R_ZIPUSP , "USP" }, { R_ZIPUSP , "UR13" }, { R_ZIPUCC , "ZIPUCC" }, { R_ZIPUCC , "UCC" }, { R_ZIPUPC , "ZIPUPC" }, { R_ZIPUPC , "UPC" }, { R_ZIPSYSTEM , "ZIPSYSTEM" }, { R_ZIPSYSTEM , "ZIPSYS" }, { R_ZIPWATCHDOG , "ZIPWATCHDOG" }, { R_ZIPBUSDOG , "BUSDOG" }, { R_ZIPAPIC , "ZIPAPIC" }, { R_ZIPAPIC , "ALTPIC" }, { R_ZIPTIMERA , "ZIPTMA" }, { R_ZIPTIMERA , "ZIPTIMERA" }, { R_ZIPTIMERB , "ZIPTMB" }, { R_ZIPTIMERB , "ZIPTIMERB" }, { R_ZIPTIMERC , "ZIPTMC" }, { R_ZIPTIMERC , "ZIPTIMERC" }, { R_ZIPJIFFIES , "ZIPJIFF" }, { R_ZIPMTASK , "ZIPMTASK" }, { R_ZIPMSTALL , "ZIPMSTALL" }, { R_ZIPMPSTAL , "ZIPMPSTAL" }, { R_ZIPMINSN , "ZIPMINSN" }, { R_ZIPUTASK , "ZIPUTASK" }, { R_ZIPUSTALL , "ZIPUSTALL" }, { R_ZIPUPSTAL , "ZIPUPSTAL" }, { R_ZIPUINSN , "ZIPUINSN" }, { R_ZIPUDMAC , "ZIPDMAC" } }; // REGSDEFS.CPP.INSERT for any bus masters // And then from the peripherals // And finally any master REGS.CPP.INSERT tags #define RAW_NREGS (sizeof(raw_bregs)/sizeof(bregs[0])) const REGNAME *bregs = raw_bregs; const int NREGS = RAW_NREGS; unsigned addrdecode(const char *v) { if (isalpha(v[0])) { for(int i=0; i for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef REGDEFS_H #define REGDEFS_H // // The @REGDEFS.H.INCLUDE tag // // @REGDEFS.H.INCLUDE for masters // @REGDEFS.H.INCLUDE for peripherals #ifndef FPGAPORT #define FPGAPORT 6782 #define UARTDBGPORT 6782 #define UARTPORT 6783 #define UDP_DBGPORT 6784 #define UDP_DATAPORT 6785 #endif // And finally any master REGDEFS.H.INCLUDE tags // End of definitions from REGDEFS.H.INCLUDE // // Register address definitions, from @REGS.#d // // SDIO SD Card addresses #define R_SDIO_CTRL 0x00800000 // 00800000, wbregs names: SDCARD #define R_SDIO_DATA 0x00800004 // 00800000, wbregs names: SDDATA #define R_SDIO_FIFOA 0x00800008 // 00800000, wbregs names: SDFIFOA, SDFIF0, SDFIFA #define R_SDIO_FIFOB 0x0080000c // 00800000, wbregs names: SDFIFOB, SDFIF1, SDFIFB #define R_SDIO_PHY 0x00800010 // 00800000, wbregs names: SDPHY #define R_FLASH 0x01000000 // 01000000, wbregs names: FLASH // FLASH erase/program configuration registers #define R_FLASHCFG 0x08000400 // 08000400, wbregs names: FLASHCFG, QSPIC // edidslvscope compressed scope #define R_EDIDSLVSCOPE 0x08000600 // 08000600, wbregs names: EDIDSLVSCOPE #define R_EDIDSLVSCOPED 0x08000604 // 08000600, wbregs names: EDIDSLVSCOPED // WB-Microphone registers #define R_MIC_DATA 0x08000800 // 08000800, wbregs names: MICD #define R_MIC_CTRL 0x08000804 // 08000800, wbregs names: MICC // GPS UART registers, similar to WBUART #define R_GPSU_SETUP 0x08000a00 // 08000a00, wbregs names: GPSSETUP #define R_GPSU_FIFO 0x08000a04 // 08000a00, wbregs names: GPSFIFO #define R_GPSU_UARTRX 0x08000a08 // 08000a00, wbregs names: GPSRX #define R_GPSU_UARTTX 0x08000a0c // 08000a00, wbregs names: GPSTX // FPGA CONFIG REGISTERS: 0x4e0-0x4ff #define R_CFG_CRC 0x08000c00 // 08000c00, wbregs names: FPGACRC #define R_CFG_FAR 0x08000c04 // 08000c00, wbregs names: FPGAFAR #define R_CFG_FDRI 0x08000c08 // 08000c00, wbregs names: FPGAFDRI #define R_CFG_FDRO 0x08000c0c // 08000c00, wbregs names: FPGAFDRO #define R_CFG_CMD 0x08000c10 // 08000c00, wbregs names: FPGACMD #define R_CFG_CTL0 0x08000c14 // 08000c00, wbregs names: FPGACTL0 #define R_CFG_MASK 0x08000c18 // 08000c00, wbregs names: FPGAMASK #define R_CFG_STAT 0x08000c1c // 08000c00, wbregs names: FPGASTAT #define R_CFG_LOUT 0x08000c20 // 08000c00, wbregs names: FPGALOUT #define R_CFG_COR0 0x08000c24 // 08000c00, wbregs names: FPGACOR0 #define R_CFG_MFWR 0x08000c28 // 08000c00, wbregs names: FPGAMFWR #define R_CFG_CBC 0x08000c2c // 08000c00, wbregs names: FPGACBC #define R_CFG_IDCODE 0x08000c30 // 08000c00, wbregs names: FPGAIDCODE #define R_CFG_AXSS 0x08000c34 // 08000c00, wbregs names: FPGAAXSS #define R_CFG_COR1 0x08000c38 // 08000c00, wbregs names: FPGACOR1 #define R_CFG_WBSTAR 0x08000c40 // 08000c00, wbregs names: WBSTAR #define R_CFG_TIMER 0x08000c44 // 08000c00, wbregs names: CFGTIMER #define R_CFG_BOOTSTS 0x08000c58 // 08000c00, wbregs names: BOOTSTS #define R_CFG_CTL1 0x08000c60 // 08000c00, wbregs names: FPGACTL1 #define R_CFG_BSPI 0x08000c7c // 08000c00, wbregs names: FPGABSPI // Meganet register definitions #define R_MEGANET_RXCMD 0x08000e00 // 08000e00, wbregs names: MEGANETRX #define R_MEGANET_TXCMD 0x08000e04 // 08000e00, wbregs names: MEGANETTX #define R_MEGANET_MACHI 0x08000e08 // 08000e00, wbregs names: MEGANETMACHI #define R_MEGANET_MACLO 0x08000e0c // 08000e00, wbregs names: MEGANETMACLO #define R_MEGANET_IPADDR 0x08000e10 // 08000e00, wbregs names: MEGANETIPADDR, MEGANETIP #define R_MEGANET_RXMISS 0x08000e14 // 08000e00, wbregs names: MEGANETMISS #define R_MEGANET_RXERR 0x08000e18 // 08000e00, wbregs names: MEGANETERR #define R_MEGANET_RXCRC 0x08000e1c // 08000e00, wbregs names: MEGANETCRCER #define R_MEGANET_DBGSEL 0x08000e20 // 08000e00, wbregs names: MEGANETDBGSL #define R_MEGANET_RXPKTS 0x08000e20 // 08000e00, wbregs names: MEGANETRXPKT #define R_MEGANET_ARPRX 0x08000e24 // 08000e00, wbregs names: MEGANETARPRX #define R_MEGANET_ICMPRX 0x08000e28 // 08000e00, wbregs names: MEGANETICMRX #define R_MEGANET_TXPKTS 0x08000e2c // 08000e00, wbregs names: MEGANETTXPKT #define R_MEGANET_ARPTX 0x08000e30 // 08000e00, wbregs names: MEGANETARPTX #define R_MEGANET_ICMPTX 0x08000e34 // 08000e00, wbregs names: MEGANETICMTX #define R_MEGANET_DATATX 0x08000e38 // 08000e00, wbregs names: MEGANETDATTX #define R_MEGANET_TXABORTS 0x08000e3c // 08000e00, wbregs names: MEGANETABRTS #define R_MEGANET_DBGRX 0x08000e40 // 08000e00, wbregs names: MEGANETDBGRX #define R_MEGANET_DBGTX 0x08000e44 // 08000e00, wbregs names: MEGANETDBGTX #define R_DDR3_PHY 0x08001000 // 08001000, wbregs names: DDR3_PHY, DPHYSTAT0 #define R_DDR3_PHYSTAT1 0x08001004 // 08001000, wbregs names: DDR3_PHYSTAT1, DPHYSTAT1 #define R_DDR3_PHYSTAT2 0x08001008 // 08001000, wbregs names: DDR3_PHYSTAT2, DPHYSTAT2 #define R_DDR3_PHYSTAT3 0x0800100c // 08001000, wbregs names: DDR3_PHYSTAT3, DPHYSTAT3 #define R_DDR3_PHYCTRLSTAT 0x08001010 // 08001000, wbregs names: DDR3_PHYCTRLSTAT, DCTRLSTAT #define R_DDR3_PHYRESET 0x08001044 // 08001000, wbregs names: DDR3_PHYRESET, DCTRLRESET #define R_DDR3_PHYDBGSEL 0x0800104c // 08001000, wbregs names: DDR3_PHYDBGSEL, DCTRLDBG // HDMI pixel clock PLL reconfiguration port #define R_PXPLL 0x08001200 // 08001200, wbregs names: PXPLL // I2C Controller registers #define R_EDID 0x08001400 // 08001400, wbregs names: EDID, EDID_CTRL, EDIDCTRL #define R_EDID_OVW 0x08001404 // 08001400, wbregs names: EDID_OVW, EDID_OVERRIDE #define R_EDID_ADDR 0x08001408 // 08001400, wbregs names: EDID_ADDR, EDID_ADDRESS #define R_EDID_CKCOUNT 0x0800140c // 08001400, wbregs names: EDIDCLK, EDID_CKCOUNT // GPS clock tracker, control loop settings registers #define R_GPS_ALPHA 0x08001410 // 08001410, wbregs names: ALPHA #define R_GPS_BETA 0x08001414 // 08001410, wbregs names: BETA #define R_GPS_GAMMA 0x08001418 // 08001410, wbregs names: GAMMA #define R_GPS_STEP 0x0800141c // 08001410, wbregs names: STEP // I2C Controller registers #define R_I2CCPU 0x08001420 // 08001420, wbregs names: I2CCPU, I2CCPU_CTRL, I2CCPUCTRL #define R_I2CCPU_OVW 0x08001424 // 08001420, wbregs names: I2CCPU_OVW, I2CCPU_OVERRIDE #define R_I2CCPU_ADDR 0x08001428 // 08001420, wbregs names: I2CCPU_ADDR, I2CCPU_ADDRESS #define R_I2CCPU_CKCOUNT 0x0800142c // 08001420, wbregs names: I2CCPUCLK, I2CCPU_CKCOUNT #define R_I2CDMA 0x08001430 // 08001430, wbregs names: I2CDMA #define R_I2CDMA_ADDR 0x08001434 // 08001430, wbregs names: I2CDMAADDR #define R_I2CDMA_BASE 0x08001438 // 08001430, wbregs names: I2CDMABASE #define R_I2CDMA_LEN 0x0800143c // 08001430, wbregs names: I2CDMALEN #define R_OLED 0x08001440 // 08001440, wbregs names: OLED #define R_OLED_OV 0x08001444 // 08001440, wbregs names: OLEDOV #define R_OLED_ADDR 0x08001448 // 08001440, wbregs names: OLEDADDR #define R_OLED_CLK 0x0800144c // 08001440, wbregs names: OLEDCLK // RTC clock registers #define R_CLOCK 0x08001450 // 08001450, wbregs names: CLOCK #define R_TIMER 0x08001454 // 08001450, wbregs names: TIMER #define R_STOPWATCH 0x08001458 // 08001450, wbregs names: STOPWATCH #define R_CKALARM 0x0800145c // 08001450, wbregs names: ALARM, CKALARM // GPS clock test bench registers, for measuring the clock trackers performance #define R_GPSTB_FREQ 0x08001460 // 08001460, wbregs names: GPSFREQ #define R_GPSTB_JUMP 0x08001464 // 08001460, wbregs names: GPSJUMP #define R_GPSTB_ERRHI 0x08001468 // 08001460, wbregs names: ERRHI #define R_GPSTB_ERRLO 0x0800146c // 08001460, wbregs names: ERRLO #define R_GPSTB_COUNTHI 0x08001470 // 08001460, wbregs names: CNTHI #define R_GPSTB_COUNTLO 0x08001474 // 08001460, wbregs names: CNTLO #define R_GPSTB_STEPHI 0x08001478 // 08001460, wbregs names: STEPHI #define R_GPSTB_STEPLO 0x0800147c // 08001460, wbregs names: STEPLO // SYSCLK Clock Counter (measures clock speed) #define R_ADCCLK 0x08001480 // 08001480, wbregs names: ADCCLK #define R_BUILDTIME 0x08001484 // 08001484, wbregs names: BUILDTIME, BUILDTIME #define R_BUSERR 0x08001488 // 08001488, wbregs names: BUSERR #define R_PIC 0x0800148c // 0800148c, wbregs names: PIC #define R_GPIO 0x08001490 // 08001490, wbregs names: GPIO, GPI, GPO #define R_PWRCOUNT 0x08001494 // 08001494, wbregs names: PWRCOUNT #define R_RTCDATE 0x08001498 // 08001498, wbregs names: RTCDATE, DATE // SYSCLK Clock Counter (measures clock speed) #define R_RXETH0CK 0x0800149c // 0800149c, wbregs names: RXETH0CK #define R_SPIO 0x080014a0 // 080014a0, wbregs names: SPIO // A register capturing subseconds, locked to GPS if present #define R_SUBSECONDS 0x080014a4 // 080014a4, wbregs names: SUBSECONDS // SYSCLK Clock Counter (measures clock speed) #define R_TXCLK 0x080014a8 // 080014a8, wbregs names: TXCLK #define R_VERSION 0x080014ac // 080014ac, wbregs names: VERSION #define R_EDIDRX 0x08001500 // 08001500, wbregs names: EDIDRX // HDMI video processing pipe registers #define R_VIDPIPE 0x08002000 // 08002000, wbregs names: VIDPIPE, VIDCTRL #define R_HDMIFREQ 0x08002004 // 08002000, wbregs names: HDMIFREQ #define R_SIFREQ 0x08002008 // 08002000, wbregs names: SIFREQ #define R_PXFREQ 0x0800200c // 08002000, wbregs names: PXFREQ #define R_INSIZE 0x08002010 // 08002000, wbregs names: INSIZE #define R_INPORCH 0x08002014 // 08002000, wbregs names: INPORCH #define R_INSYNC 0x08002018 // 08002000, wbregs names: INSYNC #define R_INRAW 0x0800201c // 08002000, wbregs names: INRAW #define R_HDMISIZE 0x08002020 // 08002000, wbregs names: HDMISIZE #define R_HDMIPORCH 0x08002024 // 08002000, wbregs names: HDMIPORCH #define R_HDMISYNC 0x08002028 // 08002000, wbregs names: HDMISYNC #define R_HDMIRAW 0x0800202c // 08002000, wbregs names: HDMIRAW #define R_OVADDR 0x08002030 // 08002000, wbregs names: OVADDR #define R_OVSIZE 0x08002034 // 08002000, wbregs names: OVSIZE #define R_OVOFFSET 0x08002038 // 08002000, wbregs names: OVOFFSET #define R_FPS 0x0800203c // 08002000, wbregs names: FPS #define R_CAPTURE 0x08002040 // 08002000, wbregs names: VCAPTURE #define R_CAPBASE 0x08002044 // 08002000, wbregs names: VCAPBASE #define R_CAPWORDS 0x08002048 // 08002000, wbregs names: VCAPWORDS #define R_CAPPOSN 0x0800204c // 08002000, wbregs names: VCAPPOSN #define R_CAPSIZE 0x08002050 // 08002000, wbregs names: VCAPSIZE #define R_SYNCWORD 0x08002060 // 08002000, wbregs names: VSYNCWORD #define R_CMAP 0x08002800 // 08002000, wbregs names: CMAP // Ethernet configuration (MDIO) port #define R_MDIO_BMCR 0x08003000 // 08003000, wbregs names: BMCR #define R_MDIO_BMSR 0x08003004 // 08003000, wbregs names: BMSR #define R_MDIO_PHYIDR1 0x08003008 // 08003000, wbregs names: PHYIDR1 #define R_MDIO_PHYIDR2 0x0800300c // 08003000, wbregs names: PHYIDR2 #define R_MDIO_ANAR 0x08003010 // 08003000, wbregs names: ANAR #define R_MDIO_ANLPAR 0x08003014 // 08003000, wbregs names: ANLPAR #define R_MDIO_ANER 0x08003018 // 08003000, wbregs names: ANER #define R_MDIO_ANNPTR 0x0800301c // 08003000, wbregs names: ANNPTR #define R_MDIO_ANNPRR 0x08003020 // 08003000, wbregs names: ANNPRR #define R_MDIO_GBCR 0x08003024 // 08003000, wbregs names: GBCR #define R_MDIO_GBSR 0x08003028 // 08003000, wbregs names: GBSR #define R_MDIO_MACR 0x08003034 // 08003000, wbregs names: MACR #define R_MDIO_MAADR 0x08003038 // 08003000, wbregs names: MAADR #define R_MDIO_GBESR 0x0800303c // 08003000, wbregs names: GBESR #define R_MDIO_PHYCR 0x08003040 // 08003000, wbregs names: PHYCR #define R_MDIO_PHYSR 0x08003044 // 08003000, wbregs names: PHYSR #define R_MDIO_INER 0x08003048 // 08003000, wbregs names: INER #define R_MDIO_INSR 0x0800304c // 08003000, wbregs names: INSR #define R_MDIO_RXERC 0x08003060 // 08003000, wbregs names: RXERC #define R_MDIO_LDPSR 0x0800306c // 08003000, wbregs names: LDPSR #define R_MDIO_EPAGSR 0x08003078 // 08003000, wbregs names: EPAGSR #define R_MDIO_PAGSEL 0x0800307c // 08003000, wbregs names: PAGSEL #define R_XMDIO_PC1R 0x08003000 // 08003000, wbregs names: XPC1R #define R_XMDIO_PS1R 0x08003004 // 08003000, wbregs names: XPS1R #define R_XMDIO_EEECR 0x08003050 // 08003000, wbregs names: XEEECR #define R_XMDIO_EEEWER 0x08003040 // 08003000, wbregs names: XEEEWER #define R_XMDIO_EEEAR 0x080030f0 // 08003000, wbregs names: XEEEAR #define R_XMDIO_EEELPAR 0x080030f4 // 08003000, wbregs names: XEEELPAR #define R_XMDIO_LACR 0x08003068 // 08003000, wbregs names: XLACR #define R_XMDIO_LCR 0x08003070 // 08003000, wbregs names: XLCR #define R_BKRAM 0x10000000 // 10000000, wbregs names: RAM #define R_SDRAM 0x40000000 // 40000000, wbregs names: SDRAM // ZipCPU control/debug registers #define R_ZIPCTRL 0x80000000 // 80000000, wbregs names: CPU, ZIPCTRL #define R_ZIPREGS 0x80000080 // 80000000, wbregs names: ZIPREGS #define R_ZIPS0 0x80000080 // 80000000, wbregs names: SR0 #define R_ZIPS1 0x80000084 // 80000000, wbregs names: SR1 #define R_ZIPS2 0x80000088 // 80000000, wbregs names: SR2 #define R_ZIPS3 0x8000008c // 80000000, wbregs names: SR3 #define R_ZIPS4 0x80000090 // 80000000, wbregs names: SR4 #define R_ZIPS5 0x80000094 // 80000000, wbregs names: SR5 #define R_ZIPS6 0x80000098 // 80000000, wbregs names: SR6 #define R_ZIPS7 0x8000009c // 80000000, wbregs names: SR7 #define R_ZIPS8 0x800000a0 // 80000000, wbregs names: SR8 #define R_ZIPS9 0x800000a4 // 80000000, wbregs names: SR9 #define R_ZIPS10 0x800000a8 // 80000000, wbregs names: SR10 #define R_ZIPS11 0x800000ac // 80000000, wbregs names: SR11 #define R_ZIPS12 0x800000b0 // 80000000, wbregs names: SR12 #define R_ZIPSSP 0x800000b4 // 80000000, wbregs names: SSP, SR13 #define R_ZIPCC 0x800000b8 // 80000000, wbregs names: ZIPCC, CC, SCC, SR14 #define R_ZIPPC 0x800000bc // 80000000, wbregs names: ZIPPC, PC, SPC, SR15 #define R_ZIPUSER 0x800000c0 // 80000000, wbregs names: ZIPUSER #define R_ZIPU0 0x800000c0 // 80000000, wbregs names: UR0 #define R_ZIPU1 0x800000c4 // 80000000, wbregs names: UR1 #define R_ZIPU2 0x800000c8 // 80000000, wbregs names: UR2 #define R_ZIPU3 0x800000cc // 80000000, wbregs names: UR3 #define R_ZIPU4 0x800000d0 // 80000000, wbregs names: UR4 #define R_ZIPU5 0x800000d4 // 80000000, wbregs names: UR5 #define R_ZIPU6 0x800000d8 // 80000000, wbregs names: UR6 #define R_ZIPU7 0x800000dc // 80000000, wbregs names: UR7 #define R_ZIPU8 0x800000e0 // 80000000, wbregs names: UR8 #define R_ZIPU9 0x800000e4 // 80000000, wbregs names: UR9 #define R_ZIPU10 0x800000e8 // 80000000, wbregs names: SR10 #define R_ZIPU11 0x800000ec // 80000000, wbregs names: SR11 #define R_ZIPU12 0x800000f0 // 80000000, wbregs names: SR12 #define R_ZIPUSP 0x800000f4 // 80000000, wbregs names: USP, UR13 #define R_ZIPUCC 0x800000f8 // 80000000, wbregs names: ZIPUCC, UCC #define R_ZIPUPC 0x800000fc // 80000000, wbregs names: ZIPUPC, UPC #define R_ZIPSYSTEM 0x80000100 // 80000000, wbregs names: ZIPSYSTEM, ZIPSYS #define R_ZIPWATCHDOG 0x80000104 // 80000000, wbregs names: ZIPWATCHDOG #define R_ZIPBUSDOG 0x80000108 // 80000000, wbregs names: BUSDOG #define R_ZIPAPIC 0x8000010c // 80000000, wbregs names: ZIPAPIC, ALTPIC #define R_ZIPTIMERA 0x80000110 // 80000000, wbregs names: ZIPTMA, ZIPTIMERA #define R_ZIPTIMERB 0x80000114 // 80000000, wbregs names: ZIPTMB, ZIPTIMERB #define R_ZIPTIMERC 0x80000118 // 80000000, wbregs names: ZIPTMC, ZIPTIMERC #define R_ZIPJIFFIES 0x8000011c // 80000000, wbregs names: ZIPJIFF #define R_ZIPMTASK 0x80000120 // 80000000, wbregs names: ZIPMTASK #define R_ZIPMSTALL 0x80000124 // 80000000, wbregs names: ZIPMSTALL #define R_ZIPMPSTAL 0x80000128 // 80000000, wbregs names: ZIPMPSTAL #define R_ZIPMINSN 0x8000012c // 80000000, wbregs names: ZIPMINSN #define R_ZIPUTASK 0x80000130 // 80000000, wbregs names: ZIPUTASK #define R_ZIPUSTALL 0x80000134 // 80000000, wbregs names: ZIPUSTALL #define R_ZIPUPSTAL 0x80000138 // 80000000, wbregs names: ZIPUPSTAL #define R_ZIPUINSN 0x8000013c // 80000000, wbregs names: ZIPUINSN #define R_ZIPUDMAC 0x80000140 // 80000000, wbregs names: ZIPDMAC // // The @REGDEFS.H.DEFNS tag // // @REGDEFS.H.DEFNS for masters #define BAUDRATE 1000000 #define CLKFREQHZ 100000000 // @REGDEFS.H.DEFNS for peripherals #define FLASHBASE 0x01000000 #define FLASHLEN 0x01000000 #define FLASHLGLEN 24 // #define FLASH_RDDELAY 2 #define FLASH_NDUMMY 6 // #define BKRAMBASE 0x10000000 #define BKRAMLEN 0x00100000 #define SDRAMBASE 0x40000000 #define SDRAMLEN 0x40000000 // @REGDEFS.H.DEFNS at the top level // End of definitions from REGDEFS.H.DEFNS // // The @REGDEFS.H.INSERT tag // // @REGDEFS.H.INSERT for masters // @REGDEFS.H.INSERT for peripherals // Flash control constants #define QSPI_FLASH // This core and hardware support a Quad SPI flash #define SZPAGEB 256 #define PGLENB 256 #define SZPAGEW 64 #define PGLENW 64 #define NPAGES 256 #define SECTORSZB (NPAGES * SZPAGEB) // In bytes, not words!! #define SECTORSZW (NPAGES * SZPAGEW) // In words #define NSECTORS 64 #define SECTOROF(A) ((A) & (-1<<16)) #define SUBSECTOROF(A) ((A) & (-1<<12)) #define PAGEOF(A) ((A) & (-1<<8)) //////////////////////////////////////////////////////////////////////////////// // // ZipCPU register definitions // {{{ #define CPU_GO 0x0000 #define CPU_HALT 0x0001 #define CPU_STALL 0x0002 #define CPU_STEP 0x0004 #define CPU_RESET 0x0008 #define CPU_CLRCACHE 0x0010 // (Reserved) 0x00e0 #define CPU_SLEEPING 0x0100 #define CPU_GIE 0x0200 #define CPU_INT 0x0400 #define CPU_BREAK 0x0800 #define CPU_EXINT 0xfffff000 // #define CPU_sR0 0x0020 #define CPU_sSP 0x002d #define CPU_sCC 0x002e #define CPU_sPC 0x002f #define CPU_uR0 0x0030 #define CPU_uSP 0x003d #define CPU_uCC 0x003e #define CPU_uPC 0x003f #ifdef BKROM_ACCESS #define RESET_ADDRESS @$[0x%08x](bkrom.REGBASE) #else #ifdef FLASH_ACCESS #define RESET_ADDRESS 0x01600000 #else #define RESET_ADDRESS 0x10000000 #endif // FLASH_ACCESS #endif // BKROM_ACCESS // }}} // @REGDEFS.H.INSERT from the top level typedef struct { unsigned m_addr; const char *m_name; } REGNAME; extern const REGNAME *bregs; extern const int NREGS; // #define NREGS (sizeof(bregs)/sizeof(bregs[0])) extern unsigned addrdecode(const char *v); extern const char *addrname(const unsigned v); // End of definitions from REGDEFS.H.INSERT #endif // REGDEFS_H ================================================ FILE: demo-out/rtl.make.inc ================================================ ################################################################################ ## ## Filename: ../demo-out/rtl.make.inc ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Computer Generated: This file is computer generated by AUTOFPGA. DO NOT EDIT. ## DO NOT EDIT THIS FILE! ## ## CmdLine: ./autofpga -d -o ../demo-out -I ../auto-data allclocks.txt bkram.txt buserr.txt clkcheck.txt crossbus.txt ddr3.txt edidslvscope.txt edid.txt exconsole.txt flashcfg.txt flash.txt global.txt gpio.txt gps.txt hdmi.txt i2ccpu.txt i2cdma.txt i2saudio.txt icape.txt meganet.txt mdio.txt pic.txt pwrcount.txt rtcdate.txt rtcgps.txt spio.txt sdio.txt vadj33.txt version.txt wboledbw.txt wbpmic.txt wbuarbiter.txt wbubus.txt zipcpu.txt zipmaster.txt ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} I2CCPUD := wbi2c I2CCPU := $(addprefix $(I2CCPUD)/,wbi2ccpu.v axisi2c.v) EXBUSD := exbus EXBUS := $(addprefix $(EXBUSD)/,exbuswb.v excompress.v exdecompress.v exdeword.v exidle.v exmkword.v exwb.v exfifo.v) FLASH := qflexpress.v EDIDD := wbi2c EDID := $(addprefix $(EDIDD)/,wbi2ccpu.v axisi2c.v) GPS := gpsclock_tb.v gpsclock.v bigadd.v bigsub.v bigsmpy.v HDMID := video HDMI := $(addprefix $(HDMID)/,axishdmi.v axisvoverlay.v hdmi2vga.v hdmibitsync.v hdmipixelsync.v sync2stream.v synccount.v tfrstb.v tmdsdecode.v tmdsencode.v vid_empty.v vid_mux.v vidpipe.v vidstream2pix.v vid_wbframebuf.v vid_crop.v xhdmiin_deserdes.v xhdmiin.v xhdmiout.v xpxclk.v) I2CSLVD := wbi2c I2CSLV := $(addprefix $(I2CSLVD)/,wbi2cslave.v) SCOPCD := wbscope SCOPC := $(addprefix $(SCOPCD)/,wbscopc.v) ICAP := wbicapetwo.v BKRAM := memdev.v DDR3D := ddr3 DDR3 := $(addprefix $(DDR3D)/,ddr3_controller.v ddr3_phy.v) I2CDMAD := wbi2c I2CDMA := $(addprefix $(I2CDMAD)/,wbi2cdma.v) AUDIOD := audio AUDIO := $(addprefix $(AUDIOD)/,axisi2s.v lli2s.v) ENETD := ethernet ENET := $(addprefix $(ENETD)/,enetstream.v addecrc.v addemac.v addepad.v addepreamble.v rxecrc.v rxehwmac.v rxeipchk.v rxemin.v rxepacket.v rxepreambl.v axinwidth.v axincdc.v pktgate.v txespeed.v xiddr.v) RTCDATED := rtc RTCDATE := $(addprefix $(RTCDATED)/,rtcdate.v) RTCGPSD := rtc RTCGPS := $(addprefix $(RTCGPSD)/,rtcgps.v rtcbare.v rtctimer.v rtcstopwatch.v rtcalarm.v rtclight.v) GPIO := wbgpio.v SDIOD := sdspi SDIO := $(addprefix $(SDIOD)/,sdio.v sdfrontend.v sdckgen.v sdwb.v sdtxframe.v sdrxframe.v sdcmd.v sddma.v sddma_mm2s.v sddma_rxgears.v sdfifo.v sddma_txgears.v sddma_s2mm.v xsdddr.v xsdserdes8x.v) BUSPICD := cpu BUSPIC := $(addprefix $(BUSPICD)/,icontrol.v) ENETMDIOD := ethernet ENETMDIO := $(addprefix $(ENETMDIOD)/,enetctrl.v) WBSPID := wbspi WBSPI := $(addprefix $(WBSPID)/,spicpu.v) UPSZ := wbupsz.v ZIPCPUD := cpu ZIPCPU := $(addprefix $(ZIPCPUD)/,zipsystem.v zipcore.v zipwb.v cpuops.v pfcache.v pipemem.v dblfetch.v pffifo.v pfcache.v idecode.v wbpriarbiter.v zipsystem.v zipcounter.v zipjiffies.v ziptimer.v icontrol.v wbwatchdog.v busdelay.v zipdma_ctrl.v zipdma_fsm.v zipdma_mm2s.v zipdma_rxgears.v zipdma_s2mm.v zipdma_txgears.v zipdma.v) VFLIST := main.v $(I2CCPU) $(EXBUS) $(FLASH) $(EDID) $(GPS) $(HDMI) $(I2CSLV) $(SCOPC) $(ICAP) $(BKRAM) $(DDR3) $(I2CDMA) $(AUDIO) $(ENET) $(RTCDATE) $(RTCGPS) $(GPIO) $(SDIO) $(BUSPIC) $(ENETMDIO) $(WBSPI) $(UPSZ) $(ZIPCPU) AUTOVDIRS := -y wbi2c -y exbus -y video -y wbscope -y ddr3 -y audio -y ethernet -y rtc -y sdspi -y cpu -y wbspi ================================================ FILE: demo-out/testb.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: ../demo-out/testb.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Computer Generated: This file is computer generated by AUTOFPGA. DO NOT EDIT. // DO NOT EDIT THIS FILE! // // CmdLine: ./autofpga -d -o ../demo-out -I ../auto-data allclocks.txt bkram.txt buserr.txt clkcheck.txt crossbus.txt ddr3.txt edidslvscope.txt edid.txt exconsole.txt flashcfg.txt flash.txt global.txt gpio.txt gps.txt hdmi.txt i2ccpu.txt i2cdma.txt i2saudio.txt icape.txt meganet.txt mdio.txt pic.txt pwrcount.txt rtcdate.txt rtcgps.txt spio.txt sdio.txt vadj33.txt version.txt wboledbw.txt wbpmic.txt wbuarbiter.txt wbubus.txt zipcpu.txt zipmaster.txt // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef TESTB_H #define TESTB_H // #define TRACE_FST #include #include #ifdef TRACE_FST #define TRACECLASS VerilatedFstC #include #else // TRACE_FST #define TRACECLASS VerilatedVcdC #include #endif #include // // The TESTB class is a useful wrapper for interacting with a Verilator // based design. Key to its capabilities are the tick() method for // advancing the simulation timestep, and the opentrace() and // closetrace() methods for handling VCD tracefile generation. To // use a non-VCD trace, redefine TRACECLASS before calling this // function to the trace class you wish to use. // template class TESTB { public: VA *m_core; bool m_changed; TRACECLASS* m_trace; bool m_done, m_paused_trace; uint64_t m_time_ps; // TBCLOCK is a clock support class, enabling multiclock simulation // operation. TBCLOCK m_clk; TBCLOCK m_pixclk; TBCLOCK m_net_rx_clk; TBCLOCK m_clk_125mhz; TESTB(void) { // {{{ m_core = new VA; m_time_ps = 0ul; m_trace = NULL; m_done = false; m_paused_trace = false; Verilated::traceEverOn(true); // Set the initial clock periods m_clk.init(10000); // 100.00 MHz m_pixclk.init(25000); // 40.00 MHz m_net_rx_clk.init(8000); // 125.00 MHz m_clk_125mhz.init(8000); // 125.00 MHz } // }}} virtual ~TESTB(void) { // {{{ if (m_trace) m_trace->close(); delete m_core; m_core = NULL; } // }}} // // opentrace() // {{{ // // Useful for beginning a (VCD) trace. To open such a trace, just call // opentrace() with the name of the VCD file you'd like to trace // everything into virtual void opentrace(const char *vcdname, int depth=99) { if (!m_trace) { m_trace = new TRACECLASS; m_core->trace(m_trace, 99); m_trace->spTrace()->set_time_resolution("ps"); m_trace->spTrace()->set_time_unit("ps"); m_trace->open(vcdname); m_paused_trace = false; } } // }}} // // trace() // {{{ // A synonym for opentrace() above. // void trace(const char *vcdname) { opentrace(vcdname); } // }}} // // pausetrace(pause) // {{{ // Set/clear a flag telling us whether or not to write to the VCD trace // file. The default is to write to the file, but this can be changed // by calling pausetrace. pausetrace(false) will resume tracing, // whereas pausetrace(true) will stop all calls to Verilator's trace() // function // virtual bool pausetrace(bool pausetrace) { m_paused_trace = pausetrace; return m_paused_trace; } // }}} // // pausetrace() // {{{ // Like pausetrace(bool) above, except that pausetrace() will return // the current status of the pausetrace flag above. Specifically, it // will return true if the trace has been paused or false otherwise. virtual bool pausetrace(void) { return m_paused_trace; } // }}} // // closetrace() // {{{ // Closes the open trace file. No more information will be written // to it virtual void closetrace(void) { if (m_trace) { m_trace->close(); delete m_trace; m_trace = NULL; } } // }}} // // eval() // {{{ // This is a synonym for Verilator's eval() function. It evaluates all // of the logic within the design. AutoFPGA based designs shouldn't // need to be calling this, they should call tick() instead. However, // in the off chance that your design inputs depend upon combinatorial // expressions that would be output based upon other input expressions, // you might need to call this function. virtual void eval(void) { m_core->eval(); } // }}} // // tick() // {{{ // tick() is the main entry point into this helper core. In general, // tick() will advance the clock by one clock tick. In a multiple clock // design, this will advance the clocks up until the nearest clock // transition. virtual void tick(void) { unsigned mintime = m_clk.time_to_edge(); if (m_pixclk.time_to_edge() < mintime) mintime = m_pixclk.time_to_edge(); if (m_net_rx_clk.time_to_edge() < mintime) mintime = m_net_rx_clk.time_to_edge(); if (m_clk_125mhz.time_to_edge() < mintime) mintime = m_clk_125mhz.time_to_edge(); assert(mintime > 1); // Pre-evaluate, to give verilator a chance to settle any // combinatorial logic thatthat may have changed since the // last clockevaluation, and then record that in the trace. eval(); if (m_trace && !m_paused_trace) m_trace->dump(m_time_ps+1); // Advance each clock m_core->i_clk = m_clk.advance(mintime); m_core->i_pixclk = m_pixclk.advance(mintime); m_core->i_net_rx_clk = m_net_rx_clk.advance(mintime); m_core->i_clk_125mhz = m_clk_125mhz.advance(mintime); m_time_ps += mintime; eval(); // If we are keeping a trace, dump the current state to that // trace now if (m_trace && !m_paused_trace) { m_trace->dump(m_time_ps); m_trace->flush(); } if (m_clk.falling_edge()) { m_changed = true; sim_clk_tick(); } if (m_pixclk.falling_edge()) { m_changed = true; sim_pixclk_tick(); } if (m_net_rx_clk.falling_edge()) { m_changed = true; sim_net_rx_clk_tick(); } if (m_clk_125mhz.falling_edge()) { m_changed = true; sim_clk_125mhz_tick(); } } // }}} virtual void sim_clk_tick(void) { // {{{ // AutoFPGA will override this method within main_tb.cpp if any // @SIM.TICK key is present within a design component also // containing a @SIM.CLOCK key identifying this clock. That // component must also set m_changed to true. m_changed = false; } // }}} virtual void sim_pixclk_tick(void) { // {{{ // AutoFPGA will override this method within main_tb.cpp if any // @SIM.TICK key is present within a design component also // containing a @SIM.CLOCK key identifying this clock. That // component must also set m_changed to true. m_changed = false; } // }}} virtual void sim_net_rx_clk_tick(void) { // {{{ // AutoFPGA will override this method within main_tb.cpp if any // @SIM.TICK key is present within a design component also // containing a @SIM.CLOCK key identifying this clock. That // component must also set m_changed to true. m_changed = false; } // }}} virtual void sim_clk_125mhz_tick(void) { // {{{ // AutoFPGA will override this method within main_tb.cpp if any // @SIM.TICK key is present within a design component also // containing a @SIM.CLOCK key identifying this clock. That // component must also set m_changed to true. m_changed = false; } // }}} virtual bool done(void) { // {{{ if (m_done) return true; if (Verilated::gotFinish()) m_done = true; return m_done; } // }}} // // reset() // {{{ // Sets the i_reset input for one clock tick. It's really just a // function for the capabilies shown below. You'll want to reset any // external input values before calling this though. virtual void reset(void) { m_core->i_reset = 1; tick(); while(!m_core->i_clk) tick(); m_core->i_reset = 0; // printf("RESET\n"); } // }}} }; #endif // TESTB ================================================ FILE: demo-out/toplevel.v ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: ../demo-out/toplevel.v // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Computer Generated: This file is computer generated by AUTOFPGA. DO NOT EDIT. // DO NOT EDIT THIS FILE! // // CmdLine: ./autofpga -d -o ../demo-out -I ../auto-data allclocks.txt bkram.txt buserr.txt clkcheck.txt crossbus.txt ddr3.txt edidslvscope.txt edid.txt exconsole.txt flashcfg.txt flash.txt global.txt gpio.txt gps.txt hdmi.txt i2ccpu.txt i2cdma.txt i2saudio.txt icape.txt meganet.txt mdio.txt pic.txt pwrcount.txt rtcdate.txt rtcgps.txt spio.txt sdio.txt vadj33.txt version.txt wboledbw.txt wbpmic.txt wbuarbiter.txt wbubus.txt zipcpu.txt zipmaster.txt // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} `default_nettype none // // Here we declare our toplevel.v (toplevel) design module. // All design logic must take place beneath this top level. // // The port declarations just copy data from the @TOP.PORTLIST // key, or equivalently from the @MAIN.PORTLIST key if // @TOP.PORTLIST is absent. For those peripherals that don't need // any top level logic, the @MAIN.PORTLIST should be sufficent, // so the @TOP.PORTLIST key may be left undefined. // // The only exception is that any clocks with CLOCK.TOP tags will // also appear in this list // module toplevel(i_clk, // Top level Quad-SPI I/O ports o_flash_cs_n, io_flash_dat, io_scl, io_sda, // UART/host to wishbone interface i_wbu_uart_rx, o_wbu_uart_tx, io_hdmitx_scl, io_hdmitx_sda, // The GPS-UART i_gpsu_rx, o_gpsu_tx, i_hdmirx_clk_p, i_hdmirx_clk_n, i_hdmirx_p, i_hdmirx_n, o_hdmitx_clk_p, o_hdmitx_clk_n, o_hdmitx_p, o_hdmitx_n, // EDID RX definitions io_hdmirx_scl, io_hdmirx_sda, // DDR3 I/O port wires o_ddr3_reset_n, o_ddr3_cke, o_ddr3_clk_p, o_ddr3_clk_n, o_ddr3_vsel, o_ddr3_cs_n, o_ddr3_ras_n, o_ddr3_cas_n, o_ddr3_we_n, o_ddr3_ba, o_ddr3_a, o_ddr3_odt, o_ddr3_dm, io_ddr3_dqs_p, io_ddr3_dqs_n, io_ddr3_dq, o_i2s_lrclk, o_i2s_bclk, o_i2s_mclk, o_i2s_dac, i_i2s_adc, // Ethernet control (packets) lines o_net_reset_n, i_net_rx_clk, i_net_rx_ctl, i_net_rxd, o_net_tx_clk, o_net_tx_ctl, o_net_txd, // SPIO interface i_sw, i_btnc, i_btnd, i_btnl, i_btnr, i_btnu, o_led, // GPIO ports o_hdmirx_hpa, // Hotplug assert o_hdmirx_txen, i_hdmitx_hpd_n, // Hotplug detect o_sd_reset, i_gps_3df, o_oled_reset_n, o_oled_panel_en, o_oled_logic_en, // SDIO SD Card o_sd_clk, i_sd_cd_n, io_sd_cmd, io_sd_dat, // VADJ ports o_vadj_en, o_vadj, // The GPS 1PPS signal port i_gps_pps, // Toplevel ethernet MDIO ports o_eth_mdclk, io_eth_mdio, // OLED control interface (roughly SPI) o_oled_sck, o_oled_mosi, o_oled_dcn, // The PMic3 microphone wires o_mic_csn, o_mic_sck, i_mic_din); // // Declaring any top level parameters. // // These declarations just copy data from the @TOP.PARAM key, // or from the @MAIN.PARAM key if @TOP.PARAM is absent. For // those peripherals that don't do anything at the top level, // the @MAIN.PARAM key should be sufficient, so the @TOP.PARAM // key may be left undefined. // //////////////////////////////////////////////////////////////////////// // // EXBUS parameters // {{{ // Baudrate : 1000000 // Clock : 100000000 localparam [23:0] BUSUART = 24'h64; // 1000000 baud localparam DBGBUSBITS = $clog2(BUSUART); // }}} localparam ICAPE_LGDIV=3; localparam real SDRAMCONTROLLER_CLK_PERIOD = 10_000, //ps, clock period of the controller interface DDR3_CLK_PERIOD = 2_500; //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD) localparam SDRAMROW_BITS = 14, // width of row address SDRAMCOL_BITS = 10, // width of column address SDRAMBA_BITS = 3, // width of bank address SDRAMDQ_BITS = 8, // Size of one octet SDRAMBYTE_LANES = 2, //8 lanes of DQ SDRAMAUX_WIDTH = 4, //width of aux line (must be >= 4) SDRAMSERDES_RATIO = $rtoi(SDRAMCONTROLLER_CLK_PERIOD/DDR3_CLK_PERIOD), //4 is the width of a single ddr3 command {cs_n, ras_n, cas_n, we_n} plus 3 (ck_en, odt, reset_n) plus bank bits plus row bits SDRAMCMD_LEN = 4 + 3 + SDRAMBA_BITS + SDRAMROW_BITS; parameter [15:0] UDP_DBGPORT = 6784; localparam [47:0] DEF_HWMAC = 48'h82_33_48_02_e1_c8; localparam [31:0] DEF_IPADDR = { 8'd192, 8'd168, 8'd15, 8'd29 }; localparam [31:0] GPSCLOCK_DEFAULT_STEP = 32'haabcc771; //////////////////////////////////////////////////////////////////////// // // Variables/definitions/parameters used by the ZipCPU bus master // {{{ // // A 32-bit address indicating where the ZipCPU should start running // from `ifdef BKROM_ACCESS localparam RESET_ADDRESS = @$(/bkrom.BASE); `else `ifdef FLASH_ACCESS localparam RESET_ADDRESS = 23068672; `else localparam RESET_ADDRESS = 268435456; `endif // FLASH_ACCESS `endif // BKROM_ACCESS // // The number of valid bits on the bus localparam ZIP_ADDRESS_WIDTH = 27; // Zip-CPU address width // // Number of ZipCPU interrupts localparam ZIP_INTS = 16; // // ZIP_START_HALTED // // A boolean, indicating whether or not the ZipCPU be halted on startup? `ifdef BKROM_ACCESS localparam ZIP_START_HALTED=1'b0; `else localparam ZIP_START_HALTED=1'b1; `endif // }}} // // Declaring our input and output ports. We listed these above, // now we are declaring them here. // // These declarations just copy data from the @TOP.IODECLS key, // or from the @MAIN.IODECL key if @TOP.IODECL is absent. For // those peripherals that don't do anything at the top level, // the @MAIN.IODECL key should be sufficient, so the @TOP.IODECL // key may be left undefined. // // We start with any @CLOCK.TOP keys // input wire i_clk; // Quad SPI flash output wire o_flash_cs_n; inout wire [3:0] io_flash_dat; inout wire io_scl, io_sda; input wire i_wbu_uart_rx; output wire o_wbu_uart_tx; inout wire io_hdmitx_scl, io_hdmitx_sda; input wire i_gpsu_rx; output wire o_gpsu_tx; input wire i_hdmirx_clk_p, i_hdmirx_clk_n; input wire [2:0] i_hdmirx_p, i_hdmirx_n; output wire o_hdmitx_clk_p, o_hdmitx_clk_n; output wire [2:0] o_hdmitx_p, o_hdmitx_n; // EDID RX definitions inout wire io_hdmirx_scl, io_hdmirx_sda; // I/O declarations for the DDR3 SDRAM // {{{ output wire o_ddr3_reset_n; output wire [0:0] o_ddr3_cke; output wire [0:0] o_ddr3_clk_p, o_ddr3_clk_n; output wire [0:0] o_ddr3_cs_n; // o_ddr3_s_n[1] is set to 0 since controller only support single rank output wire o_ddr3_vsel; output wire [0:0] o_ddr3_ras_n, o_ddr3_cas_n, o_ddr3_we_n; output wire [SDRAMBA_BITS-1:0] o_ddr3_ba; output wire [14:0] o_ddr3_a; //set to max of 16 bits, but only ROW_BITS bits are relevant output wire [0:0] o_ddr3_odt; output wire [SDRAMBYTE_LANES-1:0] o_ddr3_dm; inout wire [(SDRAMDQ_BITS*SDRAMBYTE_LANES)/8-1:0] io_ddr3_dqs_p, io_ddr3_dqs_n; inout wire [(SDRAMDQ_BITS*SDRAMBYTE_LANES)-1:0] io_ddr3_dq; // }}} output wire o_i2s_lrclk, o_i2s_bclk, o_i2s_mclk, o_i2s_dac; input wire i_i2s_adc; // MegaNet I/O port declarations // {{{ output wire o_net_reset_n; input wire i_net_rx_clk, i_net_rx_ctl; input wire [3:0] i_net_rxd; output wire o_net_tx_clk, o_net_tx_ctl; output wire [3:0] o_net_txd; // }}} // SPIO interface input wire [8-1:0] i_sw; input wire i_btnc, i_btnd, i_btnl, i_btnr, i_btnu; output wire [8-1:0] o_led; // GPIO ports output wire o_hdmirx_hpa; output wire o_hdmirx_txen; input wire i_hdmitx_hpd_n; // Hotplug detect output wire o_sd_reset; input wire i_gps_3df; output wire o_oled_reset_n, o_oled_panel_en, o_oled_logic_en; // SDIO SD Card // {{{ output wire o_sd_clk; input wire i_sd_cd_n; inout wire io_sd_cmd; inout wire [4-1:0] io_sd_dat; // }}} // VADJ wires output wire o_vadj_en; output wire [1:0] o_vadj; //The GPS Clock input wire i_gps_pps; // Ethernet control (MDIO) output wire o_eth_mdclk; inout wire io_eth_mdio; // OLEDBW interface output wire o_oled_sck, o_oled_mosi, o_oled_dcn; output wire o_mic_csn, o_mic_sck; input wire i_mic_din; // // Declaring component data, internal wires and registers // // These declarations just copy data from the @TOP.DEFNS key // within the component data files. // wire w_flash_sck, w_flash_cs_n; wire [1:0] flash_bmod; wire [3:0] flash_dat; // I2CCPU definitions // {{{ wire i_i2c_sda, i_i2c_scl, o_i2c_sda, o_i2c_scl; // }}} // I2CCPU definitions // {{{ wire i_edid_sda, i_edid_scl, o_edid_sda, o_edid_scl; // }}} wire [9:0] hdmirx_red, hdmirx_grn, hdmirx_blu; wire [9:0] hdmitx_red, hdmitx_grn, hdmitx_blu; wire [1:0] w_pxclk_cksel; wire hdmirx_clk, hdmi_ck, hdmi_serdes_clk; wire pxrx_locked, pix_reset_n, hdmirx_reset_n; wire [15-1:0] set_hdmi_delay, actual_hdmi_delay; wire w_edidslv_scl, w_edidslv_sda; wire s_clk, s_reset; reg [2:0] clk_reset_pipe; // Wires connected to PHY interface of DDR3 controller // {{{ genvar ddr3gen_index; wire [SDRAMDQ_BITS*SDRAMBYTE_LANES*8-1:0] ddr3_iserdes_data; wire [SDRAMBYTE_LANES*8-1:0] ddr3_iserdes_dqs, ddr3_iserdes_bitslip_reference; wire [SDRAMCMD_LEN*SDRAMSERDES_RATIO-1:0] ddr3_cmd; wire [SDRAMDQ_BITS*SDRAMBYTE_LANES*8-1:0] ddr3_data; wire [(SDRAMDQ_BITS*SDRAMBYTE_LANES*8)/8-1:0] ddr3_dm; wire [4:0] ddr3_odelay_data_cntvaluein, ddr3_odelay_dqs_cntvaluein, ddr3_idelay_data_cntvaluein, ddr3_idelay_dqs_cntvaluein; wire [SDRAMBYTE_LANES-1:0] ddr3_odelay_data_ld, ddr3_odelay_dqs_ld, ddr3_idelay_data_ld, ddr3_idelay_dqs_ld, ddr3_bitslip, ddr3_debug_read_dqs_p, ddr3_debug_read_dqs_n; wire ddr3_idelayctrl_rdy, ddr3_dqs_tri_control, ddr3_dq_tri_control, ddr3_toggle_dqs, ddr3_write_leveling_calib, ddr3_reset; wire ddr3_debug_clk_p, ddr3_debug_clk_n; // }}} wire [31:0] pxclk_debug; wire w_pxclk_cyc, w_pxclk_stb, w_pxclk_we, w_pxclk_stall, w_pxclk_ack; wire [6:0] w_pxclk_addr; wire [31:0] w_pxclk_data, w_pxclk_idata; wire [3:0] w_pxclk_sel; // Mega Net definitions // {{{ wire [7:0] w_net_rxd, w_net_txd; wire w_net_rxdv, w_net_rxerr, w_net_txctl; wire [1:0] w_net_tx_clk; reg net_last_tck; // }}} wire [8-1:0] w_led; // GPIO declarations. The two wire busses are just virtual lists // of input (or output) ports. wire [8-1:0] i_gpio; // Verilator lint_off UNUSED // Two of our outputs, o_trace and o_halt, will be unused at the top // level. wire [10-1:0] o_gpio; // Verilator lint_on UNUSED // SDIO SD Card definitions // {{{ wire w_sdio_hwreset_n, w_sdio_1p8v; wire w_sdio_cfg_ddr; wire w_sdio_cfg_ds, w_sdio_cfg_dscmd; wire [4:0] w_sdio_cfg_sample_shift; wire w_sdio_cmd_tristate; wire w_sdio_data_tristate; // wire [7:0] w_sdio_sdclk; wire w_sdio_cmd_en; wire [1:0] w_sdio_cmd_data; wire w_sdio_data_en; wire w_sdio_rx_en; wire [31:0] w_sdio_tx_data; // wire [1:0] w_sdio_cmd_strb; wire [1:0] w_sdio_cmd_idata; wire w_sdio_cmd_collision; wire w_sdio_crcack, w_sdio_crcnak; wire w_sdio_card_busy; wire [1:0] w_sdio_rx_strb; wire [15:0] w_sdio_rx_data; // wire w_sdio_ac_valid; wire [1:0] w_sdio_ac_data; wire w_sdio_ad_valid; wire [31:0] w_sdio_ad_data; wire w_sdio_ck; wire w_sdio_ds; wire [31:0] w_sdio_debug; // }}} // Clock/reset definitions // {{{ wire s_clk_200mhz, s_clk_200mhz_unbuffered, sysclk_locked, sysclk_feedback, sysclk_feedback_buffered, s_clk_250mhz, s_clk_250_unbuffered, s_clk_125mhz, s_clk_125_unbuffered, s_clk_125d, s_clk_125d_unbuffered, s_clksync, s_clksync_unbuffered, s_clk_400mhz, s_clk_400mhz_unbuffered, // Pixclk * 10 s_clk_80mhz_unbuffered, // 80MHz netclk_locked, netclk_feedback, netclk_feedback_buffered; wire i_clk_buffered; wire clocks_locked; wire dly_ctrl_ready; reg [3:0] sysclk_stable, syncd_stable; reg [4:0] pll_reset_sreg; reg pll_reset; // }}} reg [4:0] vadj33_vadj_counter; // Ethernet control (MDIO) wire w_mdio, w_mdwe; // Verilator lint_off UNUSED wire ign_cpu_stall, ign_cpu_ack; wire [31:0] ign_cpu_idata; // Verilator lint_on UNUSED // // Time to call the main module within main.v. Remember, the purpose // of the main.v module is to contain all of our portable logic. // Things that are Xilinx (or even Altera) specific, or for that // matter anything that requires something other than on-off logic, // such as the high impedence states required by many wires, is // kept in this (toplevel.v) module. Everything else goes in // main.v. // // We automatically place s_clk, and s_reset here. You may need // to define those above. (You did, didn't you?) Other // component descriptions come from the keys @TOP.MAIN (if it // exists), or @MAIN.PORTLIST if it does not. // main thedesign(s_clk, s_reset, // Quad SPI flash w_flash_cs_n, w_flash_sck, flash_dat, io_flash_dat, flash_bmod, // I2CCPU i_i2c_sda, i_i2c_scl, o_i2c_sda, o_i2c_scl, // UART/host to wishbone interface i_wbu_uart_rx, o_wbu_uart_tx, // I2CCPU i_edid_sda, i_edid_scl, o_edid_sda, o_edid_scl, // The GPS-UART i_gpsu_rx, o_gpsu_tx, // HDMI control ports hdmirx_clk, hdmi_ck, // Depending on s_siclk hdmirx_red, hdmirx_grn, hdmirx_blu, hdmitx_red, hdmitx_grn, hdmitx_blu, set_hdmi_delay, actual_hdmi_delay, pix_reset_n, pxrx_locked, hdmirx_reset_n, w_pxclk_cksel, // EDID RX definitions io_hdmirx_scl, io_hdmirx_sda, w_edidslv_scl, w_edidslv_sda, // DDR3 Controller-PHY Interface ddr3_iserdes_data, ddr3_iserdes_dqs, ddr3_iserdes_bitslip_reference, ddr3_idelayctrl_rdy, ddr3_cmd, ddr3_dqs_tri_control, ddr3_dq_tri_control, ddr3_toggle_dqs, ddr3_data, ddr3_dm, ddr3_odelay_data_cntvaluein, ddr3_odelay_dqs_cntvaluein, ddr3_idelay_data_cntvaluein, ddr3_idelay_dqs_cntvaluein, ddr3_odelay_data_ld, ddr3_odelay_dqs_ld, ddr3_idelay_data_ld, ddr3_idelay_dqs_ld, ddr3_bitslip, ddr3_write_leveling_calib, ddr3_reset, o_i2s_lrclk, o_i2s_bclk, o_i2s_mclk, o_i2s_dac, i_i2s_adc, w_pxclk_cyc, w_pxclk_stb, w_pxclk_we, w_pxclk_addr, w_pxclk_data, w_pxclk_sel, w_pxclk_stall, w_pxclk_ack, w_pxclk_idata, // Ethernet (RGMII) connections o_net_reset_n, i_net_rx_clk, w_net_rxdv, w_net_rxdv ^ w_net_rxerr, w_net_rxd, w_net_tx_clk, w_net_txctl, w_net_txd, i_sw, i_btnc, i_btnd, i_btnl, i_btnr, i_btnu, w_led, // GPIO wires i_gpio, o_gpio, // SDIO SD Card !i_sd_cd_n, // w_sdio_cfg_ddr, w_sdio_cfg_ds, w_sdio_cfg_dscmd, w_sdio_cfg_sample_shift, w_sdio_cmd_tristate, w_sdio_data_tristate, // w_sdio_sdclk, w_sdio_cmd_en, w_sdio_cmd_data, w_sdio_data_en, w_sdio_rx_en, w_sdio_tx_data, // w_sdio_cmd_strb, w_sdio_cmd_idata, w_sdio_cmd_collision, w_sdio_crcack, w_sdio_crcnak, w_sdio_card_busy, w_sdio_rx_strb, w_sdio_rx_data, // w_sdio_ac_valid, w_sdio_ac_data, w_sdio_ad_valid, w_sdio_ad_data, w_sdio_hwreset_n, w_sdio_1p8v, w_sdio_debug, // PLL generated clocks s_clk_125mhz, // The GPS 1PPS signal port i_gps_pps, o_eth_mdclk, w_mdio, w_mdwe, io_eth_mdio, // OLED control interface (roughly SPI) o_oled_sck, o_oled_mosi, o_oled_dcn, // The PMic3 microphone wires o_mic_csn, o_mic_sck, i_mic_din, // Simulation bus control for the CPU 1'b0, 1'b0, 1'b0, 7'h0, 32'h0, ign_cpu_stall, ign_cpu_ack, ign_cpu_idata, // Reset wire for the ZipCPU s_reset); // // Our final section to the toplevel is used to provide all of // that special logic that couldnt fit in main. This logic is // given by the @TOP.INSERT tag in our data files. // //////////////////////////////////////////////////////////////////////// // // QSPI Flash IO pin handling // {{{ // // Wires for setting up the QSPI flash wishbone peripheral // // // QSPI)BMOD, Quad SPI bus mode, Bus modes are: // 0? Normal serial mode, one bit in one bit out // 10 Quad SPI mode, going out // 11 Quad SPI mode coming from the device (read mode) xqflex #( .OPT_CLOCK(1'b0), .OPT_PHASE(1'b1) ) u_xqflex ( .i_clk(s_clk), .i_cs_n(w_flash_cs_n), .i_sck(w_flash_sck), .i_dat(o_flash_dat), .o_dat(i_flash_dat), .i_bmod(flash_bmod), // .o_cs_n(o_flash_cs_n), .o_sck(o_flash_sck), .io_dat(io_flash_dat) ); // The following primitive is necessary in many designs order to gain // access to the o_flash_sck pin. It's not necessary on the Arty, // simply because they provide two pins that can drive the QSPI // clock pin. wire [3:0] su_nc; // Startup primitive, no connect STARTUPE2 #( // {{{ // Leave PROG_USR false to avoid activating the program // event security feature. Notes state that such a feature // requires encrypted bitstreams. .PROG_USR("FALSE"), // Sets the configuration clock frequency (in ns) for // simulation. .SIM_CCLK_FREQ(0.0) // }}} ) STARTUPE2_inst ( // {{{ // CFGCLK, 1'b output: Configuration main clock output -- no // connect .CFGCLK(su_nc[0]), // CFGMCLK, 1'b output: Configuration internal oscillator clock // output .CFGMCLK(su_nc[1]), // EOS, 1'b output: Active high output indicating the End Of // Startup. .EOS(su_nc[2]), // PREQ, 1'b output: PROGRAM request to fabric output // Only enabled if PROG_USR is set. This lets the fabric // know that a request has been made (either JTAG or pin // pulled low) to program the device .PREQ(su_nc[3]), // CLK, 1'b input: User start-up clock input .CLK(1'b0), // GSR, 1'b input: Global Set/Reset input .GSR(1'b0), // GTS, 1'b input: Global 3-state input .GTS(1'b0), // KEYCLEARB, 1'b input: Clear AES Decrypter Key input from // BBRAM .KEYCLEARB(1'b0), // PACK, 1-bit input: PROGRAM acknowledge input // This pin is only enabled if PROG_USR is set. This // allows the FPGA to acknowledge a request for reprogram // to allow the FPGA to get itself into a reprogrammable // state first. .PACK(1'b0), // USRCLKO, 1-bit input: User CCLK input -- This is why I am // using this module at all. .USRCCLKO(o_flash_sck), // USRCCLKTS, 1'b input: User CCLK 3-state enable input // An active high here places the clock into a high // impedence state. Since we wish to use the clock as an // active output always, we drive this pin low. .USRCCLKTS(1'b0), // USRDONEO, 1'b input: User DONE pin output control // Set this to "high" to make sure that the DONE LED pin // is high. .USRDONEO(1'b1), // USRDONETS, 1'b input: User DONE 3-state enable output // This enables the FPGA DONE pin to be active. Setting // this active high sets the DONE pin to high impedence, // setting it low allows the output of this pin to be as // stated above. .USRDONETS(1'b1) // }}} ); // }}} //////////////////////////////////////////////////////////////////////// // // I2C IO buffers // {{{ // We need these in order to (properly) ensure the high impedance // states (pull ups) of the I2C I/O lines. Our goals are: // // o_i2c_X io_i2c_X Derived:T // 1'b0 1'b0 1'b0 // 1'b1 1'bz 1'b1 // IOBUF i2csclp( // {{{ .I(1'b0), .T(o_i2c_scl), .O(i_i2c_scl), .IO(io_scl) // }}} ); IOBUF i2csdap( // {{{ .I(1'b0), .T(o_i2c_sda), .O(i_i2c_sda), .IO(io_sda) // }}} ); // }}} //////////////////////////////////////////////////////////////////////// // // I2C IO buffers // {{{ // We need these in order to (properly) ensure the high impedance // states (pull ups) of the I2C I/O lines. Our goals are: // // o_edid_X io_edid_X Derived:T // 1'b0 1'b0 1'b0 // 1'b1 1'bz 1'b1 // IOBUF edidsclp( // {{{ .I(1'b0), .T(o_edid_scl), .O(i_edid_scl), .IO(io_hdmitx_scl) // }}} ); IOBUF edidsdap( // {{{ .I(1'b0), .T(o_edid_sda), .O(i_edid_sda), .IO(io_hdmitx_sda) // }}} ); // }}} //////////////////////////////////////////////////////////////////////// // // HDMI // {{{ // Ingest the HDMI data lines // {{{ xhdmiin u_hdmirx_red( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(hdmirx_reset_n), .i_delay(set_hdmi_delay[14:10]), .o_delay(actual_hdmi_delay[14:10]), .i_hs_wire({ i_hdmirx_p[2], i_hdmirx_n[2] }), .o_word(hdmirx_red) ); xhdmiin u_hdmirx_grn( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(hdmirx_reset_n), .i_delay(set_hdmi_delay[9:5]), .o_delay(actual_hdmi_delay[9:5]), .i_hs_wire({ i_hdmirx_p[1], i_hdmirx_n[1] }), .o_word(hdmirx_grn) ); xhdmiin u_hdmirx_blu( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(hdmirx_reset_n), .i_delay(set_hdmi_delay[4:0]), .o_delay(actual_hdmi_delay[4:0]), .i_hs_wire({ i_hdmirx_p[0], i_hdmirx_n[0] }), .o_word(hdmirx_blu) ); // }}} // Output the HDMI TX data lines // {{{ xhdmiout u_hdmitx_clk( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(pix_reset_n), .i_en(1'b1), .i_word(10'b11111_00000), .o_port({ o_hdmitx_clk_p, o_hdmitx_clk_n }) ); xhdmiout u_hdmitx_red( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(pix_reset_n), .i_en(1'b1), .i_word(hdmitx_red), .o_port({ o_hdmitx_p[2], o_hdmitx_n[2] }) ); xhdmiout u_hdmitx_grn( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(pix_reset_n), .i_en(1'b1), .i_word(hdmitx_grn), .o_port({ o_hdmitx_p[1], o_hdmitx_n[1] }) ); xhdmiout u_hdmitx_blu( .i_clk(hdmi_ck), .i_hsclk(hdmi_serdes_clk), .i_reset_n(pix_reset_n), .i_en(1'b1), .i_word(hdmitx_blu), .o_port({ o_hdmitx_p[0], o_hdmitx_n[0] }) ); // }}} // }}} assign io_hdmirx_scl = w_edidslv_scl ? 1'bz : 1'b0; assign io_hdmirx_sda = w_edidslv_sda ? 1'bz : 1'b0; assign s_clk = s_clksync; assign o_ddr3_vsel = 1'bz; always @(posedge s_clk or negedge clocks_locked) if (!clocks_locked) clk_reset_pipe <= 3'h7; else clk_reset_pipe <= { clk_reset_pipe[1:0], 1'b0 }; assign s_reset = clk_reset_pipe[2]; // DDR3 PHY Instantiation ddr3_phy #( // {{{ .ROW_BITS(SDRAMROW_BITS), //width of row address .BA_BITS(SDRAMBA_BITS), //width of bank address .DQ_BITS(SDRAMDQ_BITS), //width of DQ .LANES(SDRAMBYTE_LANES), //8 lanes of DQ .CONTROLLER_CLK_PERIOD(SDRAMCONTROLLER_CLK_PERIOD), //ns, period of clock input to this DDR3 controller module .DDR3_CLK_PERIOD(DDR3_CLK_PERIOD), //ns, period of clock input to DDR3 RAM device .ODELAY_SUPPORTED(1) // }}} ) ddr3_phy_inst ( // {{{ // clock and reset .i_controller_clk(s_clksync), .i_ddr3_clk(s_clk_400mhz), .i_ref_clk(s_clk_200mhz), .i_ddr3_clk_90(0), //required only when ODELAY_SUPPORTED is zero .i_rst_n(!s_reset), // Controller Interface .i_controller_reset(ddr3_reset), .i_controller_cmd(ddr3_cmd), .i_controller_dqs_tri_control(ddr3_dqs_tri_control), .i_controller_dq_tri_control(ddr3_dq_tri_control), .i_controller_toggle_dqs(ddr3_toggle_dqs), .i_controller_data(ddr3_data), .i_controller_dm(ddr3_dm), .i_controller_odelay_data_cntvaluein(ddr3_odelay_data_cntvaluein), .i_controller_odelay_dqs_cntvaluein(ddr3_odelay_dqs_cntvaluein), .i_controller_idelay_data_cntvaluein(ddr3_idelay_data_cntvaluein), .i_controller_idelay_dqs_cntvaluein(ddr3_idelay_dqs_cntvaluein), .i_controller_odelay_data_ld(ddr3_odelay_data_ld), .i_controller_odelay_dqs_ld(ddr3_odelay_dqs_ld), .i_controller_idelay_data_ld(ddr3_idelay_data_ld), .i_controller_idelay_dqs_ld(ddr3_idelay_dqs_ld), .i_controller_bitslip(ddr3_bitslip), .i_controller_write_leveling_calib(ddr3_write_leveling_calib), .o_controller_iserdes_data(ddr3_iserdes_data), .o_controller_iserdes_dqs(ddr3_iserdes_dqs), .o_controller_iserdes_bitslip_reference(ddr3_iserdes_bitslip_reference), .o_controller_idelayctrl_rdy(ddr3_idelayctrl_rdy), // DDR3 I/O Interface .o_ddr3_clk_p(o_ddr3_clk_p), .o_ddr3_clk_n(o_ddr3_clk_n), .o_ddr3_reset_n(o_ddr3_reset_n), .o_ddr3_cke(o_ddr3_cke[0]), // CKE .o_ddr3_cs_n(o_ddr3_cs_n[0]), // chip select signal (controls rank 1 only) .o_ddr3_ras_n(o_ddr3_ras_n), // RAS# .o_ddr3_cas_n(o_ddr3_cas_n), // CAS# .o_ddr3_we_n(o_ddr3_we_n), // WE# .o_ddr3_addr(o_ddr3_a[SDRAMROW_BITS-1:0]), .o_ddr3_ba_addr(o_ddr3_ba), .io_ddr3_dq(io_ddr3_dq), .io_ddr3_dqs(io_ddr3_dqs_p), .io_ddr3_dqs_n(io_ddr3_dqs_n), .o_ddr3_dm(o_ddr3_dm), .o_ddr3_odt(o_ddr3_odt[0]), // on-die termination // DEBUG PHY .o_ddr3_debug_read_dqs_p(ddr3_debug_read_dqs_p), .o_ddr3_debug_read_dqs_n(ddr3_debug_read_dqs_n) // }}} ); generate for(ddr3gen_index = SDRAMROW_BITS; ddr3gen_index < 15; ddr3gen_index = ddr3gen_index + 1) begin : GEN_UNUSED_SDRAM_ASSIGN assign o_ddr3_a[ddr3gen_index] = 0; end endgenerate //////////////////////////////////////////////////////////////////////// // // HDMI Clock generation // {{{ xpxclk u_xpxclk ( .i_sysclk(s_clk), // System clock .i_cksel(w_pxclk_cksel), // Clock select switch // .i_hdmirx_clk_p(i_hdmirx_clk_p), // HDMI RX input clock .i_hdmirx_clk_n(i_hdmirx_clk_n), .i_lcl_pixclk(s_clk_80mhz_unbuffered), // Locally generated clk .i_siclk(s_clk_80mhz_unbuffered), // .o_hdmick_locked(pxrx_locked), .o_hdmirx_clk(hdmirx_clk), // Clk for measurement only .o_pixclk(hdmi_ck), // Pixel clock .o_hdmick(hdmi_serdes_clk), // HS pixel clock // .i_wb_clk(s_clk), // .i_wb_cyc(w_pxclk_cyc), .i_wb_stb(w_pxclk_stb), .i_wb_we(w_pxclk_we), .i_wb_addr(w_pxclk_addr[7-1:0]), .i_wb_data(w_pxclk_data), // 32 bits wide .i_wb_sel(w_pxclk_sel), // 32/8 bits wide .o_wb_stall(w_pxclk_stall),.o_wb_ack(w_pxclk_ack), .o_wb_data(w_pxclk_idata), // .o_debug(pxclk_debug) ); // }}} // RGMII control // {{{ xiddr netrx0(i_net_rx_clk, i_net_rxd[0], { w_net_rxd[4], w_net_rxd[0] }); xiddr netrx1(i_net_rx_clk, i_net_rxd[1], { w_net_rxd[5], w_net_rxd[1] }); xiddr netrx2(i_net_rx_clk, i_net_rxd[2], { w_net_rxd[6], w_net_rxd[2] }); xiddr netrx3(i_net_rx_clk, i_net_rxd[3], { w_net_rxd[7], w_net_rxd[3] }); xiddr netrxc(i_net_rx_clk, i_net_rx_ctl, { w_net_rxdv, w_net_rxerr }); // // All of the below is about delaying the clock 90 degrees from the data // xoserdes nettx0(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_net_txd[0]}}, {(2){w_net_txd[4]}} }, o_net_txd[0]); xoserdes nettx1(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_net_txd[1]}}, {(2){w_net_txd[5]}} }, o_net_txd[1]); xoserdes nettx2(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_net_txd[2]}}, {(2){w_net_txd[6]}} }, o_net_txd[2]); xoserdes nettx3(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_net_txd[3]}}, {(2){w_net_txd[7]}} }, o_net_txd[3]); always @(posedge s_clk_125mhz) net_last_tck <= w_net_tx_clk[0]; xoserdes nettxc(s_clk_125mhz, pll_reset, s_clk_250mhz, {(4){w_net_txctl}}, o_net_tx_ctl ); xoserdes nettxck(s_clk_125mhz, pll_reset, s_clk_250mhz, {net_last_tck, {(2){w_net_tx_clk[1]}},w_net_tx_clk[0]},o_net_tx_clk); // xoserdes nettxck(s_clk_125mhz, pll_reset, s_clk_250mhz, { {(2){w_net_tx_clk[1]}},{(2){w_net_tx_clk[0]}} }, o_net_tx_clk); // }}} assign o_led = { w_led[8-1:3], (w_led[2] || !syncd_stable[3]), (w_led[1] || !clocks_locked), (w_led[0] || s_reset) }; //////////////////////////////////////////////////////////////////////// // // GPIO adjustments // {{{ assign i_gpio = { 8'h0, pxrx_locked, sysclk_locked, `ifdef GPSTRK_ACCESS i_gps_3df, `else 1'b0, `endif !i_hdmitx_hpd_n, // Hotplug detect !i_sd_cd_n, 1'b0, i_hdmitx_cec, i_hdmirx_cec }; assign o_hdmirx_txen = o_gpio[2]; assign o_hdmirx_hpa = o_gpio[3]; // Hotplug assert assign o_sd_reset = !w_sdio_hwreset_n; assign o_oled_reset_n = !o_gpio[5]; assign o_oled_panel_en = o_gpio[6]; assign o_oled_logic_en = o_gpio[7]; // These two pins are only used in simulation, and only within the // MAIN RTL component. // assign o_trace = o_gpio[8]; // assign o_halt = o_gpio[9]; // }}} sdfrontend #( .OPT_SERDES(1'b1), .OPT_DDR(1'b1), .NUMIO(4), .BUSY_CLOCKS(16), .OPT_CRCTOKEN(1) ) u_sdio_frontend ( // {{{ .i_clk(s_clk), .i_hsclk(s_clk_400mhz), .i_reset(s_reset), // Configuration .i_cfg_ddr(w_sdio_cfg_ddr), .i_cfg_ds(w_sdio_cfg_ds), .i_cfg_dscmd(w_sdio_cfg_dscmd), .i_sample_shift(w_sdio_cfg_sample_shift), .i_cmd_tristate(w_sdio_cmd_tristate), .i_data_tristate(w_sdio_data_tristate), // Run-time inputs .i_sdclk(w_sdio_sdclk), .i_cmd_en(w_sdio_cmd_en), .i_cmd_data(w_sdio_cmd_data), .i_data_en(w_sdio_data_en), .i_rx_en(w_sdio_rx_en), .i_tx_data(w_sdio_tx_data), // Return values .o_cmd_strb(w_sdio_cmd_strb), .o_cmd_data(w_sdio_cmd_idata), .o_cmd_collision(w_sdio_cmd_collision), .o_crcack(w_sdio_crcack), .o_crcnak(w_sdio_crcnak), .o_data_busy(w_sdio_card_busy), .o_rx_strb( w_sdio_rx_strb), .o_rx_data( w_sdio_rx_data), // .MAC_VALID(w_sdio_ac_valid), .MAC_DATA( w_sdio_ac_data), .MAD_VALID(w_sdio_ad_valid), .MAD_DATA( w_sdio_ad_data), // IO ports .o_ck(w_sdio_ck), .i_ds(w_sdio_ds), .io_cmd(io_sd_cmd), .io_dat(io_sd_dat), .o_debug(w_sdio_debug) // }}} ); assign o_sd_clk = w_sdio_ck; assign w_sdio_ds = 1'b0; // Buffer the incoming clock BUFG masterclkclkbufi(.I(i_clk), .O(i_clk_buffered)); // pll_reset initial { pll_reset, pll_reset_sreg } = -1; always @(posedge i_clk_buffered) { pll_reset, pll_reset_sreg } <= { pll_reset_sreg, 1'b0 }; //////////////////////////////////////////////////////////////////////// // // PLL #1: 100MHz, 200MHz, 400MHz, and 80MHz // {{{ //////////////////////////////////////////////////////////////////////// // // // But ... the delay controller requires a 200 MHz reference clock, // the generic clock generator requires a 400MHz clock and a clock // synchronized to it PLLE2_BASE #( // {{{ .CLKFBOUT_MULT(8), .CLKFBOUT_PHASE(0.0), .CLKIN1_PERIOD(10), .CLKOUT0_DIVIDE(4), // 200 MHz .CLKOUT1_DIVIDE(2), // 400 MHz .CLKOUT2_DIVIDE(8), // 100 MHz .CLKOUT3_DIVIDE(10) // 80 MHz // }}} ) gen_sysclk( // {{{ .CLKIN1(i_clk_buffered), .CLKOUT0(s_clk_200mhz_unbuffered), .CLKOUT1(s_clk_400mhz_unbuffered), .CLKOUT2(s_clksync_unbuffered), .CLKOUT3(s_clk_80mhz_unbuffered), // .CLKOUT4(), // .CLKOUT5(), .PWRDWN(1'b0), .RST(pll_reset), .CLKFBOUT(sysclk_feedback), .CLKFBIN(sysclk_feedback_buffered), .LOCKED(sysclk_locked) // }}} ); BUFG sysbuf( .I(s_clk_200mhz_unbuffered),.O(s_clk_200mhz)); BUFG clksync_buf(.I(s_clksync_unbuffered), .O(s_clksync)); BUFG clk4x_buf( .I(s_clk_400mhz_unbuffered),.O(s_clk_400mhz)); BUFG sys_feedback(.I(sysclk_feedback),.O(sysclk_feedback_buffered)); // }}} //////////////////////////////////////////////////////////////////////// // // PLL #2: 125MHz, 250MHz // {{{ //////////////////////////////////////////////////////////////////////// // // // The ethernet MAC requires a 125MHz clock // We can't trust the RX 125MHz clock for this, since there's a // possibility the RX 125MHz clock might arrive at a different rate. // PLLE2_BASE #( // {{{ .CLKFBOUT_MULT(10), .CLKFBOUT_PHASE(0.0), .CLKIN1_PERIOD(10), .CLKOUT0_DIVIDE(8), // 125 MHz .CLKOUT0_PHASE(0), .CLKOUT1_DIVIDE(4), // 250 MHz .CLKOUT1_PHASE(0) // }}} ) gen_netclk( // {{{ .CLKIN1(i_clk_buffered), .CLKOUT0(s_clk_125_unbuffered), .CLKOUT1(s_clk_250_unbuffered), // .CLKOUT2(), // .CLKOUT3(), // .CLKOUT4(), // .CLKOUT5(), .PWRDWN(1'b0), .RST(pll_reset), .CLKFBOUT(netclk_feedback), .CLKFBIN(netclk_feedback_buffered), .LOCKED(netclk_locked) // }}} ); BUFG netbuf(.I(s_clk_125_unbuffered), .O(s_clk_125mhz)); BUFG netbf5(.I(s_clk_250_unbuffered), .O(s_clk_250mhz)); BUFG netfb(.I(netclk_feedback), .O(netclk_feedback_buffered)); assign clocks_locked = (netclk_locked && sysclk_locked && dly_ctrl_ready); // }}} //////////////////////////////////////////////////////////////////////// // // reg [3:0] sysclk_stable; // {{{ initial sysclk_stable = 0; always @(posedge i_clk_buffered or negedge clocks_locked) if (!clocks_locked) sysclk_stable <= 0; else sysclk_stable <= { sysclk_stable[2:0], 1'b1 }; initial syncd_stable = 0; always @(posedge i_clk_buffered) if (!sysclk_stable[3]) syncd_stable <= 0; else syncd_stable <= { syncd_stable[2:0], 1'b1 }; // }}} //////////////////////////////////////////////////////////////////////// // // IDELAYCTRL IDELAYCTRL u_delay_control ( .REFCLK(s_clk_200mhz), .RST(!sysclk_locked), .RDY(dly_ctrl_ready) ); assign o_vadj = 2'b11; initial vadj33_vadj_counter = 0; always @(posedge i_clk_buffered) if (!vadj33_vadj_counter[4]) vadj33_vadj_counter[4] <= vadj33_vadj_counter[4] + 1; assign o_vadj_en = vadj33_vadj_counter[4]; assign io_eth_mdio = (w_mdwe)?w_mdio : 1'bz; endmodule // end of toplevel.v module definition ================================================ FILE: doc/Makefile ================================================ ################################################################################ ## ## Filename: doc/Makefile ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: To coordinate the build of documentation PDFs from their ## LaTeX sources. ## ## Targets include: ## all Builds all documents ## ## gpl-3.0.pdf Builds the GPL license these files are released ## under. ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2015-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} all: gpl pdf: gpl spec DSRC := src .PHONY: gpl ## {{{ gpl: gpl-3.0.pdf gpl-3.0.pdf: $(DSRC)/gpl-3.0.tex latex $(DSRC)/gpl-3.0.tex latex $(DSRC)/gpl-3.0.tex dvips -q -z -t letter -P pdf -o gpl-3.0.ps gpl-3.0.dvi ps2pdf -dAutoRotatePages=/All gpl-3.0.ps gpl-3.0.pdf rm gpl-3.0.dvi gpl-3.0.log gpl-3.0.aux gpl-3.0.ps ## }}} .PHONY: spec ## {{{ spec: spec.pdf spec.pdf: $(DSRC)/spec.tex $(DSRC)/gqtekspec.cls $(DSRC)/GT.eps cd $(DSRC)/; latex spec.tex cd $(DSRC)/; latex spec.tex cd $(DSRC)/; dvips -q -z -t letter -P pdf -o ../spec.ps spec.dvi ps2pdf -dAutoRotatePages=/All spec.ps spec.pdf -grep -i warning $(DSRC)/spec.log @rm -f $(DSRC)/spec.dvi $(DSRC)/spec.log @rm -f $(DSRC)/spec.aux $(DSRC)/spec.toc @rm -f $(DSRC)/spec.lot $(DSRC)/spec.lof @rm -f $(DSRC)/spec.out spec.ps ## }}} .PHONY: clean ## {{{ clean: rm -f $(DSRC)/spec.dvi $(DSRC)/spec.log rm -f $(DSRC)/spec.aux $(DSRC)/spec.toc rm -f $(DSRC)/spec.lot $(DSRC)/spec.lof rm -f $(DSRC)/spec.out spec.ps spec.pdf rm -f gpl-3.0.pdf ## }}} ================================================ FILE: doc/bus.md ================================================ ## Bus Declarations Before creating any bus-based components, you'll want to declare the bus that these components will connect to. This is primarily done through the `BUS.NAME`, `BUS.TYPE`, `BUS.CLOCK`, and `BUS.WIDTH` tags. `BUS.NAME` gives the bus a short-hand name that you can then use to reference it within other design components. `BUS.TYPE` names the protocol used by the bus. As of this writing, AutoFPGA supports three bus types: `wb` for Wishbone (B4 pipeline), `axil` for AXIr-Lite, and `axi` for the AXI4 bus types. `BUS.WIDTH` defines the data width of the bus. The bus address width will be defined internally based upon the minimum address width required to address all of your components. Once addresses have been assigned, `BUS.AWID` may be used to reference the number of addressing wires used and defined by this bus. This is separate from the per-component `AWID` tag which may be used to reference the number of address bits used an individual component. As with the clocks, you can define as many buses as you want within your design. However, only one bus can be defined per component, i.e. per `@PREFIX` tag, lest the `@BUS` tags overwrite each other. As an example, the following defines a 32-bit Wishbone bus, ```text @PREFIX=mywb_definition @BUS.NAME=mywb @BUS.TYPE=wb @BUS.CLOCK=clk @BUS.WIDTH=32 ``` ================================================ FILE: doc/clocks.md ================================================ ## Defining clocks The first item you'll want to define within your design is a clock. You may define more than one in your design, and design elements may use them at will, but you may only define one clock within any component. For this reason, I typically create a component for each of my clock definitions. ```text @CLOCK.NAME=clk @CLOCK.WIRE=i_clk @CLOCK.FREQUENCY=100000000 ``` This defines a clock known to AutoFPGA as `clk`. Within your `main.v` design file it will be known as `i_clk`. ## Associating a reset Often clock domains also have a reset associated with them. For this reason, AutoFPGA allows the definition of an associated reset. ```text @CLOCK.RESET=i_reset ``` This is primarily a convenience definition that you can use if you wish. It may also be used by the bus composer, by any design whose bus doesn't have an associated reset. This will then be used as the reset for that bus, otherwise AutoFPGA may generate an error that the bus has no associated reset wire. ## Default clock and reset The clock named `i_clk` is special. It is automatically passed to the `main` module for you. To make this work, you'll need a clock in your top level named `s_clk`, that will then be forwarded directly to your main module. From the top level, AutoFPGA's generated code will look like, ```verilog module toplevel(i_clk, /* ... */); input wire i_clk; /* Your code here */ main themain(s_clk, s_reset, ... ``` For this reason, you'll want to define a clock named `s_clk` in your top level. You'll also want to define `s_reset`. These can be as simple as defining these two wires, ```text @TOP.DEFNS= wire s_clk, s_reset; ``` and then adding the `TOP.INSERT` tag to your clock definition, ```text @TOP.INSERT= assign s_clk = i_clk; assign s_reset = 1'b0; ``` If your external clock needs to have a top level port assigned to it, then you'll want to use the `CLOCK.TOP` tag to specify its name. For example, the following defines a 50MHz input clock, transformed via logic to become the 50MHz top level clock. (Normally I'd recommend using a PLL, but due to a mistake during board design, the PLL wasn't available for this pin.) ```text @PREFIX=clk @CLOCK.TOP=i_clk @CLOCK.NAME=clk @CLOCK.RESET=i_reset @TOP.DEFNS= reg clk_50mhz; wire s_clk, s_reset; @TOP.INSERT= assign s_reset = 1'b0; initial clk_50mhz = 1'b0; always @(posedge i_clk) clk_50mhz <= !clk_50mhz; SB_GB global_buffer(clk_50mhz, s_clk); @CLOCK.FREQUENCY= 50000000 ``` ================================================ FILE: doc/constraints.md ================================================ ## Adjusting Constraint files One of the challenges associated with adding and removing components from a design is that the constraint files also need to be adjusted as well. AutoFPGA provides some support for doing this across several architectures. The basic idea is that you would declare an original constraint file to AutoFPGA. This needs to be done at the top level of your design, before any PREFIX tags in a given file. ```text XDC.FILE=../nexysv.xdc ``` AutoFPGA will then reference that file when building a new XDC file. ## XDC file support For example, if you give AutoFPGA an `XDC.FILE` tag, as shown above, then AutoFPGA will create a new XDC file based upon it. Specifically, it will uncomment any lines in your XDC file defining ports used by your component, and it will also insert any `XDC.INSERT` tags required by your component into the newly produced XDC file. All you need to do then is to maintain a master XDC file where all of the various I/O port definitions are commented. AutoFPGA will then uncomment only the ports defined in your `TOP.PORTLIST` tag--or alternatively your `MAIN.PORTLIST` tag if no `TOP.PORTLIST` tag is defined. For example, in my ethernet component, I need to define a series of false paths. These are only used if the ethernet component is included into the design. Therefore, they are placed into the `XDC.INSERT` tag. ``` @XDC.INSERT= set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *netctrl/tx*}] -to [get_cells -hier -filter {NAME=~*netctrl/n_tx*}] 8.0 set_max_delay -datapath_only -from [get_cells -hier -filter {NAME=~ *netctrl/hw_mac*}] -to [get_cells -hier -filter {NAME=~*netctrl/txmaci/r_hw*}] 8.0 ``` ## Other Constraint Files AutoFPGA has similar support for UCF and PCF files. ================================================ FILE: doc/double.md ================================================ # Double Slave Definitions AutoFPGA defines two special classes of slaves, `SINGLE` and `DOUBLE`. These classes are used to help AutoFPGA coalesce bus logic together, while simplifying your design. The `DOUBLE` slave describes a slave that may have many registers, that never stalls, and whose register values may be read with a single clock cycle delay. It's almost as simple as the `SINGLE` slave to create. ```text @PREFIX=wb_double_example @SLAVE.NADDR=2 @SLAVE.BUS=wbbus @SLAVE.TYPE=DOUBLE @MAIN.DEFNS= reg [31:0] r_@$(PREFIX)_0, r_@$(PREFIX)_b, r_@$(PREFIX)_rdata; @MAIN.INSERT= initial r_@$(PREFIX)_0 = 0; always @(posedge i_clk) if (@$(SLAVE.PREFIX)_stb && !@$(SLAVE.PREFIX)_addr[0]) r_@$(PREFIX)_0 <= @$(SLAVE.PREFIX)_data; else if (r_@$(PREFIX)_0 > 0) r_@$(PREFIX)_0 <= r_@$(PREFIX)_0 - 1; initial r_@$(PREFIX)_1 = 0; always @(posedge i_clk) if (@$(SLAVE.PREFIX)_stb && @$(SLAVE.PREFIX)_addr[0]) r_@$(PREFIX)_1 <= @$(SLAVE.PREFIX)_data; else if (r_@$(PREFIX)_1 > 0) r_@$(PREFIX)_1 <= r_@$(PREFIX)_1 - 1; always @(posedge i_clk) case (@$(SLAVE.PREFIX)_addr[0]) 1'b0: r_@$(PREFIX)_data <= r_@$(PREFIX)_0; 1'b1: r_@$(PREFIX)_data <= r_@$(PREFIX)_1; endcase assign @$(SLAVE.PREFIX)_idata = r_@$(PREFIX)_rdata; ``` This will create your slave and connect it to the bus named `wbbus`. Any attempt to read from your slave will return the value `r_@$(PREFIX)_rdata`, which was itself calculated from the bus address given to it one clock prior. Building this same example for an AXI or AXI-Lite bus is almost the same, only that you also need to define values for `@$(SLAVE.PREFIX)_bresp` and `@$(SLAVE.PREFIX)_rresp`. Further, AXI slave addresses are octet based, whereas Wishbone addresses are word based. Hence we'll check awaddr[2] instead of addr[0]. ```text @PREFIX=wb_double_example @SLAVE.NADDR=2 @SLAVE.BUS=axilbus @SLAVE.TYPE=DOUBLE @MAIN.INSERT= initial r_@$(PREFIX)_0 = 0; always @(posedge i_clk) if (@$(SLAVE.PREFIX)_awvalid && !@$(SLAVE.PREFIX)_awaddr[2]) r_@$(PREFIX)_0 <= @$(SLAVE.PREFIX)_data; else if (r_@$(PREFIX)_0 > 0) r_@$(PREFIX)_0 <= r_@$(PREFIX)_0 - 1; initial r_@$(PREFIX)_1 = 0; always @(posedge i_clk) if (@$(SLAVE.PREFIX)_stb && @$(SLAVE.PREFIX)_addr[2]) r_@$(PREFIX)_1 <= @$(SLAVE.PREFIX)_data; else if (r_@$(PREFIX)_1 > 0) r_@$(PREFIX)_1 <= r_@$(PREFIX)_1 - 1; always @(posedge i_clk) case (@$(SLAVE.PREFIX)_addr[0]) 1'b0: r_@$(PREFIX)_data <= r_@$(PREFIX)_0; 1'b1: r_@$(PREFIX)_data <= r_@$(PREFIX)_1; endcase assign @$(SLAVE.PREFIX)_rdata = r_@$(PREFIX)_rdata; ``` When creating an AXI or AXI-Lite `DOUBLE` slave, AutoFPGA will use one of the bus simplifiers found in the [WB2AXIP](https://github.com/ZipCPU/wb2axip) repository, either [AXIDOUBLE](https://github.com/ZipCPU/wb2axip/blob/master/rtl/axisingle.v) or [AXILDOUBLE](https://github.com/ZipCPU/wb2axip/blob/master/rtl/axilsingle.v). These drivers will guarantee for you that the respective `xREADY` lines remain high, and that `AWVALID == WVALID` (and more). All you therefore need to do is to check `WVALID` to know when to adjust your counter. For more information about these bus drivers, please see their internal documentation. As with the `SINGLE` slaves, AutoFPGA defines a `@SLAVE.PORTLIST` tag that expands into a list of all of your design ports. This makes it easier to design an AXI slave from a submodule. ```text @MAIN.INSERT= mymodule @$(PREFIX)i (i_axi_aclk, i_axi_aresetn, @$(SLAVE.PORTLIST)); ``` ================================================ FILE: doc/goals.txt ================================================ 1. Be able to create a project from a series of configuration files, where each file specifies a component of the ultimate project. 2. Maintain the look/feel of an open source project All source should be readable, and maintainable. This includes any component configuration/description files 3. Turn into a full Verilog/C/C++ project Code should be "added" at appropriate points down stream Removing a component should just take appropriate code sections out later. Configuration files should consist of those data portions necessary to cut/copy/paste into a project to get it up and running. The result should therefore be as though someone had configured the project by hand and included the new component, only that the auto-component compiler had done the configuration work instead. 4. Preserve the ability to have comments in the ultimate source code. Such comments should be able to pass through the configuration files ================================================ FILE: doc/icd.txt ================================================ AutoFPGA does all of its work based upon KEY/VALUE pairs. Key/value pairs are organized into a hierarchical, but unordered, structure which is then referenced by the logic that follows. The values themselves are either strings or numbers. Lines defining keys may begin as: @KEY= Defining a given key @$KEY= Defines a numeric key value that may need to be evaluated @KEY+= Concatenates the following onto the pre-existing string key. If the key does not (yet) exist, it is created and initialized to this value. @/KEY= References a global key @/KEY+= Concatenates onto a global key Lines not defining keys are either comment lines (lines beginning with either ## or # and a space), or lines appended to the value of the last key. AutoFPGA document lines starting with @ specify a key name. Lines starting with a @$ specify an integer valued expression. The key is given by the string between the @ (or @$) and the ='s (minus any white space at the end, white space at the beginning is not allowed). KEYs are case sensitive. By convention, KEYs are in all caps, although keys with lower case letters are allowed and used as names of particular file components. For the discussion below, any keys will be identified by prefixing the key name with an @ sign. Comments. Lines beginning with either two hash marks, ##, or a single hash followed by a space, as in "# ", are comment lines. Other lines beginning with "#", such as #define, are not comments, neither do lines containing "#" in any location other than the first location contain comments. KEYs are by convention all capitals. They are also hierarchical. Hence, a key BDEFS.IONAME references the BDEFS set of key-value pairs, with the keyname IONAME within that set. Every device or bus master *must* contain a @PREFIX key. This key will be used as a unique string to identify the device. As parsing takes place, all of the keys for a given device will be placed into a key-value set prefixed by the @PREFIX key. Hence, for a device with name @PREFIX=uart, a definition such as @NADDR=4 creates a key named @uart.NADDR and gives it the value 4. Keys defined prior to the first @PREFIX key are global keys, and are not given any @PREFIX in front of them prior to being inserted into the master key-value mapping. Key definitions beginning with @$ are integer expressions that will be evaluated before use. Further, strings may reference other parts of the key-value mapping by placing a @$ in front of a key name. This value will then be replaced by the value once that value is known. Expressions may also be used when assigning to things such as @$KEY, as in ... @$KEY.EXPR=(1<<20) @KEY.FORMAT=0x%08x @KEY.VAL will be created with the calculated value @KEY.STR will be created with the value formated as desired into a string Once this expression has a value, a new key will be created, KEY.VAL, having the integer value of this expression. This value may be referenced via the base @KEY. Further, this value will be substituted wherever @$KEY exists within any other VALUE's. Which value it gets, either the number or the string, is dependent upon the context and how it is referenced. Peripheral devices *must* also contain a @SLAVE.TYPE key. This key can have one of the following values: SINGLE A peripheral with no internal address decoding, but whose output value (@PREFIX_data) is valid on any given clock. These peripherals are not allowed to stall the bus. These peripherals will be collected together. DOUBLE A peripheral with internal address decoding, but no delays. Hence, the data value for this peripheral will always be valid one clock after the select line goes high. These peripherals are not allowed to stall the bus. These peripherals will also be collected together. MEMORY A peripheral including information that needs to be placed into a linker script. Examples of MEMORY can be block RAM's, SDRAM, or even FLASH. MEMORY that fits the criteria for DOUBLE is also best given the MEMORY attribute instead. BUS This slave is a bus translator. It acts as a slave on its given bus, but has a bus (MASTER) interface beneath it OTHER Any peripheral that doesn't match the above. Other tags include ACCESS This is a STRING that will be turned into a DEFINE and a couple IFDEFs in the main.v file. The idea is, if this string is defined, then the components logic will be included, otherwise not. DEPENDS If the logic of one component is dependent upon another, set the DEPENDS tag to be a list of ACCESS parameters upon which this component depends upon. The ACCESS item for this parameter will then be turned off if it's dependencies are not met. Dependencies beginning with a "!" are negative dependencies. Hence, the ACCESS tag will only be true if the dependency ifdef is *not* defined. (No spaces are allowed between the ! and the dependency ID) NADDR The number of uniquely addressable registers/ports this device has ERROR.WIRE The name of a wire set by the module, which (if set) will cause a bus error. Components should only set this if they are being accessed. INCLUDEFILE Defines a file with default key values within it. If those key values are then not defined in the main file, the include file will be checked for default values. The include path searched can be controlled via the '-I' command line option. TOP.PORTLIST This string gets added into the toplevel( portlist ) declaration, allowing each peripheral to control external wires. If not specified, this is given by MAIN.PORTLIST. TOP.IODECL This string includes the declarations for the portlist above, such as output wire o_value. If not specified, this is given by MAIN.IODECL. TOP.DEFNS Defines variables in toplevel.v TOP.MAIN This string gets added into the main module instantiation, between the ( parentheses ). TOP.INSERT Some peripherals need some cleanup. Hence, after instantiating main, these need to do some logic. Any variables needed here need to have been declared in TOP.DEFNS. MAIN.INCLUDE Specicies logic to be placed before module main in main.v MAIN.PARAM Logic placed after the PORTLIST in main.v, used to define parameters MAIN.PORTLIST Same as TOP.PORTLIST, only as applied to the main.v file MAIN.IODECL Same as TOP.IODECL, only as applied to the main.v file MAIN.DEFNS Logic defined after PARAM, PORTLIST, and IODECL. Used to define global registers or wires used by this component MAIN.INSERT MAIN.ALT BASE (Created and used internally) This is the base address of the given peripheral within its current bus REGBASE (Created and used internally) This is the base address of the given peripheral from an external bus address reference. MASK (Created and used internally) AWID Address width, in terms of # of address lines, used by this component REGDEFS.H.INCLUDE Placed at the top of the regdefs.h file REGS.NOTE A comment to be placed at the beginning of the register list for this peripheral REGS.N The number of registers this peripheral has. AutoFPGA will then look for keys of the form REGS.0 through REGS.(REGS.N-1). REGS.0...? Describes a register by name. The first value is the offset within the address space of this device. The second token is a string defining a C #def'd constant. The third and subsequent tokens represent human readable names that may be associated with this register. REGDEFS.H.DEFNS Placed with other definitions within regdefs.h REGDEFS.H.INSERT Placed in regdefs.h following all of the definitions I may change this to the following notation, though: REGSDEFS.NOTE REGS..ADDR # Offset within the peripheral REGS..UNAME(s) # User-readable name REGS..DESC(ription for LaTeX) BDEF.INCLUDE Gets placed at the top of the board definitions file, and is used to insert references for any particular include files into the board file. Include files are not ordered by dependency, so they should either be independent of each other, or they should reference any other component they use. BDEF.DEFN A list of lines defining anything that needs to be defined inside the board component description. This might include, for example, a type for the component or particular defines that define things associated with the component BDEF.IONAME The name given to this component in the board.h file BDEF.IOTYPE The name of a type, describing the structure of the memory begin pointed to. BDEF.OSDEF Contains the name of a value that will be #define'd if this component is included in the design, and not otherwise BDEF.OSVAL A definition line, to be placed into the board definitions file, that is then used to define a pointer to this type of object // Likely to default, in the future, to static volatile @BDEF.IOTYPE *const @BDEF.IONAME = &((@BDEF.IOTYPE *)@BASE); (deprecated) IONAME (not BDEF.IONAME) (deprecated) CSTRUCT (now BDEF.DEFN) XDC.FILE If present, autofpga will open this file and look through it for commented lines defining pins that exist in our top level port list. Lines beginning with a #, but not ##, will be uncommented and added the build.xdc file. If no XDC.FILE key is given, then the build.xdc file will not be created. XDC.INSERT This line, if present, gets inserted verbatim at the bottom of the generated XDC file UCF.FILE Does the same thing with a UCF file as was done with the XDC.FILE, creating a build.ucf file when done. UCF.INSERT Adds lines to the UCF file, just as with the XDC.INSERT tag does for the XDC file. PCF.FILE Does the same thing with a UCF file as was done with the XDC.FILE, creating a build.pcf file when done. PCF.INSERT Adds lines to the PCF file, just as with the XDC.INSERT tag does for the XDC file. LD.FILE Name of the linker script to generate. The linker script will reflect memory components found beneath the component containing this file. LD.SCRIPT Contains a customized script LD.ENTRY The name of the entry symbol in the linker script. LD.DEFNS (Any definitions to be added to the linker script) If the peripheral has an LD.FILE attribute, the LD.DEFNS will not be included in any other linker scripts LD.PERM The permissions a memory region has before the linker. This is either r, rx, or wx. See the documentation for binutils/ld for more details of this field LD.NAME The name of this peripheral, as it appears in the linker script PIC.BUS The name of a parameter to hold all of the interrupt wires PIC.MAX The maximum number of interrutps this one can have INT.NAME.WIRE Specifies that an interrupt with C #define name NAME is connected to the internal wire with its name given by this key INT.NAME.PIC Identifies which PIC this wire is connected to. Any particular interrupt may be assigned to multipl PICs. If so, these are listed on this line and separated by white space INT.NAME.ID Identifies which interrupt wire this device it connected to OUT.FILE Creates an output file by this name OUT.DATA Places this information within the data file RTL.MAKE.GROUP A make variable name which will contain the file list for this component RTL.MAKE.FILES The files composing this component RTL.MAKE.SUBD The location of the Verilog files for this component SIM.DEFINES #define's follow any #includes. You can place those here. SIM.DEFNS Any variables necessary in the Verilog simulation class can be defined within this tag. SIM.INCLUDE Place any #includes here. #includes will be included before anything else SIM.INIT If variables need to be initialized when the verilog simulation object is initialized, place that initialization code within this tag SIM.CLRRESET CLRRESET code goes in the same block as the reset method, but gets called after the reset tick. SIM.CLOCK Specifies the clock that is used for the SIM.TICK method. Only one clock is allowed. If you need another, make another component using the other clock. SIM.DBGCONDITION If you might need to debug your component, you can put a debug condition here. The condition code should set the bool "writeout" to true, or leave it as it is. SIM.DEBUG If you are doing debug by printf, place any of your printf debug lines in this tag SIM.LOAD If your component is a memory that might need to be loaded when your program is loaded into the simulation, you'll need to define this component. Your code will be passed a "start" offset into your address region, a buffer pointer, buf, an "offset" into that buffer, and a length (wlen) to copy from the buffer into your memory area. SIM.METHODS If your code requires the definition of methods to be used within the Verilator simulator class, place those definitions here. SIM.SETRESET If your component has specific simulation actions that need to take place when the reset pin is set high, place that code in this block. SIM.TICK If you want your simulation software to be called as part of a simulation tick, place that code within this tag CLOCK.NAME A list of the clocks used by this component CLOCK.WIRE A list of the clock names used by this component. These names should already be defined in either the main I/O ports list, or the main definitions. If no wire is given for a clock, the clock's name with a i_ prepended to the beginning is used instead. For this reason, the CLOCK.WIRE field may not be necessary for your application. CLOCK.FREQUENCY A list of frequencies in Hz corresponding to each of the clocks listed in the CLOCK.NAME tag CLOCK.CLASS A list containing the names of clock support classes used for these clocks. If no class is given, TBCLOCK is assumed as a default. The clock class must have a time_to_edge() function, an advance(int ps) function, and rising_edge() and falling_edge() indicators. Likewise, an init(ps) function will be called to define the period of the clock. CLOCK.RESET Optionally contains the name of a reset wire, synchronous to the given clock. SLAVE.TYPE Indicates the type of peripheral SLAVE.BUS Indicates the name of the bus used by this slave SLAVE.BUS.NAME An alternate form of entering a SLAVE.BUS. This version allows you to specify other parameters of the SLAVE.BUS at the same time. SLAVE.ORDER Slaves are naturally ordered from fewest addresses to largest. You can use the SLAVE.ORDER to impose a particular order on bus slaves going through address assignment. This is not the same as creating constant addressing. Constant addresses are not (yet) supported by AutoFPGA. SLAVE.PREFIX AutoFPGA will assign a bus prefix to every slave. Typically this will be the slave's name followed by the name of the bus (or vice versa). You can use the SLAVE.PREFIX key to override this, or otherwise to know what the value has been set to. Bus connections will be made to wires having names of the form, @$(SLAVE.PREFIX)_buswire. (SLAVE.OPTIONS) (When implemented) will indicate if a slave can be accessed as either read-only (RO) or write-only (WO). SLAVE.PORTLIST A helper string that you can use (or not) as you prefer. This string is created by the bus logic generator, and contains all of the wires you will need to connect to the bus. SLAVE.ANSIPORTLIST Same as SLAVE.PORTLIST, but assumes ANSI naming. MASTER.BUS Indicates that this component acts as a bus master, and identifies (names) the bus it is a master of MASTER.TYPE One of CPU, HOST, BUS, SUBBUS, ARBITER, or XCLOCK. CPU will cause board.ld to be created. Depends upon RESET_ADDRESS being defined. DMA Has a control SLAVE port, and an unrelated MASTER port--one that cannot be accessed through the slave HOST Controls the bus from an external interface. BUS, SUBBUS, ARBITER, XCLOCK These define a series of bridges, whereby the master of one bus can control another bus. All of these therefore need to have both a master and a slave bus. Requests come in on the slave bus, go out on the master, get returns to the master, get sent back out on as returns on the slave bus. Many bus masters of type ARBITER can master the same bus. In this way, slaves of one bus can also be ARBITER masters of another. Further, some busses may have multiple masters, if all of those masters are of type ARBITER. SCRIPT Doesn't connect to the bus at all, but identifies to the linker script generator the bus-master perspective to write the linker script from. MASTER.OPTIONS A list of options used to describe this master. Possible options include: RO (read only) and WO (write only) currently. MASTER.PORTLIST Analogous to SLAVE.PORTLIST, expands into a string describing all of the bus connections to be made to a given slave. MASTER.ANSIPORTLIST This is the same as MASTER.PORTLIST, save using ANSI declarations for the bus port. Again, this is an optional string, generated by the bus compositor, that you may use (or not) at your desire. BUS.NAME wb - master wishbone bus, dbg the debug port (wbu), zip - the ZipCPU bus master sdram - the MIG generated bus master BUS.PREFIX $(BUS.NAME)_ BUS.TYPE One of WB, (b4 assumed), WB/B4, WB/B3, WB/C(lassic), or AXI BUS.WIDTH 32 (common), could also be 8, 16, 64, 128, 256, etc. BUS.AWID Width of the address bus, also known as the number of address lines used to address items on this bus. The bus can address (2^BUS.AWID)*(BUS.WIDTH/8) bytes of memory. BUS.NULLSZ The number of addresses consumed by the null pointer address BUS.CLOCK The name of a previously defined clock from which this bus runs on BUS.RESET The name of a reset wire associated with this bus. BUS.(OPTIONS) BUS.OPT_LOWPOWER When set, any unused bus wires will be set to zero. Since bus wires can potentially have high fan out, this wire helps to keep all those wires from toggling if they don't need to. If this isn't set, the crossbar's will be tuned for lowest logic, which isn't necessarily lowest power.. BUS.OPT_LINGER Used by the AXI-lite master to indicate the number of idle clock cycles to wait before releasing the bus. This will potentially speed up a given masters access to the same slave over and over again, while slowing down accesses to other slaves. BUS.OPT_LGMAXBURST The number of bits necessary to count the maximum number of outstanding transactions at any given instant in time. BUS.OPT_TIMEOUT Used by the WB crossbar to indicate a maximum amount of time to wait for a given slave. Set this to zero to ignore the timeout, otherwise it defaults to the value in wbxbar.v. BUS.OPT_STARVATION_TIMEOUT (Currently ignored, eventually to be used by the Wishbone crossbar to indicate that the OPT_TIMEOUT is to be applied to starvation, where the slave is valid and active but responding to a different master, as well as slave timeouts) BUS.OPT_DBLBUFFER Used by the wishbone crossbar, wbxbar DEFAULT.BUS The name of the default bus, which we spend most of our time on. This bus gets the null device, for example REGISTER.BUS The name of the bus global register addresses are calculated from REGISTER.BUS.NAME An alternative form of REGISTER.BUS CACHABLE.FILE Creates a Verilog module of this name containing a combinatorial check of whether a given address beneath it is a cachable address (i.e., is it a memory or other type of peripheral). Walks the address tree below the containing master peripheral to find memories that may be some number of arbiters removed from the current file. .... GOALS ... Build S/W to collect all busses together Allow someone to inherit from the arbiters in such a manner that they can connect busses together simply Redo the address assignments, so as to be on a bus-by-bus basis Set the peripherals up in such a way that, if you have to walk from one bus to the next, you can still figure out what the adderss of the peripheral is--even if it is a couple busses deep ================================================ FILE: doc/ioports.md ================================================ ## Getting Access to External I/O Ports Accessing external I/O has a couple parts. First, you'll want to declare your need for accessing external I/O in the first place. For example, a serial port (uart) might have an input and an output port. Since AutoFPGA (currently) uses the older Verilog portlist syntax, defining these ports comes in two parts. First, you'd define the `MAIN.PORTLIST` tag, listing all of the ports in your design, and then the `MAIN.IODECL` tag declaring the various ports. Further, to avoid name collision, I typically use the `@$(PREFIX)` tag as part of any component I/O names--it's convenient, although not technically required. ```text @PREFIX=uart @NADDR=4 @SLAVE.BUS=wb @SLAVE.TYPE=DOUBLE @MAIN.PORTLIST= // Serial port wires i_@$(PREFIX)_uart, o_@$(PREFIX)_uart @MAIN.IODECL= input wire i_@$(PREFIX)_uart; output wire o_@$(PREFIX)_uart; @MAIN.INSERT= wbuart @$(PREFIX)i (i_clk, @$(SLAVE.PORTLIST), i_@$(PREFIX)_uart, o_@$(PREFIX)_uart); ``` By default, these ports will automatically be promoted to the top level. To keep from promoting them to the top level, or to adjust their names and definitions at the top level, simply override the `TOP.PORTLIST` and/or `TOP.IODECL` tags. ================================================ FILE: doc/single.md ================================================ # Single Slave Definitions AutoFPGA defines two special classes of slaves, `SINGLE` and `DOUBLE`. These classes are used to help AutoFPGA coalesce bus logic together, while simplifying your design. The `SINGLE` slave describes a slave with only one register, which register can be accessed on every cycle without stalling. It is the easiest slave to create. ```text @PREFIX=wbexample @SLAVE.NADDR=1 @SLAVE.BUS=wbbus @SLAVE.TYPE=SINGLE @MAIN.INSERT= assign @$(SLAVE.PREFIX)_idata = value; ``` This will create your slave and connect it to the bus named `wb`. Any attempt to read from your slave will return the value `value`, having a width specified by the `wb` bus width. (You'll still need to define `value` yourself somewhere within your design.) Building this same example for an AXI or AXI-Lite bus is almost the same, only that you also need to define values for `@$(SLAVE.PREFIX)_bresp` and `@$(SLAVE.PREFIX)_rresp`. ```text @PREFIX=axilexample @SLAVE.NADDR=1 @SLAVE.BUS=axilbus @SLAVE.TYPE=SINGLE @MAIN.INSERT= assign @$(SLAVE.PREFIX)_bresp = 2'b00; assign @$(SLAVE.PREFIX)_rresp = 2'b00; assign @$(SLAVE.PREFIX)_rdata = value; ``` The neat thing about `SINGLE` slaves, is that the logic can be created however within your design. For example, you might decide to declare a counter that could then be read from your design. ```text @SLAVE.BUS=wbbus @MAIN.DEFNS= reg [31:0] r_counter; @MAIN.INSERT= initial r_counter = 0; always @(posedge i_clk) r_counter <= r_counter + 1; assign @$(SLAVE.PREFIX)_idata = r_counter; ``` Indeed, I often create a startup counter that I use within my designs--one that just counts the number of clock ticks since startup, but that saturates the top bit. I can then use this to time things in startup sequences, or for relative (30-bit) timing ever afterwards. ```text @SLAVE.BUS=axilbus @MAIN.DEFNS= reg [31:0] r_pwrcount; @MAIN.INSERT= initial r_pwrcount = 0; always @(posedge i_clk) if (r_pwrcount[31]) r_pwrcount[30:0] <= r_pwrcount[30:0] + 1; else r_pwrcount <= r_pwrcount + 1; assign @$(SLAVE.PREFIX)_idata = r_pwrcount; ``` We could also give our counter a value as well. How you might do this is somewhat dependent upon the bus protocol in question. For example, when using Wishbone, this would look like: ```text @SLAVE.BUS=wbbus @MAIN.DEFNS= reg [31:0] r_pwrcount; @MAIN.INSERT= initial r_pwrcount = 0; always @(posedge i_clk) if (@$(SLAVE.PREFIX)_stb && @$(SLAVE.PREFIX)_we) r_pwrcount <= @$(SLAVE.PREFIX)_data; else if (r_pwrcount[31]) r_pwrcount[30:0] <= r_pwrcount[30:0] + 1; else r_pwrcount <= r_pwrcount + 1; assign @$(SLAVE.PREFIX)_idata = r_pwrcount; ``` When creating an AXI or AXI-Lite slave, AutoFPGA will use one of the bus simplifiers found in the [WB2AXIP](https://github.com/ZipCPU/wb2axip) repository, either [AXISINGLE](https://github.com/ZipCPU/wb2axip/blob/master/rtl/axisingle.v) or [AXILSINGLE](https://github.com/ZipCPU/wb2axip/blob/master/rtl/axilsingle.v) These drivers will guarantee for you that the respective `xREADY` lines remain high. All you therefore need to do is to check `WVALID` to know when to adjust your counter. ```text @SLAVE.BUS=axilbus @MAIN.DEFNS= reg [31:0] r_pwrcount; @MAIN.INSERT= initial r_pwrcount = 0; always @(posedge i_clk) if (@$(SLAVE.PREFIX)_awvalid) r_pwrcount <= @$(SLAVE.PREFIX)_data; else if (r_pwrcount[31]) r_pwrcount[30:0] <= r_pwrcount[30:0] + 1; else r_pwrcount <= r_pwrcount + 1; assign @$(SLAVE.PREFIX)_rdata = r_pwrcount; ``` Ideally, the `@PREFIX` tag should be unique to your slave. This makes it possible to name wires uniquely between bus components, although doing so isn't required. ```text @PREFIX=renamed @MAIN.DEFNS= reg [31:0] r_@$(PREFIX); @MAIN.INSERT= // Follows as before from above, but now with a new name ``` Remember, the `@MAIN.INSERT` tag will be copied directly into your `main.v`` file. Therefore, you can place anything into it you wish. For example, you might wish to reference a submodule of your own instead of placing your logic within the global scope of `main.v`. To make this easier, AutoFPGA will define a `@SLAVE.PORTLIST` tag that expands into a list of all of your design ports--just to make connections easier. ```text @MAIN.INSERT= mymodule @$(PREFIX)i (i_clk @$(SLAVE.PORTLIST)); ``` I like naming my modules as `@$(PREFIX)i` to avoid name contention, but this is only a convention--it's not required at all. The `@SLAVE.PORTLIST` tag doesn't include either clock or reset. You can either include these as I did above, or reference them from other names within your design--such as `@SLAVE.BUS.CLOCK.WIRE`. ```text @MAIN.INSERT= mymodule @$(PREFIX)i (@$(SLAVE.BUS.CLOCK.WIRE), @$(SLAVE.PORTLIST)); ``` Since this can get tedious, and since my designs rarely use more than one clock for the bus, I often just use `i_clk`. ================================================ FILE: doc/slaves.md ================================================ ## Creating a Generic Slave Now that you know how to create `SINGLE` and `DOUBLE` slaves, generic slaves really aren't that much more difficult. These are typically of type `OTHER`, and just reference your design. ```text @PREFIX=wbslave @SLAVE.BUS=wb @SLAVE.TYPE=OTHER @SLAVE.NADDR=32 @MAIN.INSERT= busslave @$(PREFIX)i (i_clk, i_reset, @$(SLAVE.PORTLIST)); ``` Unlike `SINGLE` or `DOUBLE` slaves which are not allowed to stall the bus, `OTHER` slaves can exploit the full bus protocol. ================================================ FILE: doc/src/gpl-3.0.tex ================================================ \documentclass[11pt]{article} \title{GNU GENERAL PUBLIC LICENSE} \date{Version 3, 29 June 2007} \begin{document} \maketitle \begin{center} {\parindent 0in Copyright \copyright\ 2007 Free Software Foundation, Inc. \texttt{http://fsf.org/} \bigskip Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.} \end{center} \renewcommand{\abstractname}{Preamble} \begin{abstract} 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. \end{abstract} \begin{center} {\Large \sc Terms and Conditions} \end{center} \begin{enumerate} \addtocounter{enumi}{-1} \item 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. \item 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. \item 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. \item 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. \item 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. \item 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: \begin{enumerate} \item The work must carry prominent notices stating that you modified it, and giving a relevant date. \item 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''. \item 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. \item 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. \end{enumerate} 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. \item 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: \begin{enumerate} \item 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. \item 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. \item 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. \item 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. \item 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. \end{enumerate} 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. \item 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: \begin{enumerate} \item Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or \item 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 \item 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 \item Limiting the use for publicity purposes of names of licensors or authors of the material; or \item Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or \item 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. \end{enumerate} 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. \item 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. \item 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. \item 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. \item 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. \item 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. \item 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. \item 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. \item Disclaimer of Warranty. \begin{sloppypar} 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. \end{sloppypar} \item 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. \item 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. \begin{center} {\Large\sc End of Terms and Conditions} \bigskip How to Apply These Terms to Your New Programs \end{center} 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. {\footnotesize \begin{verbatim} Copyright (C) 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 . \end{verbatim} } 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: {\footnotesize \begin{verbatim} Copyright (C) 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. \end{verbatim} } The hypothetical commands {\tt show w} and {\tt 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 \texttt{http://www.gnu.org/licenses/}. 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 \texttt{http://www.gnu.org/philosophy/why-not-lgpl.html}. \end{enumerate} \end{document} ================================================ FILE: sw/.gitignore ================================================ autofpga runme.sh expr.tab.h expr.tab.cpp lex.yy.h lex.yy.cpp *tmp.txt tmp*.txt demo-out ================================================ FILE: sw/Makefile ================================================ ################################################################################ ## ## Filename: sw/Makefile ## ## Project: AutoFPGA, a utility for composing FPGA designs from peripherals ## {{{ ## Purpose: ## ## Creator: Dan Gisselquist, Ph.D. ## Gisselquist Technology, LLC ## ################################################################################ ## }}} ## Copyright (C) 2017-2024, Gisselquist Technology, LLC ## {{{ ## This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ## target there if the PDF file isn't present.) If not, see ## for a copy. ## }}} ## License: GPL, v3, as defined and found on www.gnu.org, ## {{{ ## http://www.gnu.org/licenses/gpl.html ## ## ################################################################################ ## ## }}} all: PROGRAMS := autofpga demo OBJDIR:= obj-pc YYMMDD:= `date +%Y%m%d` CXX:= g++ SED:= sed CFLAGS:= -std=c++11 -g -Wall -I bus/ SOURCES := autofpga.cpp parser.cpp kveval.cpp keys.cpp mapdhash.cpp ast.cpp \ legalnotice.cpp ifdefs.cpp bldregdefs.cpp expr.tab.cpp lex.yy.cpp \ bitlib.cpp bldtestb.cpp bldsim.cpp predicates.cpp \ clockinfo.cpp subbus.cpp globals.cpp gather.cpp \ bldboardld.cpp bldrtlmake.cpp msgs.cpp bldcachable.cpp \ businfo.cpp plist.cpp mlist.cpp genbus.cpp $(wildcard bus/*.cpp) POSSHDRS:= $(subst .c,.h,$(subst .cpp,.h,$(SOURCES))) HEADERS := $(foreach header,$(POSSHDRS),$(wildcard $(header))) OBJECTS := $(addprefix $(OBJDIR)/,$(subst bus/,,$(subst .c,.o,$(subst .cpp,.o,$(SOURCES))))) all: $(PROGRAMS) $(OBJDIR)/autofpga.o: autofpga.cpp $(mk-objdir) $(CXX) -DBUILDDATE=0x$(YYMMDD) $(CFLAGS) -c $< -o $@ $(OBJDIR)/lex.yy.o: lex.yy.cpp $(mk-objdir) $(CXX) $(CFLAGS) -Wno-sign-compare -Wno-unused-function -c $< -o $@ $(OBJDIR)/%.o: %.cpp $(mk-objdir) $(CXX) $(CFLAGS) -c $< -o $@ $(OBJDIR)/%.o: bus/%.cpp $(mk-objdir) $(CXX) $(CFLAGS) -I. -c $< -o $@ $(OBJDIR)/%.o: %.c $(mk-objdir) $(CXX) $(CFLAGS) -c $< -o $@ expr.tab.h: expr.ypp bison --defines=expr.tab.h expr.ypp expr.tab.cpp: expr.tab.h $(OBJDIR)/expr.tab.o: lex.yy.h lex.yy.cpp lex.yy.h: expr.l expr.tab.h flex --header-file=lex.yy.h -o lex.yy.cpp expr.l autofpga: $(OBJECTS) echo $(OBJECTS) $(CXX) $(CFLAGS) $(OBJECTS) -o $@ VDATA := allclocks.txt bkram.txt buserr.txt clkcheck.txt crossbus.txt \ ddr3.txt edidslvscope.txt edid.txt exconsole.txt flashcfg.txt \ flash.txt global.txt gpio.txt gps.txt hdmi.txt i2ccpu.txt \ i2cdma.txt i2saudio.txt icape.txt meganet.txt mdio.txt pic.txt \ pwrcount.txt rtcdate.txt rtcgps.txt spio.txt sdio.txt \ vadj33.txt version.txt wboledbw.txt wbpmic.txt wbuarbiter.txt \ wbubus.txt zipcpu.txt zipmaster.txt .PHONY: demo demo: runme.sh bash runme.sh .PHONY: runme.sh # Force a rebuild of this file every time runme.sh: autofpga $(addprefix ../auto-data/,$(VDATA)) @echo "#!/bin/bash" > $@ @echo >> $@ @echo >> $@ @echo ./autofpga -d -o ../demo-out -I ../auto-data $(VDATA) >> $@ @echo >> $@ @echo "echo \"exit code \" \$$?" >> $@ define mk-objdir @bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi" endef define build-depends @echo "Building dependency file" $(CXX) $(CFLAGS) -MM $(SOURCES) > $(OBJDIR)/xdep.txt $(SED) -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdep.txt > $(OBJDIR)/depends.txt endef .PHONY: depends depends: tags $(mk-objdir) $(build-depends) tags: $(SOURCES) $(HEADERS) @echo "Generating tags" @ctags $(SOURCES) $(HEADERS) .PHONY: clean clean: rm -rf $(OBJDIR)/ $(PROGRAMS) rm -rf lex.yy.cpp lex.yy.h expr.tab.cpp expr.tab.h expr.output -include $(OBJDIR)/depends.txt ================================================ FILE: sw/ast.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/ast.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include "ast.h" #include "keys.h" bool AST_BRANCH::isdefined(void) { return ((m_left)&&(m_right)&&(m_left->isdefined()) &&(m_right->isdefined())); } long AST_BRANCH::eval(void) { long lft = m_left->eval(), rht = m_right->eval(); switch(m_op) { case '+': return lft + rht; break; case '-': return lft - rht; break; case '*': return lft * rht; break; case '/': return lft / rht; break; case '%': return lft % rht; break; // case 'u': return lft << rht; break; case 'd': return lft >> rht; break; // case '|': return lft | rht; break; case '&': return lft & rht; break; case '^': return lft ^ rht; break; // ~ ?? // case 'o': return ((lft)||(rht))?1:0; break; case 'a': return ((lft)&&(rht))?1:0; break; case 'e': return ((lft)==(rht))?1:0; break; // ! ?? case 'N': return (lft != rht)? 1:0; break; case 'L': return (lft <= rht)? 1:0; break; case 'G': return (lft >= rht)? 1:0; break; case '<': return (lft < rht)? 1:0; break; case '>': return (lft > rht)? 1:0; break; // // default: fprintf(stderr, "ERR: AST Unknown operation, %c", m_op); return lft; } } bool AST_BRANCH::define(MAPSTACK &stack, MAPDHASH &here) { bool v; v = m_left->define(stack, here); v = m_right->define(stack, here) || v; return v; } void AST_BRANCH::dump(FILE *fp, int offset) { fprintf(fp, "%*s%c\n", offset, "", m_op); m_left->dump(fp, offset+2); m_right->dump(fp, offset+2); } AST *AST_BRANCH::copy(void) { return new AST_BRANCH(m_op, ::copy(m_left), ::copy(m_right)); } bool AST_SINGLEOP::isdefined(void) { return (m_val->isdefined()); } long AST_SINGLEOP::eval(void) { if (m_op == '~') return ~m_val->eval(); else return (m_val->eval())?0:1; } bool AST_SINGLEOP::define(MAPSTACK &stack, MAPDHASH &here) { return m_val->define(stack, here); } void AST_SINGLEOP::dump(FILE *fp, int offset) { fprintf(fp, "%*s%c\n", offset, "", m_op); m_val->dump(fp, offset+2); } AST *AST_SINGLEOP::copy(void) { return new AST_SINGLEOP(m_op, ::copy(m_val)); } bool AST_TRIOP::isdefined(void) { return (m_cond->isdefined())&&(m_left->isdefined()) &&(m_right->isdefined()); } long AST_TRIOP::eval(void) { return (m_cond->eval()) ? m_left->eval() : m_right->eval(); } bool AST_TRIOP::define(MAPSTACK &stack, MAPDHASH &here) { bool v = false; v = (m_cond->define(stack, here)) || v; v = (m_left->define(stack, here)) || v; v = (m_right->define(stack, here)) || v; return v; } void AST_TRIOP::dump(FILE *fp, int offset) { fprintf(fp, "%*sTRIPL:\n", offset, ""); m_cond->dump(fp, offset+2); m_left->dump(fp, offset+2); m_right->dump(fp, offset+2); } AST *AST_TRIOP::copy(void) { return new AST_TRIOP(::copy(m_cond), ::copy(m_left), ::copy(m_right)); } bool AST_NUMBER::isdefined(void) { return true; } long AST_NUMBER::eval(void) { return m_val; } bool AST_NUMBER::define(MAPSTACK &stack, MAPDHASH &here) { return false; } void AST_NUMBER::dump(FILE *fp, int offset) { fprintf(fp, "%*s%ld\n", offset, "", m_val); } AST *AST_NUMBER::copy(void) { return new AST_NUMBER(m_val); } bool AST_IDENTIFIER::isdefined(void) { return m_def; } long AST_IDENTIFIER::eval(void) { return m_v; } bool AST_IDENTIFIER::define(MAPSTACK &stack, MAPDHASH &here) { if (m_def) return false; // No change if (get_named_value(stack, here, m_id, m_v)) { // GOT IT!!!! We now know our value, so ... set it and // report that things have changed. m_def = true; return true; // Things have changed! } return false; // Nothing changed, we still don't know our value } void AST_IDENTIFIER::dump(FILE *fp, int offset) { if (m_def) fprintf(fp, "%*s%s (= %d)\n", offset, "", m_id.c_str(), m_v); else fprintf(fp, "%*s%s (Undefined)\n", offset, "", m_id.c_str()); } AST *AST_IDENTIFIER::copy(void) { return new AST_IDENTIFIER(m_id.c_str()); } ================================================ FILE: sw/ast.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/ast.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef AST_H #define AST_H #include #include #include #include "parser.h" #include "kveval.h" class AST { public: virtual ~AST(void) {} char m_node_type; virtual bool isdefined(void) = 0; virtual long eval(void) = 0; virtual bool define(MAPSTACK &stack, MAPDHASH &comp) = 0; virtual void dump(FILE *fp, int offset) = 0; virtual AST *copy(void) = 0; }; class AST_BRANCH : public AST { public: int m_op; AST *m_left, *m_right; AST_BRANCH(int op, AST *l, AST *r) : m_op(op), m_left(l), m_right(r) { m_node_type = 'B';} ~AST_BRANCH(void) { if (m_left) delete m_left; if (m_right) delete m_right; } virtual bool isdefined(void); virtual long eval(void); virtual bool define(MAPSTACK &stack, MAPDHASH &here); virtual void dump(FILE *fp, int offset); virtual AST *copy(void); }; class AST_SINGLEOP : public AST { public: int m_op; AST *m_val; AST_SINGLEOP(int op, AST *v) : m_op(op), m_val(v) { m_node_type = 'S'; } ~AST_SINGLEOP(void) { delete m_val; } virtual bool isdefined(void); virtual long eval(void); virtual bool define(MAPSTACK &stack, MAPDHASH &here); virtual void dump(FILE *fp, int offset); virtual AST *copy(void); }; class AST_TRIOP : public AST { public: AST *m_cond, *m_left, *m_right; AST_TRIOP(AST *c, AST *l, AST *r) : m_cond(c), m_left(l), m_right(r) { m_node_type = 'T'; } ~AST_TRIOP(void) { delete m_cond; delete m_left; delete m_right; } virtual bool isdefined(void); virtual long eval(void); virtual bool define(MAPSTACK &stack, MAPDHASH &here); virtual void dump(FILE *fp, int offset); virtual AST *copy(void); }; class AST_NUMBER : public AST { public: long m_val; AST_NUMBER(long val) : m_val(val) { m_node_type = 'N'; } virtual bool isdefined(void); virtual long eval(void); virtual bool define(MAPSTACK &stack, MAPDHASH &here); virtual void dump(FILE *fp, int offset); virtual AST *copy(void); }; class AST_IDENTIFIER : public AST { public: STRING m_id; bool m_def; int m_v; AST_IDENTIFIER(const char *id) : m_id(id) { m_node_type = 'I'; m_def=false; m_v = 0; } virtual bool isdefined(void); virtual long eval(void); virtual bool define(MAPSTACK &stack, MAPDHASH &here); virtual void dump(FILE *fp, int offset); virtual AST *copy(void); }; extern AST *parse_ast(const STRING &str); inline AST *copy(AST *a) { return a->copy(); } #endif // AST_H ================================================ FILE: sw/autofpga.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/autofpga.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: This is the main/master program for the autofpga project. All // other components server this one. // // The purpose of autofpga.cpp is to read a group of configuration files // (.txt currently), and to generate code from those files to connect // the various parts and pieces within them into a design. // // Currently that design is dependent upon the Wishbone B4/Pipelined // bus, but that's likely to change in the future. // // Design files produced include: // // toplevel.v // main.v // regdefs.h // iscachable.h // regdefs.cpp // board.h // board.ld // main_tb.cpp // testb.h // * dev.tex (Not yet included) // * kernel device tree file // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "keys.h" #include "kveval.h" #include "legalnotice.h" #include "bldtestb.h" #include "bldboardld.h" #include "bldrtlmake.h" #include "bitlib.h" #include "plist.h" #include "bldregdefs.h" #include "ifdefs.h" #include "bldsim.h" #include "predicates.h" #include "businfo.h" #include "globals.h" #include "msgs.h" #include "bldcachable.h" // class INFINFO // The ILIST, a list of interrupt lines within the design // {{{ // class INTINFO { public: STRINGP i_name; STRINGP i_wire; unsigned i_id; MAPDHASH *i_hash; INTINFO(void) { i_name = NULL; i_wire = NULL; i_id = 0; } INTINFO(STRINGP nm, STRINGP wr, unsigned id) : i_name(nm), i_wire(wr), i_id(id) {} INTINFO(STRING &nm, STRING &wr, unsigned id) : i_id(id) { i_name = new STRING(nm); i_wire = new STRING(wr); } }; typedef INTINFO INTID, *INTP; typedef std::vector ILIST; // }}} // class PICINFO // {{{ // The PICINFO structure, one that keeps track of all of the information used // by a given Programmable Interrupt Controller (PIC) // // class PICINFO { public: STRINGP i_name, // The name of this PIC // i_bus is the name of a vector, that is ... a series // of wires, composed of the interrupts going to this // controller i_bus; unsigned i_max, // Max # of interrupts this controller can handle // i_nassigned is the number of interrupts that have // been given assignments (positions) to our interrupt // vector i_nassigned, // i_nallocated references the number of interrupts that // this controller knows about. This is separate from // the number of interrupts that have positions assigned // to them i_nallocated; // // The list of all interrupts this controller can handle // ILIST i_ilist; // // The list of assigned interrupts INTID **i_alist; PICINFO(MAPDHASH &pic) { i_max = 0; int mx = 0; i_name = getstring(pic, KYPREFIX); assert(i_name); i_bus = getstring(pic, KYPIC_BUS); if (getvalue( pic, KYPIC_MAX, mx)) { i_max = mx; i_alist = new INTID *[mx]; for(int i=0; ic_str() : "(No name)"); gbl_msg.dump(pic); i_max = 0; i_alist = NULL; } i_nassigned = 0; i_nallocated = 0; } // Add an interrupt with the given name, and hash source, to the table void add(MAPDHASH &psrc, STRINGP iname) { if (!iname) return; if (i_nallocated >= i_max) { gbl_msg.warning("Interrupt %s not assigned, PIC %s is full\n", iname->c_str(), i_name->c_str()); return; } INTP ip = new INTID(); i_ilist.push_back(ip); // Initialize the table entry with the name of this interrupt assert(iname); ip->i_name = trim(*iname); assert(ip->i_name->size() > 0); // The wire from the rest of the design to connect to this // interrupt bus ip->i_wire = getstring(psrc, KY_WIRE); // We'll set the ID of this interrupt to MAX, to indicate that // the interrupt has not been assigned yet ip->i_id = i_max; ip->i_hash = &psrc; i_nallocated++; } // This is identical to the add function above, save that we are adding // an interrupt with a known position assignment within the controller. void add(unsigned id, MAPDHASH &psrc, STRINGP iname) { if (!iname) { gbl_msg.warning("No name given for interrupt\n"); return; } else if (id >= i_max) { gbl_msg.error("ERR: Interrupt ID %d out of bounds [0..%d]\n", id, i_max); return; } else if (i_nassigned+1 > i_max) { gbl_msg.error("ERR: Too many interrupts assigned to %s\n", i_name->c_str()); return; } // Check to see if any other interrupt already has this // identifier, and write an error out if so. if (i_alist[id]) { gbl_msg.error("%s and %s are both competing for the same interrupt ID, #%d\n", i_alist[id]->i_name->c_str(), iname->c_str(), id); gbl_msg.error("interrupt %s dropped\n", iname->c_str()); return; } // Otherwise, add the interrupt to our list INTP ip = new INTID(); i_ilist.push_back(ip); assert(iname); ip->i_name = trim(*iname); assert(ip->i_name->size() > 0); ip->i_wire = getstring(psrc, KY_WIRE); ip->i_id = id; ip->i_hash = &psrc; i_nassigned++; i_nallocated++; i_alist[id] = ip; } // Let's look through our list of interrupts for unassigned interrupt // values, and ... assign them void assignids(void) { for(unsigned iid=0; iidi_id >= i_max) { uid = jid; break; } } if (uid < mx) { // Assign this interrupt // 1. Give it an interrupt ID i_ilist[uid]->i_id = iid; // 2. Place it in our numbered interrupt list i_alist[iid] = i_ilist[uid]; i_nassigned++; } else continue; // All interrupts assigned } if (i_max < i_ilist.size()) { gbl_msg.warning("Too many interrupts assigned to PIC %s\n", i_name->c_str()); } // Write the interrupt assignments back into the map for(unsigned iid=0; iidi_id < i_max) { STRING ky = (*i_name) + ".ID"; setvalue(*i_ilist[iid]->i_hash, ky, i_ilist[iid]->i_id); } } } // Given an interrupt number associated with this PIC, lookup the // interrupt having that number, returning NULL on error or if not // found. INTP getint(unsigned iid) { if ((iid < i_max)&&(NULL != i_alist[iid])) return i_alist[iid]; return NULL; } }; typedef PICINFO PICI, *PICP; typedef std::vector PICLIST; // A list of all of our interrupt controllers PICLIST piclist; unsigned unusedmsk; // }}} // Return the number of interrupt controllers within this design. If no such // field/tag exists, count the number and add it to the hash. int count_pics(MAPDHASH &info) { // {{{ MAPDHASH::iterator kvpair, kvpic; int npics=0; if (getvalue(info, KYNPIC, npics)) return npics; for(kvpair = info.begin(); kvpair != info.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; kvpic = kvpair->second.u.m_m->find(KYPIC); if (kvpic != kvpair->second.u.m_m->end()) npics++; } setvalue(info, KYNPIC, npics); return npics; } // }}} void assign_int_to_pics(const STRING &iname, MAPDHASH &ihash) { // {{{ STRINGP picname; int inum; // Now, we need to map this to a PIC if (NULL==(picname=getstring(ihash, KYPIC))) { return; } char *tok, *cpy, *sr; cpy = strdup(picname->c_str()); tok = strtok_r(cpy, ", \t\n", &sr); while(tok) { unsigned pid; for(pid = 0; pidi_name->compare(tok)==0) break; if (pid >= piclist.size()) { gbl_msg.error("PIC NOT FOUND: %s\n", tok); } else if (getvalue(ihash, KY_ID, inum)) { piclist[pid]->add((unsigned)inum, ihash, (STRINGP)&iname); } else { piclist[pid]->add(ihash, (STRINGP)&iname); } tok = strtok_r(NULL, ", \t\n", &sr); } free(cpy); } // }}} // // assign_interrupts // // Find all the interrup controllers, and then find all the interrupts, and map // interrupts to controllers. Individual interrupt wires may be mapped to // multiple interrupt controllers. // void assign_interrupts(MAPDHASH &master) { // {{{ MAPDHASH::iterator kvpair, kvint, kvline; MAPDHASH *submap, *intmap; STRINGP sintlist; // First step, gather all of our PIC's together for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (ispic(kvpair->second)) { PICP npic = new PICI(*kvpair->second.u.m_m); piclist.push_back(npic); } } // Okay, now we need to gather all of our interrupts together and to // assign them to PICs. for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; // submap now points to a component. It can be any component. // We now need to check if it has an INT. hash. submap = kvpair->second.u.m_m; kvint = submap->find(KY_INT); if (kvint == submap->end()) { continue; } if (kvint->second.m_typ != MAPT_MAP) { continue; } // Now, let's look to see if it has a list of interrupts if (NULL != (sintlist = getstring(kvint->second, KYINTLIST))) { const char DELIMITERS[] = " \t\n,"; char *scpy = strdup(sintlist->c_str()); char *tok, *stoksv=NULL; tok = strtok_r(scpy, DELIMITERS, &stoksv); while(tok) { STRING stok = STRING(tok); kvline = findkey(*kvint->second.u.m_m, stok); if (kvline != kvint->second.u.m_m->end()) { assign_int_to_pics(stok, *kvline->second.u.m_m); } else gbl_msg.warning("INT %s not found, not connected\n", tok); tok = strtok_r(NULL, DELIMITERS, &stoksv); } free(scpy); } else { // NAME is now @comp.INT. // Yes, an INT hash exists within this component. // Hence the component has one (or more) interrupts. // Let's loop over those interrupts intmap = kvint->second.u.m_m; for(kvline=intmap->begin(); kvline != intmap->end(); kvline++) { if (kvline->second.m_typ != MAPT_MAP) continue; assign_int_to_pics(kvline->first, *kvline->second.u.m_m); } } } // Now, let's assign everything that doesn't yet have any definitions for(unsigned picid=0; picidassignids(); reeval(master); } // }}} void writeout(FILE *fp, MAPDHASH &master, const STRING &ky) { // {{{ MAPDHASH::iterator kvpair; STRINGP str; // fprintf(fp, "// Looking for string: %s\n", ky.c_str()); str = getstring(master, ky); if (NULL != str) { fprintf(fp, "%s", str->c_str()); } for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; str = getstring(kvpair->second, ky); if (str == NULL) continue; fprintf(fp, "%s", str->c_str()); } } // }}} void build_board_h( MAPDHASH &master, FILE *fp, STRING &fname) { // {{{ const char DELIMITERS[] = " \t\n"; MAPDHASH::iterator kvpair; STRING str, astr; STRINGP defns; legal_notice(master, fp, fname); fprintf(fp, "#ifndef BOARD_H\n#define\tBOARD_H\n"); fprintf(fp, "\n"); fprintf(fp, "// And, so that we can know what is and isn\'t defined\n"); fprintf(fp, "// from within our main.v file, let\'s include:\n"); fprintf(fp, "#include \n\n"); defns = getstring(master, KYBDEF_INCLUDE); if (defns) fprintf(fp, "%s\n\n", defns->c_str()); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; defns = getstring(kvpair->second, KYBDEF_INCLUDE); if (defns) fprintf(fp, "%s\n\n", defns->c_str()); } for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; defns = getstring(kvpair->second, KYBDEF_DEFN); if (defns) fprintf(fp, "%s\n\n", defns->c_str()); } for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { char *dup, *tok; STRINGP osdef, osval, access; if (kvpair->second.m_typ != MAPT_MAP) continue; osdef = getstring(*kvpair->second.u.m_m, KYBDEF_OSDEF); osval = getstring(*kvpair->second.u.m_m, KYBDEF_OSVAL); if ((!osdef)&&(!osval)) continue; access= getstring(kvpair->second, KYACCESS); dup = NULL; tok = NULL; if (access) { dup = strdup(access->c_str()); tok = strtok(dup, DELIMITERS); if (tok[0] == '!') tok++; } else tok = NULL; if (tok) fprintf(fp, "#ifdef\t%s\n", tok); if (osdef) fprintf(fp, "#define\t%s\n", osdef->c_str()); if (osval) { fputs(osval->c_str(), fp); if (osval->c_str()[strlen(osval->c_str())-1] != '\n') fputc('\n', fp); } if (tok) fprintf(fp, "#endif\t// %s\n", tok); } fprintf(fp, "//\n// Interrupt assignments (%ld PICs)\n//\n", piclist.size()); for(unsigned pid = 0; pidi_name->c_str()); for(unsigned iid=0; iid< pic->i_max; iid++) { INTP ip = pic->getint(iid); if (NULL == ip) continue; if (NULL == ip->i_name) continue; char *buf = strdup(pic->i_name->c_str()), *ptr; for(ptr = buf; (*ptr); ptr++) *ptr = toupper(*ptr); fprintf(fp, "#define\t%s_%s\t%s(%d)\n", buf, ip->i_name->c_str(), buf, iid); free(buf); } } defns = getstring(master, KYBDEF_INSERT); if (defns) fprintf(fp, "%s\n\n", defns->c_str()); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; defns = getstring(*kvpair->second.u.m_m, KYBDEF_INSERT); if (defns) fprintf(fp, "%s\n\n", defns->c_str()); } fprintf(fp, "#endif\t// BOARD_H\n"); } // }}} void build_latex_tbls( MAPDHASH &master) { // {{{ // legal_notice(master, fp, fname); #ifdef NEW_FILE_FORMAT printf("\n\n\n// TO BE PLACED INTO doc/src\n"); for(int i=0; i 0)?" ":"", cklist[ck].m_top->c_str()); nclocks_at_top++; } } fprintf(fp, "\n"); first = 1; for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; STRINGP strp; strp = getstring(*kvpair->second.u.m_m, KYTOP_PORTLIST); if (!strp) strp = getstring(*kvpair->second.u.m_m, KYMAIN_PORTLIST); if (!strp) continue; STRING tmps(*strp); STRING::iterator si; for(si=tmps.end()-1; si>=tmps.begin(); si--) if (isspace(*si)) *si = '\0'; else break; if (tmps.size() == 0) continue; if (!first) fprintf(fp, ",\n"); first=0; fprintf(fp, "%s", tmps.c_str()); } fprintf(fp, ");\n"); // External declarations (input/output) for our various ports fprintf(fp, "\t//\n" "\t// Declaring any top level parameters.\n" "\t//\n" "\t// These declarations just copy data from the @TOP.PARAM key,\n" "\t// or from the @MAIN.PARAM key if @TOP.PARAM is absent. For\n" "\t// those peripherals that don't do anything at the top level,\n" "\t// the @MAIN.PARAM key should be sufficient, so the @TOP.PARAM\n" "\t// key may be left undefined.\n" "\t//\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; STRINGP strp = getstring(*kvpair->second.u.m_m, KYTOP_PARAM); if (!strp) strp = getstring(*kvpair->second.u.m_m, KYMAIN_PARAM); if (strp) fprintf(fp, "%s", strp->c_str()); } fprintf(fp, "\t//\n" "\t// Declaring our input and output ports. We listed these above,\n" "\t// now we are declaring them here.\n" "\t//\n" "\t// These declarations just copy data from the @TOP.IODECLS key,\n" "\t// or from the @MAIN.IODECL key if @TOP.IODECL is absent. For\n" "\t// those peripherals that don't do anything at the top level,\n" "\t// the @MAIN.IODECL key should be sufficient, so the @TOP.IODECL\n" "\t// key may be left undefined.\n" "\t//\n" "\t// We start with any @CLOCK.TOP keys\n" "\t//\n"); for(unsigned ck=0; ckc_str()); } } for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; STRINGP strp = getstring(*kvpair->second.u.m_m, KYTOP_IODECL); if (!strp) strp = getstring(*kvpair->second.u.m_m, KYMAIN_IODECL); if (strp) fprintf(fp, "%s", strp->c_str()); } // Declare peripheral data fprintf(fp, "\n\n"); fprintf(fp, "\t//\n" "\t// Declaring component data, internal wires and registers\n" "\t//\n" "\t// These declarations just copy data from the @TOP.DEFNS key\n" "\t// within the component data files.\n" "\t//\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; STRINGP strp = getstring(*kvpair->second.u.m_m, KYTOP_DEFNS); if (strp) fprintf(fp, "%s", strp->c_str()); } fprintf(fp, "\n\n"); fprintf(fp, "" "\t//\n" "\t// Time to call the main module within main.v. Remember, the purpose\n" "\t// of the main.v module is to contain all of our portable logic.\n" "\t// Things that are Xilinx (or even Altera) specific, or for that\n" "\t// matter anything that requires something other than on-off logic,\n" "\t// such as the high impedence states required by many wires, is\n" "\t// kept in this (toplevel.v) module. Everything else goes in\n" "\t// main.v.\n" "\t//\n" "\t// We automatically place s_clk, and s_reset here. You may need\n" "\t// to define those above. (You did, didn't you?) Other\n" "\t// component descriptions come from the keys @TOP.MAIN (if it\n" "\t// exists), or @MAIN.PORTLIST if it does not.\n" "\t//\n"); fprintf(fp, "\n\tmain\tthedesign(s_clk, s_reset,\n"); first = 1; for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; STRINGP strp = getstring(*kvpair->second.u.m_m, KYTOP_MAIN); if (!strp) strp = getstring(*kvpair->second.u.m_m, KYMAIN_PORTLIST); if (!strp) continue; STRING tmps(*strp); STRING::iterator si; for(si=tmps.end()-1; si>=tmps.begin(); si--) { if (isspace(*si)) *si = '\0'; else break; } if (tmps.size() == 0) continue; if (!first) fprintf(fp, ",\n"); first=0; fprintf(fp, "%s", tmps.c_str()); } fprintf(fp, ");\n"); fprintf(fp, "\n\n" "\t//\n" "\t// Our final section to the toplevel is used to provide all of\n" "\t// that special logic that couldnt fit in main. This logic is\n" "\t// given by the @TOP.INSERT tag in our data files.\n" "\t//\n\n\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; STRINGP strp = getstring(*kvpair->second.u.m_m, KYTOP_INSERT); if (!strp) continue; fprintf(fp, "%s\n", strp->c_str()); } fprintf(fp, "\n\nendmodule // end of toplevel.v module definition\n"); } // }}} void build_main_v( MAPDHASH &master, FILE *fp, STRING &fname) { // {{{ char DELIMITERS[] = ", \t\n"; MAPDHASH::iterator kvpair, kvaccess, kvsearch; STRING str, astr, sellist, acklist, siosel_str, diosel_str; int first; fprintf(fp, "`timescale\t1ps / 1ps\n"); legal_notice(master, fp, fname); // Include a legal notice // Build a set of ifdefs to turn things on or off fprintf(fp, "`default_nettype\tnone\n"); fprintf(fp, "////////////////////////////////////////////////////////////////////////////////\n" "//\n" "// Macro defines\n" "// {{{\n"); build_access_ifdefs_v(master, fp); fprintf(fp, "// }}}\n"); fprintf(fp, "////////////////////////////////////////////////////////////////////////////////\n" "//\n" "// Any include files\n// {{{\n" "// These are drawn from anything with a MAIN.INCLUDE definition.\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { STRINGP strp = getstring(kvpair->second, KYMAIN_INCLUDE); if (!strp) continue; fprintf(fp, "%s", strp->c_str()); } fprintf(fp, "// }}}\n//\n"); fprintf(fp, "// Finally, we define our main module itself. We start with the list of\n" "// I/O ports, or wires, passed into (or out of) the main function.\n" "//\n" "// These fields are copied verbatim from the respective I/O port lists,\n" "// from the fields given by @MAIN.PORTLIST\n" "//\n"); // Define our external ports within a port list fprintf(fp, "module\tmain(i_clk, i_reset,\n\t// {{{\n"); str = "MAIN.PORTLIST"; first = 1; for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; STRINGP strp = getstring(*kvpair->second.u.m_m, str); if (!strp) continue; STRING tmps(*strp); STRING::iterator si; for(si=tmps.end()-1; si>=tmps.begin(); si--) { if (isspace(*si)) *si = '\0'; else break; } if (tmps.size() == 0) continue; if (!first) fprintf(fp, ",\n"); first=0; fprintf(fp, "%s", tmps.c_str()); } fprintf(fp, "\n\t// }}}\n\t);\n"); fprintf(fp, "////////////////////////////////////////////////////////////////////////////////\n" "//\n" "// Any parameter definitions\n// {{{\n" "// These are drawn from anything with a MAIN.PARAM definition.\n" "// As they aren\'t connected to the toplevel at all, it would\n" "// be best to use localparam over parameter, but here we don\'t\n" "// check\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { STRINGP strp = getstring(kvpair->second, KYMAIN_PARAM); if (!strp) continue; fprintf(fp, "%s", strp->c_str()); } fprintf(fp, "// }}}\n" "////////////////////////////////////////////////////////////////////////////////\n" "//\n" "// Port declarations\n" "// {{{\n" "// The next step is to declare all of the various ports that were just\n" "// listed above.\n" "//\n" "// The following declarations are taken from the values of the various\n" "// @MAIN.IODECL keys.\n" "//\n"); // #warning "How do I know these will be in the same order? // They have been--because the master always reads its subfields in the // same order. // // External declarations (input/output) for our various ports fprintf(fp, "\tinput\twire\t\ti_clk;\n\t// verilator lint_off UNUSED\n\tinput\twire\t\ti_reset;\n\t// verilator lint_on UNUSED\n"); str = "MAIN.IODECL"; for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { STRINGP strp; if (kvpair->second.m_typ != MAPT_MAP) continue; strp = getstring(*kvpair->second.u.m_m, str); if (strp) fprintf(fp, "%s", strp->c_str()); } fprintf(fp, "// }}}\n"); fprintf(fp, "\t// Make Verilator happy\n" "\t// {{{\n" "\t// Defining bus wires for lots of components often ends up with unused\n" "\t// wires lying around. We'll turn off Ver1lator\'s lint warning\n" "\t// here that checks for unused wires.\n" "\t// }}}\n" "\t// verilator lint_off UNUSED\n"); fprintf(fp, "\t////////////////////////////////////////////////////////////////////////\n" "\t//\n\t// Declaring interrupt lines\n\t// {{{\n" "\t// These declarations come from the various components values\n" "\t// given under the @INT..WIRE key.\n\t//\n"); // Define any interrupt wires for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { MAPDHASH::iterator kvint, kvsub, kvwire; if (kvpair->second.m_typ != MAPT_MAP) continue; kvint = kvpair->second.u.m_m->find(KY_INT); if (kvint == kvpair->second.u.m_m->end()) continue; if (kvint->second.m_typ != MAPT_MAP) continue; for(kvsub=kvint->second.u.m_m->begin(); kvsub != kvint->second.u.m_m->end(); kvsub++) { if (kvsub->second.m_typ != MAPT_MAP) continue; // Cant use getstring() here, 'cause we need the name of // the wire below kvwire = kvsub->second.u.m_m->find(KY_WIRE); if (kvwire == kvsub->second.u.m_m->end()) continue; if (kvwire->second.m_typ != MAPT_STRING) continue; if (kvwire->second.u.m_s->size() == 0) continue; fprintf(fp, "\twire\t%s;\t// %s.%s.%s.%s\n", kvwire->second.u.m_s->c_str(), kvpair->first.c_str(), kvint->first.c_str(), kvsub->first.c_str(), kvwire->first.c_str()); } } fprintf(fp, "\t// }}}\n"); fprintf(fp, "\t////////////////////////////////////////////////////////////////////////\n" "\t//\n\t// Component declarations\n\t// {{{\n" "\t// These declarations come from the @MAIN.DEFNS keys found in the\n" "\t// various components comprising the design.\n\t//\n"); writeout(fp, master, KYMAIN_DEFNS); // Declare interrupt vector wires. fprintf(fp, "\n// }}}\n" "\t////////////////////////////////////////////////////////////////////////\n" "\t//\n\t// Declaring interrupt vector wires\n\t// {{{\n" "\t// These declarations come from the various components having\n" "\t// PIC and PIC.MAX keys.\n\t//\n"); for(unsigned picid=0; picid < piclist.size(); picid++) { STRINGP defnstr, vecstr; MAPDHASH *picmap; if (piclist[picid]->i_max <= 0) continue; picmap = getmap(master, *piclist[picid]->i_name); if (!picmap) continue; vecstr = getstring(*picmap, KYPIC_BUS); if (vecstr) { fprintf(fp, "\twire\t[%d:0]\t%s;\n", piclist[picid]->i_max-1, vecstr->c_str()); } else { defnstr = piclist[picid]->i_name; if (defnstr) fprintf(fp, "\twire\t[%d:0]\t%s_int_vec;\n", piclist[picid]->i_max-1, defnstr->c_str()); } } fprintf(fp, "\t// }}}\n"); writeout_bus_defns_v(fp); // Define the select lines fprintf(fp, "\t////////////////////////////////////////////////////////////////////////\n" "\t//\n" "\t// Peripheral address decoding, bus handling\n\t// {{{\n"); writeout_bus_logic_v(fp); fprintf(fp, "\t// }}}\n" "\t////////////////////////////////////////////////////////////////////////\n" "\t//\n\t// Declare the interrupt busses\n\t// {{{\n" "\t// Interrupt busses are defined by anything with a @PIC tag.\n" "\t// The @PIC.BUS tag defines the name of the wire bus below,\n" "\t// while the @PIC.MAX tag determines the size of the bus width.\n" "\t//\n" "\t// For your peripheral to be assigned to this bus, it must have an\n" "\t// @INT.NAME.WIRE= tag to define the wire name of the interrupt line,\n" "\t// and an @INT.NAME.PIC= tag matching the @PIC.BUS tag of the bus\n" "\t// your interrupt will be assigned to. If an @INT.NAME.ID tag also\n" "\t// exists, then your interrupt will be assigned to the position given\n" "\t// by the ID# in that tag.\n" "\t//\n"); for(unsigned picid=0; picid < piclist.size(); picid++) { STRINGP defnstr, vecstr; MAPDHASH *picmap; if (piclist[picid]->i_max <= 0) continue; picmap = getmap(master, *piclist[picid]->i_name); if (!picmap) continue; vecstr = getstring(*picmap, KYPIC_BUS); if (vecstr) { fprintf(fp, "\tassign\t%s = {\n", vecstr->c_str()); } else { defnstr = piclist[picid]->i_name; if (defnstr) fprintf(fp, "\tassign\t%s_int_vec = {\n", defnstr->c_str()); else { gbl_msg.error("PIC has no associated name\n"); continue; } } for(int iid=piclist[picid]->i_max-1; iid>=0; iid--) { INTP iip = piclist[picid]->getint(iid); if ((iip == NULL)||(iip->i_wire == NULL) ||(iip->i_wire->size() == 0)) { fprintf(fp, "\t\t1\'b0%s\n", (iid != 0)?",":""); continue; } fprintf(fp, "\t\t%s%s\n", iip->i_wire->c_str(), (iid == 0)?"":","); } fprintf(fp, "\t};\n"); } fprintf(fp, "\t// }}}\n"); fprintf(fp, "\t////////////////////////////////////////////////////////////////////////\n" "\t////////////////////////////////////////////////////////////////////////\n" "\t//\n\t// @MAIN.INSERT and @MAIN.ALT\n" "\t// {{{\n" "\t////////////////////////////////////////////////////////////////////////\n" "\t////////////////////////////////////////////////////////////////////////\n"); fprintf(fp, "\t//\n" "\t//\n" "\t// Now we turn to defining all of the parts and pieces of what\n" "\t// each of the various peripherals does, and what logic it needs.\n" "\t//\n" "\t// This information comes from the @MAIN.INSERT and @MAIN.ALT tags.\n" "\t// If an @ACCESS tag is available, an ifdef is created to handle\n" "\t// having the access and not. If the @ACCESS tag is `defined above\n" "\t// then the @MAIN.INSERT code is executed. If not, the @MAIN.ALT\n" "\t// code is exeucted, together with any other cleanup settings that\n" "\t// might need to take place--such as returning zeros to the bus,\n" "\t// or making sure all of the various interrupt wires are set to\n" "\t// zero if the component is not included.\n" "\t//\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { // MAPDHASH::iterator kvpair, kvaccess, kvsearch; MAPDHASH::iterator kvint, kvsub, kvwire; bool nomain, noaccess, noalt; STRINGP insert, alt, access; char *accessdup, *accesstok; if (kvpair->second.m_typ != MAPT_MAP) continue; insert = getstring(kvpair->second, KYMAIN_INSERT); access = getstring(kvpair->second, KYACCESS); alt = getstring(kvpair->second, KYMAIN_ALT); nomain = false; noaccess = false; noalt = false; accessdup= NULL; if (NULL == insert) nomain = true; if (NULL == access) { noaccess= true; } else { accessdup = strdup(access->c_str()); accesstok = strtok(accessdup, DELIMITERS); if (accesstok[0] == '!') accesstok++; } if (NULL == alt) noalt = true; if (noaccess) { if (!nomain) fputs(insert->c_str(), fp); } else if ((!nomain)||(!noalt)) { if (nomain) { fprintf(fp, "`ifndef\t%s\n", accesstok); } else { fprintf(fp, "`ifdef\t%s\n", accesstok); fprintf(fp, "\t// {{{\n"); fputs(insert->c_str(), fp); fprintf(fp, "\t// }}}\n"); fprintf(fp, "`else\t// %s\n", accesstok); } fprintf(fp, "\t// {{{\n"); if (!noalt) { fputs(alt->c_str(), fp); } if (isbusmaster(kvpair->second)) { // {{{ STRINGP pfx = getstring(*kvpair->second.u.m_m, KYPREFIX); if (pfx) { STRINGP busname = getstring( *kvpair->second.u.m_m, KYMASTER_BUS_NAME); if (busname) { BUSINFO *bus = find_bus(busname); if (bus) { fprintf(fp, "\t// Null bus master\n\t// {{{\n"); bus->writeout_no_master_v(fp); fprintf(fp, "\t// }}}\n"); } } } // }}} } if (isperipheral(kvpair->second)) { // {{{ BUSINFO *bi = find_bus_of_peripheral(kvpair->second.u.m_m); STRINGP pfx = getstring(*kvpair->second.u.m_m, KYSLAVE_PREFIX); if ((bi)&&(pfx)) { fprintf(fp, "\t// Null bus slave\n\t// {{{\n"); bi->writeout_no_slave_v(fp, pfx); fprintf(fp, "\t// }}}\n"); } // }}} } kvint = kvpair->second.u.m_m->find(KY_INT); if ((kvint != kvpair->second.u.m_m->end()) &&(kvint->second.m_typ == MAPT_MAP)) { MAPDHASH *imap = kvint->second.u.m_m, *smap; fprintf(fp, "\t// Null interrupt definitions\n" "\t// {{{\n"); for(kvsub=imap->begin(); kvsub != imap->end(); kvsub++) { // p.INT.SUB if (kvsub->second.m_typ != MAPT_MAP) continue; smap = kvsub->second.u.m_m; kvwire = smap->find(KY_WIRE); if (kvwire == smap->end()) continue; if (kvwire->second.m_typ != MAPT_STRING) continue; if ((NULL == kvwire->second.u.m_s) ||(kvwire->second.u.m_s->size()==0)) continue; fprintf(fp, "\tassign\t%s = 1\'b0;\t// %s.%s.%s.%s\n", kvwire->second.u.m_s->c_str(), kvpair->first.c_str(), kvint->first.c_str(), kvsub->first.c_str(), kvwire->first.c_str()); } fprintf(fp, "\t// }}}\n"); } fprintf(fp, "\t// }}}\n"); fprintf(fp, "`endif\t// %s\n\n", accesstok); } if (accessdup) free(accessdup); } fprintf(fp, "\t// }}}\nendmodule // main.v\n"); } // }}} STRINGP remove_comments(STRINGP s) { STRINGP r; int si, di; // Source and destination indices r = new STRING(*s); for(si=0, di=0; (*s)[si]; si++) { if (((*s)[si] == '/')&&((*s)[si+1])&&((*s)[si+1] == '/')) { // Comment to the end of the line si += 2; while(((*s)[si])&&((*s)[si] != '\r')&&((*s)[si] != '\n')) si++; } else if (((*s)[si] == '/')&&((*s)[si+1])&&((*s)[si+1] == '*')) { si += 2; // Go until the end of a block comment while(((*s)[si])&&((*s)[si] != '*')&&((!(*s)[si+1])||((*s)[si+1]!='/'))) si++; si += 1; } else (*r)[di++] = (*s)[si]; } (*r)[di] = '\0'; return r; } void build_outfile_aux(MAPDHASH &info, STRINGP fname, STRINGP data) { STRING str; STRINGP subd = getstring(info, KYSUBD); if (NULL != strchr(fname->c_str(), '/')) { gbl_msg.warning("Output files can only be placed in output directory\n" "Output file: %s ignored\n", fname->c_str()); return; } FILE *fp; str = subd->c_str(); str += "/"+(*fname); fp = fopen(str.c_str(), "w"); if (NULL == fp) gbl_msg.fatal("Cannot write %s\n", str.c_str()); unsigned nw = fwrite(data->c_str(), 1, data->size(), fp); if (nw != data->size()) gbl_msg.fatal("%s data not fully written\n", str.c_str()); } void build_other_files(MAPDHASH &info) { MAPDHASH::iterator kvpair; STRINGP fname, data; for(kvpair = info.begin(); kvpair != info.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; fname = getstring(kvpair->second, KYOUT_FILE); if (NULL == fname) continue; data = getstring(kvpair->second, KYOUT_DATA); if (NULL == data) continue; build_outfile_aux(info, fname, data); } } FILE *open_in(MAPDHASH &info, const STRING &fname) { static const char delimiters[] = " \t\n:,"; STRINGP path = getstring(info, KYPATH); STRING pathcpy; char *tok; FILE *fp; if (!path) path = getstring(gbl_hash, KYPATH); if (path && fname[0] != '.' && fname[0] != '/') { pathcpy = *path; tok =strtok((char *)pathcpy.c_str(), delimiters); while(NULL != tok) { char *prepath = realpath(tok, NULL); STRING fpath = STRING(prepath) + "/" + fname; free(prepath); if (NULL != (fp = fopen(fpath.c_str(), "r"))) { return fp; } tok = strtok(NULL, delimiters); } } return fopen(fname.c_str(), "r"); } typedef std::vector PORTLIST; void get_portlist(MAPDHASH &master, PORTLIST &ports) { MAPDHASH::iterator kvpair; STRINGP str, stripped; char *pptr; for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { const char *DELIMITERS = ", \t\n"; if (kvpair->second.m_typ != MAPT_MAP) continue; str = getstring(kvpair->second, KYTOP_PORTLIST); if (str == NULL) str = getstring(kvpair->second, KYMAIN_PORTLIST); if (str == NULL) continue; stripped = remove_comments(str); pptr = strtok((char *)stripped->c_str(), DELIMITERS); while(pptr) { ports.push_back(new STRING(pptr)); gbl_msg.info("\t%s\n", pptr); pptr = strtok(NULL, DELIMITERS); } delete stripped; } // Check any CLOCK.TOP keys for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { const char *DELIMITERS = ", \t\n"; if (kvpair->second.m_typ != MAPT_MAP) continue; str = getstring(kvpair->second, KYCLOCK_TOP); if (str == NULL) continue; stripped = remove_comments(str); pptr = strtok((char *)stripped->c_str(), DELIMITERS); while(pptr) { ports.push_back(new STRING(pptr)); gbl_msg.info("\t%s\n", pptr); pptr = strtok(NULL, DELIMITERS); } delete stripped; } } void build_xdc(MAPDHASH &master, FILE *fp, STRING &fname) { MAPDHASH::iterator kvpair; STRINGP str; PORTLIST ports; FILE *fpsrc; char line[512]; gbl_msg.info("\n\nBUILD-XDC\nLooking for ports:\n"); gbl_msg.flush(); get_portlist(master, ports); str = getstring(master, KYXDC_FILE); fpsrc = open_in(master, *str); if (!fpsrc) { gbl_msg.fatal("Could not find or open %s\n", str->c_str()); } // Uncomment any lines referencing top-level ports // {{{ while(fgets(line, sizeof(line), fpsrc)) { const char *GET_PORTS_KEY = "get_ports", *SET_PROPERTY_KEY = "set_property"; const char *cptr; STRINGP tmp = trim(STRING(line)); strcpy(line, tmp->c_str()); delete tmp; // Ignore any lines that don't begin with #, // Ignore any lines that start with two ##'s, // Ignore any lines that don't have set_property within them if ((line[0] != '#')||(line[1] == '#') ||(NULL == (cptr= strstr(line, SET_PROPERTY_KEY)))) { fprintf(fp, "%s\n", line); continue; } if (NULL != (cptr = strstr(cptr, GET_PORTS_KEY))) { bool found = false; cptr += strlen(GET_PORTS_KEY); while((*cptr)&&(*cptr != '{')&&(isspace(*cptr))) cptr++; if (*cptr == '{') cptr++; if (!(*cptr)) { fprintf(fp, "%s\n", line); continue; } while((*cptr)&&(isspace(*cptr))) cptr++; char *ptr, *name; name = strdup(cptr); ptr = name; while((*ptr) &&(*ptr != '[') &&(*ptr != '}') &&(*ptr != ']') &&(!isspace(*ptr))) ptr++; *ptr = '\0'; gbl_msg.info("Found XDC port: %s\n", name); // Now, let's check to see if this is in our set for(unsigned k=0; kc_str(), name)==0) { found = true; break; } } free(name); if (found) { int start = 0; while((line[start])&&( (line[start]=='#') ||(isspace(line[start])))) start++; fprintf(fp, "%s\n", &line[start]); } else fprintf(fp, "%s\n", line); } else fprintf(fp, "%s\n", line); } // }}} fclose(fpsrc); fprintf(fp, "\n## Adding in any XDC_INSERT tags\n\n"); // {{{ for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; str = getstring(kvpair->second, KYXDC_INSERT); if (NULL == str) { fprintf(fp, "## No XDC.INSERT tag in %s\n", kvpair->first.c_str()); continue; } fprintf(fp, "## From %s\n%s", kvpair->first.c_str(), str->c_str()); } str = getstring(master, KYXDC_INSERT); if (NULL != str) { fprintf(fp, "## From the global level\n%s", str->c_str()); } // }}} } void build_pcf(MAPDHASH &master, FILE *fp, STRING &fname) { MAPDHASH::iterator kvpair; STRINGP str; PORTLIST ports; FILE *fpsrc; char line[512]; gbl_msg.info("\n\nBUILD-PCF\nLooking for ports:\n"); gbl_msg.flush(); get_portlist(master, ports); str = getstring(master, KYPCF_FILE); fpsrc = open_in(master, *str); if (!fpsrc) { gbl_msg.fatal("Could not find or open %s\n", str->c_str()); } // Uncomment any lines referencing top-level ports // {{{ while(fgets(line, sizeof(line), fpsrc)) { const char *SET_IO_KEY = "set_io"; const char *cptr; STRINGP tmp = trim(STRING(line)); strcpy(line, tmp->c_str()); delete tmp; // Ignore any lines that don't begin with #, // Ignore any lines that start with two ##'s, // Ignore any lines that don't have the SET_IO_KEY within them if ((line[0] != '#')||(line[1] == '#') ||(NULL == (cptr= strstr(line, SET_IO_KEY)))) { fprintf(fp, "%s\n", line); continue; } bool found = false; char *cpy = strdup(cptr + strlen(SET_IO_KEY)); char *ptr, *name; name = strtok(cpy, " \t"); ptr = name; while((*ptr) &&(*ptr != '[') &&(*ptr != '}') &&(*ptr != ']') &&(!isspace(*ptr))) ptr++; *ptr = '\0'; gbl_msg.info("Found PCF port: %s\n", name); // Now, let's check to see if this is in our set for(unsigned k=0; kc_str(), name)==0) { found = true; break; } } free(cpy); if (found) { int start = 0; while((line[start])&&( (line[start]=='#') ||(isspace(line[start])))) start++; fprintf(fp, "%s\n", &line[start]); } else fprintf(fp, "%s\n", line); } fclose(fpsrc); // }}} fprintf(fp, "\n## Adding in any PCF_INSERT tags\n\n"); // {{{ for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; str = getstring(kvpair->second, KYPCF_INSERT); if (NULL == str) { fprintf(fp, "## No PCF.INSERT tag in %s\n", kvpair->first.c_str()); continue; } fprintf(fp, "## From %s\n%s", kvpair->first.c_str(), str->c_str()); } str = getstring(master, KYPCF_INSERT); if (NULL != str) { fprintf(fp, "## From the global level\n%s", str->c_str()); } // }}} } void build_lpf(MAPDHASH &master, FILE *fp, STRING &fname) { MAPDHASH::iterator kvpair; STRINGP str; PORTLIST ports; FILE *fpsrc; char line[512]; gbl_msg.info("\n\nBUILD-LPF\nLooking for ports:\n"); gbl_msg.flush(); get_portlist(master, ports); // Uncomment any lines referencing top-level ports // {{{ str = getstring(master, KYLPF_FILE); fpsrc = open_in(master, *str); if (!fpsrc) { gbl_msg.fatal("Could not find or open %s\n", str->c_str()); } while(fgets(line, sizeof(line), fpsrc)) { const char *LOC_KEY = "LOCATE COMP", *BUF_KEY = "IOBUF PORT"; const char *locp, *bufp, *keyp; STRINGP tmp = trim(STRING(line)); strcpy(line, tmp->c_str()); delete tmp; // Ignore any lines that don't begin with #, // Ignore any lines that start with two ##'s, // Ignore any lines that don't have either key within them if ((line[0] != '#')||(line[1] == '#') ||((NULL == (locp= strcasestr(line, LOC_KEY))) &&(NULL == (bufp= strcasestr(line, BUF_KEY))))) { fprintf(fp, "%s\n", line); continue; } bool found = false; keyp = LOC_KEY; if (!locp) { locp = bufp; keyp = BUF_KEY; } if (strncmp(locp+strlen(keyp), " \"", 2)==0) locp += 2; char *cpy = strdup(locp + strlen(keyp)); char *ptr, *name; name = strtok(cpy, " \t"); ptr = name; while((*ptr) &&(*ptr != '[') &&(*ptr != '}') &&(*ptr != ']') &&(*ptr != '\"') &&(!isspace(*ptr))) ptr++; *ptr = '\0'; gbl_msg.info("Found LOC port: %s\n", name); // Now, let's check to see if this is in our set for(unsigned k=0; kc_str(), name)==0) { found = true; break; } } free(cpy); if (found) { int start = 0; while((line[start])&&( (line[start]=='#') ||(isspace(line[start])))) start++; fprintf(fp, "%s\n", &line[start]); } else fprintf(fp, "%s\n", line); } fclose(fpsrc); // }}} fprintf(fp, "\n## Adding in any LPF_INSERT tags\n\n"); // {{{ for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; str = getstring(kvpair->second, KYLPF_INSERT); if (NULL == str) continue; fprintf(fp, "## From %s\n%s", kvpair->first.c_str(), str->c_str()); } str = getstring(master, KYLPF_INSERT); if (NULL != str) { fprintf(fp, "## From the global level\n%s", str->c_str()); } // }}} } void build_ucf(MAPDHASH &master, FILE *fp, STRING &fname) { MAPDHASH::iterator kvpair; STRINGP str; FILE *fpsrc; PORTLIST ports; char line[512]; gbl_msg.info("\n\nBUILD-UCF\nLooking for ports:\n"); gbl_msg.flush(); get_portlist(master, ports); // Uncomment any lines referencing top-level ports // {{{ str = getstring(master, KYUCF_FILE); fpsrc = open_in(master, *str); if (!fpsrc) { gbl_msg.fatal("Could not find or open %s\n", str->c_str()); } while(fgets(line, sizeof(line), fpsrc)) { const char *NET_KEY = "NET"; const char *cptr; if ((line[0] == '#')&&(cptr = strstr(line, NET_KEY))) { bool found = false; cptr += strlen(NET_KEY); if (!isspace(*cptr)) { fprintf(fp, "%s", line); continue; } // Skip white space while((*cptr)&&(isspace(*cptr))) cptr++; // On a broken file, just continue if (!(*cptr)) { fprintf(fp, "%s", line); continue; } char *ptr, *name; name = strdup(cptr+1); ptr = name; while((*ptr)&&(!isspace(*ptr))&&(*ptr != ';')) ptr++; *ptr = '\0'; gbl_msg.info("Found UCF port: %s", name); gbl_msg.flush(); // Now, let's check to see if this is in our set for(unsigned k=0; kc_str(), name)==0) { found = true; break; } } free(name); if (found) { unsigned start = 0; while((line[start])&&( (line[start]=='#') ||(isspace(line[start])))) start++; fprintf(fp, "%s", &line[start]); } else fprintf(fp, "%s", line); } else fprintf(fp, "%s", line); } fclose(fpsrc); // }}} fprintf(fp, "\n## Adding in any UCF_INSERT tags\n\n"); // {{{ for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; str = getstring(kvpair->second, KYUCF_INSERT); if (str == NULL) continue; fprintf(fp, "## From %s\n%s", kvpair->first.c_str(), str->c_str()); } str = getstring(master, KYUCF_INSERT); if (NULL != str) { fprintf(fp, "## From the global level\n%s", str->c_str()); } // }}} } int main(int argc, char **argv) { int argn, nhash = 0; MAPDHASH master; FILE *fp; STRING str, cmdline, searchstr = "."; const char *subdir = NULL; // gbl_msg.open("autofpga.dbg", "w"); if (argc > 0) { cmdline = STRING(argv[0]); for(argn=1; argnc_str()); } if ((*subd)[subd->size()-1] == '/') (*subd).erase(subd->size()-1); { // Build ourselves a subdirectory for our outputs // First, check if the directory exists. // If it does not, then create it. struct stat sbuf; if (0 == stat(subd->c_str(), &sbuf)) { if (!S_ISDIR(sbuf.st_mode)) { gbl_msg.fatal("%s exists, and is not a directory\n" "Cowardly refusing to erase %s and build a directory in its place\n", subd->c_str(), subd->c_str()); } } else if (mkdir(subd->c_str(), 0777) != 0) { gbl_msg.fatal("Could not create %s/ directory\n", subd->c_str()); } } STRINGP legal = getstring(master, KYLEGAL); if (legal == NULL) { legal = getstring(master, KYCOPYRIGHT); if (legal == NULL) legal = new STRING("legalgen.txt"); setstring(master, KYLEGAL, legal); } flatten(master); // trimbykeylist(master, KYKEYS_TRIMLIST); cvtintbykeylist(master, KYKEYS_INTLIST); reeval(master); assign_interrupts(master); reeval(master); find_clocks(master); // assign_scopes( master); build_bus_list(master); // assign_addresses( master); // get_address_width(master); reeval(master); str = subd->c_str(); str += "/regdefs.h"; fp = fopen(str.c_str(), "w"); if (fp) { build_regdefs_h( master, fp, str); fclose(fp); } str = subd->c_str(); str += "/regdefs.cpp"; fp = fopen(str.c_str(), "w"); if (fp) { build_regdefs_cpp( master, fp, str); fclose(fp); } str = subd->c_str(); str += "/board.h"; fp = fopen(str.c_str(), "w"); if (fp) { build_board_h( master, fp, str); fclose(fp); } build_ld_files(master, subd); build_latex_tbls( master); str = subd->c_str(); str += "/toplevel.v"; fp = fopen(str.c_str(), "w"); if (fp) { build_toplevel_v( master, fp, str); fclose(fp); } str = subd->c_str(); str += "/main.v"; fp = fopen(str.c_str(), "w"); if (fp) { build_main_v( master, fp, str); // fprintf(fp, "//\n//\n//\n//\n//\n//\n"); // writeout_bus_defns_v(fp); // writeout_bus_logic_v(fp); fclose(fp); } build_cachable_v(master, subd); str = subd->c_str(); str += "/rtl.make.inc"; fp = fopen(str.c_str(), "w"); if (fp) { build_rtl_make_inc( master, fp, str); fclose(fp); } str = subd->c_str(); str += "/testb.h"; fp = fopen(str.c_str(), "w"); if (fp) { build_testb_h( master, fp, str); fclose(fp); } if (NULL != getstring(master, KYXDC_FILE)) { str = subd->c_str(); str += "/build.xdc"; fp = fopen(str.c_str(), "w"); if (fp) { build_xdc( master, fp, str); fclose(fp); } else gbl_msg.error("Cannot open %s !\n", str.c_str()); } if (NULL != getstring(master, KYPCF_FILE)) { str = subd->c_str(); str += "/build.pcf"; fp = fopen(str.c_str(), "w"); if (fp) { build_pcf( master, fp, str); fclose(fp); } else gbl_msg.error("Cannot open %s !\n", str.c_str()); } if (NULL != getstring(master, KYLPF_FILE)) { str = subd->c_str(); str += "/build.lpf"; fp = fopen(str.c_str(), "w"); if (fp) { build_lpf( master, fp, str); fclose(fp); } else gbl_msg.error("Cannot open %s !\n", str.c_str()); } if (NULL != getstring(master, KYUCF_FILE)) { str = subd->c_str(); str += "/build.ucf"; fp = fopen(str.c_str(), "w"); if (fp) { build_ucf( master, fp, str); fclose(fp); } } str = subd->c_str(); str += "/main_tb.cpp"; fp = fopen(str.c_str(), "w"); if (fp) { build_main_tb_cpp( master, fp, str); fclose(fp); } build_other_files(master); if (0 != gbl_msg.status()) gbl_msg.error("ERR: Errors present\n"); gbl_msg.dump(master); return gbl_msg.status(); } ================================================ FILE: sw/automdata.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/automdata.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2015-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef AUTOMDATA_H #define AUTOMDATA_H typedef struct BUSMASTER_S { const char *prefix; // to build %s_cyc const char *access; // for `ifdef } BUSMASTER; #endif ================================================ FILE: sw/autopdata.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/autopdata.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef AUTOPDATA_H #define AUTOPDATA_H typedef struct REGINFO_S { int offset; const char *defname; const char *namelist; } REGINFO; typedef struct AUTOPDATA_S { const char *prefix; int naddr; const char *access; const char *ext_ports, *ext_decls; const char *main_defns; const char *dbg_defns; const char *main_insert; const char *alt_insert; const char *dbg_insert; REGINFO *pregs; const char *cstruct, *ioname; } AUTOPDATA; #endif ================================================ FILE: sw/bitlib.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bitlib.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Basic bit-level processing functions. // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} // // nextlg // {{{ // This is basically ceil(log_2(vl)) // unsigned nextlg(const unsigned long vl) { unsigned r; for(r=0; (1ul<>1)+(vl & 0x55555555); r = (r & 0x33333333)+((r>> 2)&0x33333333); r = (r +(r>> 4))&0x0f0f0f0f; r = (r +(r>> 8))&0x001f001f; r = (r +(r>>16))&0x03f; return r; } // }}} ================================================ FILE: sw/bitlib.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bitlib.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef BITLIB_H #define BITLIB_H // // nextlg // // This is basically ceil(log_2(vl)) // unsigned nextlg(const unsigned long vl); // // popc // // Return the number of non-zero bits in a given value unsigned popc(const unsigned vl); #endif // BITLIB_H ================================================ FILE: sw/bldboardld.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldboardld.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Builds the board.h file, used by the CPU within the design // (if present) to know where particular components are located // on the bus. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "keys.h" #include "kveval.h" #include "legalnotice.h" #include "bldtestb.h" #include "bitlib.h" #include "plist.h" #include "bldregdefs.h" #include "ifdefs.h" #include "bldsim.h" #include "predicates.h" #include "businfo.h" #include "globals.h" #include "gather.h" #include "msgs.h" static void build_script_ld(MAPDHASH &master, MAPDHASH &busmaster, FILE *fp, STRING &fname) { MAPDHASH::iterator kvpair; STRINGP strp; int reset_address; PERIPHP fastmem = NULL, bigmem = NULL, bootmem = NULL; APLIST *alist; BUSINFO *bi; MAPDHASH *bimap; int found = 0; legal_notice(master, fp, fname, "/*******************************************************************************", "*"); fprintf(fp, "*/\n"); if (NULL == (strp = getstring(busmaster, KYLD_ENTRY))) fprintf(fp, "ENTRY(_start)\n\n"); else fprintf(fp, "ENTRY(%s)\n\n", strp->c_str()); bimap = getmap(busmaster, KYMASTER_BUS); if (bimap == NULL) { gbl_msg.error("Linker script not found within a bus master component\n"); return; } bi = find_bus(bimap); alist = gather_peripherals(bi); sort(alist->begin(), alist->end(), compare_regaddr); fprintf(fp, "MEMORY\n{\n" "\t/* To be listed here, a slave must be of type MEMORY. If the slave\n" "\t* has a defined name in its @%s tag, it will be listed here\n" "\t* under that name, otherwise it will be listed under it\'s\n" "\t* @$(PREFIX) tag with an underscore prepended to it. The permissions\n" "\t* are given by the @%s tag. Allowable permissions include\n" "\t* \'r\' (read only), \'rx\' (read and execute, but no writes),\n" "\t* \'wx\' (read, write, and execute). If no permission tag exists, a\n" "\t* permission of \'r\' will be assumed.\n" "\t*/\n", KYLD_NAME.c_str(), KYLD_PERM.c_str()); for(unsigned i=0; isize(); i++) { PERIPHP p = (*alist)[i]; STRINGP name = getstring(*p->p_phash, KYLD_NAME), perm = getstring(*p->p_phash, KYLD_PERM); if (!ismemory(*p->p_phash)) { // fprintf(fp,"\t\t/* %s is not a memory */\n", // (name) ? name->c_str():p->p_name->c_str()); continue; } if (NULL == name) name = p->p_name; found++; fprintf(fp,"\t%8s(%2s) : ORIGIN = 0x%08lx, LENGTH = 0x%08x\n", name->c_str(), (perm)?(perm->c_str()):"r", p->p_regbase, (p->naddr()*(p->p_slave_bus->data_width()/8))); if (perm != NULL && (perm->compare("wx") != 0) && (perm->compare("rx") != 0)) gbl_msg.warning("%s.LD.PERM=%s is not supported.\nUse either wx or rx as defined by ld\n", name->c_str(), perm->c_str()); if ((perm == NULL) || (tolower(perm->c_str()[0]) != 'w')) { // Read only memory must be flash if (!bootmem) bootmem = p; else if ((bootmem)&&(KYFLASH.compare(*name)==0)) // Unless flash is explicitly named bootmem = p; } else { // Find our bigest (and fastest?) memories if (!bigmem) bigmem = p; else if ((bigmem)&&(p->naddr() > bigmem->naddr())) { bigmem = p; } } } if (found == 0) fprintf(fp, "\t/* No memories found */\n"); fprintf(fp, "}\n\n"); fprintf(fp, "/* For each defined memory peripheral, we also define a pointer to that\n" "* memory. The name of this pointer is given by the @%s tag within\n" "* the memory peripheral\'s configuration\n" "*/\n", KYLD_NAME.c_str()); // Define pointers to these memories for(unsigned i=0; isize(); i++) { PERIPHP p = (*alist)[i]; STRINGP name = getstring(*p->p_phash, KYLD_NAME); if (!ismemory(*p->p_phash)) continue; if (NULL == name) name = p->p_name; fprintf(fp, "_%-8s = ORIGIN(%s);\n", name->c_str(), name->c_str()); } STRINGP defns, ldfile; defns = getstring(master, KYLD_DEFNS); if (NULL != defns) { ldfile = getstring(master, KYLD_FILE); if ((NULL == ldfile)||(ldfile->compare(fname)==0)) fprintf(fp, "%s\n", defns->c_str()); } for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { defns = getstring(kvpair->second, KYLD_DEFNS); if (NULL == defns) continue; ldfile = getstring(kvpair->second, KYLD_FILE); if ((NULL == ldfile)||(ldfile->compare(fname)==0)) fprintf(fp, "%s\n", defns->c_str()); } // // Check to see if the configuration for this master has already given // us a linker script to work with. If so, use it. // if (NULL != (strp = getstring(busmaster,KYLD_SCRIPT))) { fprintf(fp, "%s\n", strp->c_str()); // clear_regbase(alist); // delete alist; return; } // // There is no given configuration script. We'll have to try to build // one using a default that may or may not apply in all cases. This is // making the best of a bad situation. // if (!getvalue(master, KYRESET_ADDRESS, reset_address)) { bool found = false; for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (getvalue(*kvpair->second.u.m_m, KYRESET_ADDRESS, reset_address)) { found = true; break; } } if (!found) { if (bootmem) { reset_address = bootmem->p_regbase; } else { for(unsigned i=0; isize(); i++) { PERIPHP p = (*alist)[i]; if (!ismemory(*p->p_phash)) continue; STRINGP name = getstring(*p->p_phash, KYLD_NAME); if (NULL == name) { bootmem = p; name = p->p_name; } if (KYFLASH.compare(*name) == 0) { reset_address = p->p_regbase; bootmem = p; found = true; break; } } } } if (!found) { reset_address = 0; gbl_msg.warning("RESET_ADDRESS NOT FOUND, assuming address zero\n"); } } if ((reset_address != 0)&&(!bootmem)) { // We have a boot memory, but just don't know what it is. // Let's go find it for(unsigned i=0; isize(); i++) { PERIPHP p = (*alist)[i]; // If its not a memory, then we can't boot from it if (!ismemory(*p->p_phash)) continue; // If the reset address comes before this address, // then its not the right peripheral if ((unsigned)reset_address < p->p_regbase) continue; // Likewise if the reset address comes after this // peripheral, this peripheral isn't it either else if ((unsigned)reset_address >= p->p_regbase + (p->naddr() *(p->p_slave_bus->data_width()/8))) continue; // Otherwise we just found it. bootmem = p; break; } } if (!bootmem) { gbl_msg.warning("WARNING: No boot device, abandoning board.ld\n"); } else { fprintf(fp, "SECTIONS\n{\n"); fprintf(fp, "\t.rocode 0x%08x : ALIGN(4) {\n" "\t\t_boot_address = .;\n" "\t\t*(.start) *(.boot)\n", reset_address); fprintf(fp, "\t} > %s\n\t_kernel_image_start = . ;\n", bootmem->p_name->c_str()); if ((fastmem)&&(fastmem != bigmem)) { STRINGP name = getstring(*fastmem->p_phash, KYLD_NAME); if (!name) name = fastmem->p_name; fprintf(fp, "\t.fastcode : ALIGN_WITH_INPUT {\n" "\t\t*(.kernel)\n" "\t\t_kernel_image_end = . ;\n" "\t\t*(.start) *(.boot)\n"); fprintf(fp, "\t} > %s", name->c_str()); if (bootmem != fastmem) fprintf(fp, " AT>%s", bootmem->p_name->c_str()); fprintf(fp, "\n"); } else { fprintf(fp, "\t_kernel_image_end = . ;\n"); } if (bigmem) { STRINGP name = getstring(*bigmem->p_phash, KYLD_NAME); if (!name) name = bigmem->p_name; fprintf(fp, "\t_ram_image_start = . ;\n"); fprintf(fp, "\t.ramcode : ALIGN_WITH_INPUT {\n"); if ((!fastmem)||(fastmem == bigmem)) fprintf(fp, "\t\t*(.kernel)\n"); fprintf(fp, "" "\t\t*(.text.startup)\n" "\t\t*(.text*)\n" "\t\t*(.rodata*) *(.strings)\n" "\t\t*(.data) *(COMMON)\n" "\t\t}> %s", bigmem->p_name->c_str()); if (bootmem != bigmem) fprintf(fp, " AT> %s", bootmem->p_name->c_str()); fprintf(fp, "\n\t_ram_image_end = . ;\n" "\t.bss : ALIGN_WITH_INPUT {\n" "\t\t*(.bss)\n" "\t\t_bss_image_end = . ;\n" "\t\t} > %s\n", bigmem->p_name->c_str()); } fprintf(fp, "\t_top_of_heap = .;\n"); fprintf(fp, "}\n"); } } void build_ld_files(MAPDHASH &master, STRINGP subd) { FILE *fp; MAPDHASH::iterator kvpair; STRINGP fnamep; MAPDHASH *bimap; for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { STRINGP mtyp; if (kvpair->second.m_typ != MAPT_MAP) continue; fnamep = getstring(kvpair->second.u.m_m, KYLD_FILE); if (fnamep == NULL) // No linker script filename, ignore this component continue; bimap = getmap(kvpair->second.u.m_m, KYMASTER_BUS); if (bimap == NULL) { gbl_msg.error("Linker scripts can only be made within bus master. %s is not a bus master\n", kvpair->first.c_str()); continue; } mtyp = getstring(kvpair->second.u.m_m, KYMASTER_TYPE); if ((mtyp == NULL)||(KYSCRIPT.compare(*mtyp)!=0)) { gbl_msg.error("Linker script for %s " "must have type SCRIPT, not %s\n", kvpair->first.c_str(), (mtyp) ? mtyp->c_str() : "(NULL)"); continue; } if (fnamep->size() < 3) { gbl_msg.error("Linker script filename, %s, " "for %s is too short\n", fnamep->c_str(), kvpair->first.c_str()); continue; } else if ((*fnamep)[0] == '/') { gbl_msg.error("Cowardly refusing to write a linker " "script to an absolute pathname, %s\n", fnamep->c_str()); continue; } STRING fname = (*subd) + "/" + (*fnamep); if (strcmp(&fname.c_str()[fname.size()-3],".ld")!=0) fname += ".ld"; fp = fopen(fname.c_str(), "w"); if (fp == NULL) gbl_msg.error("Could not write linker script, %s\n", fname.c_str()); else { build_script_ld(master, *kvpair->second.u.m_m, fp, *fnamep); fclose(fp); } } } ================================================ FILE: sw/bldboardld.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldboardld.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef BLDBOARDLD_H #define BLDBOARDLD_H #include #include #include "parser.h" extern void build_ld_files(MAPDHASH &master, STRINGP subd); #endif // BLDBOARDLD_H ================================================ FILE: sw/bldcachable.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldcachable.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Creates a verilog file, upon request, containing combinatorial // logic returning true if a particular address beneath this // location in the address/bus hierarchy is a memory. This can be used // to determine if an address is a cachable address or not--something the // ZipCPU data cache needs to know. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include "bldcachable.h" #include "keys.h" #include "legalnotice.h" #include "businfo.h" #include "bitlib.h" #include "predicates.h" #include "msgs.h" static void print_cachable(FILE *fp, BUSINFO *bi, unsigned dw, unsigned mask_8, unsigned addr_8) { unsigned pbits; unsigned submask = 0, subaddr = 0; unsigned lgdw = nextlg(bi->data_width()), bbits=lgdw-3; PLIST *pl; pl = bi->m_plist; fprintf(fp, "\t\t// Bus master: %s\n", bi->name()->c_str()); submask = mask_8; // Octets for(unsigned i=0; isize(); i++) submask |= (*pl)[i]->p_mask << bbits; // bytes for(unsigned i=0; isize(); i++) { if (!(*pl)[i]->p_name) { continue; } if (((0)&&(*pl)[i]->p_mask == 0)) { continue;// } // Octets if (bi->word_addressing()) submask = ((*pl)[i]->p_mask<p_mask) | mask_8; subaddr = ((*pl)[i]->p_base | addr_8) & submask; pbits = nextlg(submask); if ((1ul<p_master_bus) { print_cachable(fp, (*pl)[i]->p_master_bus, dw, submask, subaddr); continue; } else if ((!(*pl)[i]->ismemory()) &&(!issubbus(*(*pl)[i]->p_phash))) { // fprintf(fp, "\t\t// %s: Not a memory\n", (*pl)[i]->p_name->c_str()); continue; } // pbits -= dw; fprintf(fp, "\t\t// %s\n" "\t\tif ((i_addr[%d:0] & %d'h%0*x) == %d'h%0*x)\n" "\t\t\to_cachable = 1'b1;\n", (*pl)[i]->p_name->c_str(), pbits - 1, pbits, (pbits+3)/4, submask, pbits, (pbits+3)/4, subaddr); } } void build_cachable_core_v(MAPDHASH &master, MAPDHASH &busmaster, FILE *fp, STRING &fname) { // We come in here after a CACHEABLE.FILE = (*fname) key char *modulename; const char *ptr; BUSINFO *bi; int dw; MAPDHASH *bimap; bimap = getmap(busmaster, KYMASTER_BUS); if (bimap == NULL) { gbl_msg.error("Could not find MASTER.BUS key for LD script file %s\n", fname.c_str()); return; } bi = find_bus(bimap); if (NULL == (ptr = strrchr(fname.c_str(),'/'))) modulename = strdup(fname.c_str()); else modulename = strdup(ptr+1); assert((strlen(modulename)>2) && strcmp(&modulename[strlen(modulename)-2],".v")==0); modulename[strlen(modulename)-2] = '\0'; legal_notice(master, fp, fname); fprintf(fp, "`default_nettype none\n" "//\n" "module %s(\n" "\t\t// {{{\n" "\t\tinput\twire\t[%d-1:0]\ti_addr,\n" "\t\toutput\treg\t\t\to_cachable\n" "\t\t// }}}\n" "\t);\n" "\n", modulename, bi->byte_address_width()); free(modulename); fprintf(fp, "\talways @(*)\n" "\tbegin\n" "\t\to_cachable = 1'b0;\n"); dw = bi->data_width(); dw = nextlg(dw)-3; print_cachable(fp, bi, dw, 0, 0); fprintf(fp, "\tend\n" "\n" "endmodule\n"); } void build_cachable_v(MAPDHASH &master, STRINGP subd) { FILE *fp; MAPDHASH::iterator kvpair; STRINGP fnamep; for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; fnamep = getstring(kvpair->second.u.m_m, KYCACHABLE_FILE); if (fnamep == NULL) // No cachable file tag, ignore this component continue; // A cachable file tag can only be found within a bus master // component if (fnamep->size() < 3) { gbl_msg.error("Cachable filename is too short\n", kvpair->first.c_str()); continue; } else if ((*fnamep)[0] == '/') { gbl_msg.error("Cowardly refusing to write cachable with an absolute pathname, %s\n", fnamep->c_str()); continue; } STRING fname = (*subd) + "/" + (*fnamep); if (strcmp(&fname.c_str()[fname.size()-2],".v") != 0) fname += ".v"; fp = fopen(fname.c_str(), "w"); if (fp == NULL) gbl_msg.error("Could not write cachable file: %s\n", fname.c_str()); else { build_cachable_core_v(master, *kvpair->second.u.m_m, fp, fname); fclose(fp); } } } ================================================ FILE: sw/bldcachable.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldcachable.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef BLDCACHABLE_H #define BLDCACHABLE_H #include #include #include "parser.h" extern void build_cachable_v(MAPDHASH &master, STRINGP subd); #endif // BLDCACHABLE_H ================================================ FILE: sw/bldregdefs.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldregdefs.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To build the regdefs.h and regdefs.cpp files. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "keys.h" #include "kveval.h" #include "legalnotice.h" #include "plist.h" #include "bldregdefs.h" #include "businfo.h" #include "subbus.h" #include "globals.h" #include "gather.h" #include "msgs.h" extern bool isperipheral(MAPT &pmap); extern bool isperipheral(MAPDHASH &phash); int get_longest_defname(APLIST *alist) { // {{{ const char DELIMITERS[] = ", \t\n"; unsigned longest_defname = 0; STRING str; for(unsigned i=0; isize(); i++) { MAPDHASH::iterator kvp; int nregs = 0; MAPDHASH *ph; ph = (*alist)[i]->p_phash; /* if ((*alist)[i]->isbus()) { SUBBUS *sbp; sbp = (SUBBUS *)(*alist[i]); assert(sbp->p_slave_bus); assert(sbp->p_master_bus); if (!sbp->p_slave_bus->need_translator(sbp->p_master_bus)) { unsigned k = get_longest_defname(*sbp->p_master_bus->m_plist); if (k > longest_defname) longest_defname = k; } }*/ if (!getvalue(*ph, KYREGS_N, nregs)) continue; for(int j=0; jend()) { fprintf(stderr, "%s not found\n", str.c_str()); continue; } if (kvp->second.m_typ != MAPT_STRING) { gbl_msg.info("%s is not a string\n", str.c_str()); continue; } STRING scpy = *kvp->second.u.m_s; char *nxtp, *rname; // 1. Read the number (Not used) strtoul(scpy.c_str(), &nxtp, 0); if ((nxtp==NULL)||(nxtp == scpy.c_str())) { fprintf(stderr, "No register name within string: %s\n", scpy.c_str()); continue; } // 2. Get the C name rname = strtok(nxtp, DELIMITERS); if (strlen(rname) > longest_defname) longest_defname = strlen(rname); } } return longest_defname; } // }}} // // write_regdefs // {{{ // This writes out the definitions of all the registers found within the plist // to the C++ header file given by fp. It takes as a parameter the longest // name definition, which we use to try to line things up in a prettier fashion // than we could without it. // void write_regdefs(FILE *fp, APLIST *alist, unsigned longest_defname) { const char DELIMITERS[] = ", \t\n"; STRING str; gbl_msg.info("WRITE-REGDEFS\n"); // Walk through this peripheral list one peripheral at a time for(unsigned i=0; isize(); i++) { MAPDHASH::iterator kvp; int nregs = 0; MAPDHASH *ph; STRINGP pname; ph = (*alist)[i]->p_phash; pname = (*alist)[i]->p_name; gbl_msg.info("WRITE-REGDEFS(%d, %s)\n", i, (NULL != pname)?pname->c_str() : "(No-name)"); // If there is a note key for this peripheral, place it into // the output without modifications. kvp = findkey(*ph,KYREGS_NOTE); if ((kvp != ph->end())&&(kvp->second.m_typ == MAPT_STRING)) fprintf(fp, "%s\n", kvp->second.u.m_s->c_str()); // Walk through each of the defined registers. There will be // @REGS.N registers defined. if (!getvalue(ph, KYREGS_N, nregs)) { gbl_msg.info("REGS.N not found in %s\n", pname->c_str()); continue; } gbl_msg.info("Looking for REGS in %s\n", pname->c_str()); // Now, walk through all of the register definitions for(int j=0; jp_regbase); fprintf(fp, "\t// %08lx, wbregs names: ", (*alist)[i]->p_regbase); int first = 1; // 3. Get the various user names while(NULL != (rv = strtok(NULL, DELIMITERS))) { if (!first) fprintf(fp, ", "); first = 0; fprintf(fp, "%s", rv); } fprintf(fp, "\n"); } } fprintf(fp, "\n\n"); } // }}} // // build_regdefs_h // {{{ // This builds a regdefs.h file, a file that can be used on a host in order // to access our design. // void build_regdefs_h( MAPDHASH &master, FILE *fp, STRING &fname) { MAPDHASH::iterator kvpair, kvaccess; STRING str; STRINGP strp; APLIST *alist; legal_notice(master, fp, fname); fprintf(fp, "#ifndef\tREGDEFS_H\n"); fprintf(fp, "#define\tREGDEFS_H\n"); fprintf(fp, "\n\n"); fprintf(fp, "//\n"); fprintf(fp, "// The @REGDEFS.H.INCLUDE tag\n"); fprintf(fp, "//\n"); fprintf(fp, "// @REGDEFS.H.INCLUDE for masters\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (isperipheral(kvpair->second)) continue; strp = getstring(kvpair->second, KYREGDEFS_H_INCLUDE); if (strp) fputs(strp->c_str(), fp); } fprintf(fp, "// @REGDEFS.H.INCLUDE for peripherals\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (!isperipheral(kvpair->second)) continue; strp = getstring(kvpair->second, KYREGDEFS_H_INCLUDE); if (strp) fputs(strp->c_str(), fp); } fprintf(fp, "// And finally any master REGDEFS.H.INCLUDE tags\n"); strp = getstring(master, KYREGDEFS_H_INCLUDE); if (strp) fputs(strp->c_str(), fp); fprintf(fp, "// End of definitions from REGDEFS.H.INCLUDE\n\n\n"); fprintf(fp, "//\n// Register address definitions, from @REGS.#d\n//\n"); unsigned longest_defname = 0; // Get the list of all peripherals alist = full_gather(); longest_defname = get_longest_defname(alist); write_regdefs(fp, alist, longest_defname); fprintf(fp, "//\n"); fprintf(fp, "// The @REGDEFS.H.DEFNS tag\n"); fprintf(fp, "//\n"); fprintf(fp, "// @REGDEFS.H.DEFNS for masters\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (isperipheral(kvpair->second)) continue; strp = getstring(kvpair->second, KYREGDEFS_H_DEFNS); if (strp) fputs(strp->c_str(), fp); } fprintf(fp, "// @REGDEFS.H.DEFNS for peripherals\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (!isperipheral(kvpair->second)) continue; strp = getstring(kvpair->second, KYREGDEFS_H_DEFNS); if (strp) fputs(strp->c_str(), fp); } fprintf(fp, "// @REGDEFS.H.DEFNS at the top level\n"); strp = getstring(master, KYREGDEFS_H_DEFNS); if (strp) fputs(strp->c_str(), fp); fprintf(fp, "// End of definitions from REGDEFS.H.DEFNS\n"); fprintf(fp, "//\n"); fprintf(fp, "// The @REGDEFS.H.INSERT tag\n"); fprintf(fp, "//\n"); fprintf(fp, "// @REGDEFS.H.INSERT for masters\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (isperipheral(kvpair->second)) continue; strp = getstring(kvpair->second, KYREGDEFS_H_INSERT); if (strp) fputs(strp->c_str(), fp); } fprintf(fp, "// @REGDEFS.H.INSERT for peripherals\n"); for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (!isperipheral(kvpair->second)) continue; strp = getstring(kvpair->second, KYREGDEFS_H_INSERT); if (strp) fputs(strp->c_str(), fp); } fprintf(fp, "// @REGDEFS.H.INSERT from the top level\n"); strp = getstring(master, KYREGDEFS_H_INSERT); if (strp) fputs(strp->c_str(), fp); fprintf(fp, "// End of definitions from REGDEFS.H.INSERT\n"); fprintf(fp, "\n\n"); fprintf(fp, "#endif\t// REGDEFS_H\n"); } // }}} // // get_longest_uname // {{{ // This is very similar to the get longest defname (get length of the longest // variable definition name) above, save that this is applied to the user // names within regdefs.cpp // unsigned get_longest_uname(APLIST *alist) { const char DELIMITERS[] = ", \t\n"; unsigned longest_uname = 0; STRING str; STRINGP strp; for(unsigned i=0; isize(); i++) { MAPDHASH::iterator kvp; MAPDHASH *ph; ph = (*alist)[i]->p_phash; int nregs = 0; if (!getvalue(*ph, KYREGS_N, nregs)) continue; for(int j=0; j longest_uname) longest_uname = strlen(rv); } } } return longest_uname; } // }}} // // write_regnames // {{{ // void write_regnames(FILE *fp, APLIST *alist, unsigned longest_defname, unsigned longest_uname) { const char DELIMITERS[] = ", \t\n"; STRING str; STRINGP strp; int first = 1; for(unsigned i=0; isize(); i++) { int nregs = 0; MAPDHASH *ph; ph = (*alist)[i]->p_phash; if (!getvalue(*ph, KYREGS_N, nregs)) continue; for(int j=0; jc_str(), fp); } else { fprintf(fp, "// No default include list found\n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); } fprintf(fp, "#include \"regdefs.h\"\n\n"); fprintf(fp, "const\tREGNAME\traw_bregs[] = {\n"); // Get the list of peripherals alist = full_gather(); // First, find out how long our longest definition name is. // This will help to allow us to line things up later. unsigned longest_defname = 0; unsigned longest_uname = 0; // Find the length of the longest register name longest_defname = get_longest_defname(alist); // Find the length of the longest user name string longest_uname = get_longest_uname(alist); write_regnames(fp, alist, longest_defname, longest_uname); fprintf(fp, "\n};\n\n"); fprintf(fp, "// REGSDEFS.CPP.INSERT for any bus masters\n"); for(MAPDHASH::iterator kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (isperipheral(kvpair->second)) continue; strp = getstring(kvpair->second, KYREGDEFS_CPP_INSERT); if (strp) fputs(strp->c_str(), fp); } fprintf(fp, "// And then from the peripherals\n"); for(MAPDHASH::iterator kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (!isperipheral(kvpair->second)) continue; strp = getstring(kvpair->second, KYREGDEFS_CPP_INSERT); if (strp) fputs(strp->c_str(), fp); } fprintf(fp, "// And finally any master REGS.CPP.INSERT tags\n"); if (NULL != (strp = getstring(master, KYREGDEFS_CPP_INSERT))) { fputs(strp->c_str(), fp); } } // }}} ================================================ FILE: sw/bldregdefs.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldregdefs.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To build the regdefs.h and regdefs.cpp files. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef BLDREGDEFS_H #define BLDREGDEFS_H #include #include "mapdhash.h" #include "plist.h" extern int get_longest_defname(PLIST &plist); // // write_regdefs // // This writes out the definitions of all the registers found within the plist // to the C++ header file given by fp. It takes as a parameter the longest // name definition, which we use to try to line things up in a prettier fashion // than we could without it. // extern void write_regdefs(FILE *fp, PLIST &plist, unsigned longest_defname); // // build_regdefs_h // // // This builds a regdefs.h file, a file that can be used on a host in order // to access our design. // extern void build_regdefs_h( MAPDHASH &master, FILE *fp, STRING &fname); // // get_longest_uname // // This is very similar to the get longest defname (get length of the longest // variable definition name) above, save that this is applied to the user // names within regdefs.cpp // extern unsigned get_longest_uname(PLIST &plist); // // write_regnames // // extern void write_regnames(FILE *fp, PLIST &plist, unsigned longest_defname, unsigned longest_uname); // // build_regdefs_cpp // extern void build_regdefs_cpp(MAPDHASH &master, FILE *fp, STRING &fname); #endif // BLDREGDEFS_H ================================================ FILE: sw/bldrtlmake.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldrtlmake.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To draw the information from the master hash database out in // to create a Makefile for an rtl/ directory. // // Builds: rtl.make.inc, for include'ing in your rtl Makefile // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "keys.h" #include "kveval.h" #include "legalnotice.h" #include "bldtestb.h" #include "bldboardld.h" #include "bitlib.h" #include "plist.h" #include "bldregdefs.h" #include "ifdefs.h" #include "bldsim.h" #include "predicates.h" #include "businfo.h" #include "globals.h" void build_rtl_make_inc(MAPDHASH &master, FILE *fp, STRING &fname) { MAPDHASH::iterator kvpair; STRINGP mksubd, mkgroup, mkfiles; STRING allgroups, vdirs; const char *DELIMITERS=", \t\r\n"; std::vector subdirs; legal_notice(master, fp, fname, "########################################" "########################################", "##"); for(kvpair=master.begin(); kvpair!=master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; mksubd = getstring(kvpair->second, KYRTL_MAKE_SUBD); mkgroup = getstring(kvpair->second, KYRTL_MAKE_GROUP); mkfiles = getstring(kvpair->second, KYRTL_MAKE_FILES); if (mksubd && mksubd->size() > 0) { bool prior_dir = false; for(auto k : subdirs) { if (mksubd->compare(*k)==0) { prior_dir = true; break; } } if (!prior_dir) subdirs.push_back(mksubd); } if (!mkfiles) continue; char *tokstr = strdup(mkfiles->c_str()), *tok; STRING filstr = ""; tok = strtok(tokstr, DELIMITERS); while(NULL != tok) { filstr += STRING(tok) + " "; tok = strtok(NULL, DELIMITERS); } if (filstr[filstr.size()-1] == ' ') filstr[filstr.size()-1] = '\0'; if (!mkgroup) { char temp[] = "MKGRPXXXXXX"; mkstemp(temp); unlink(temp); mkgroup = new STRING(temp); setstring(kvpair->second, KYRTL_MAKE_GROUP, mkgroup); STRINGP pfx = getstring(kvpair->second.u.m_m, KYPREFIX); if (NULL == pfx) pfx = new STRING("(Unnamed)"); fprintf(stderr, "WARNING: Creating a temporary group name for %s\n", pfx->c_str()); } if (mksubd && mksubd->size() > 0) { fprintf(fp, "%sD := %s\n", mkgroup->c_str(), mksubd->c_str()); fprintf(fp, "%s := $(addprefix $(%sD)/,%s)\n", mkgroup->c_str(), mkgroup->c_str(), filstr.c_str()); } else { fprintf(fp, "%s := %s\n\n", mkgroup->c_str(), filstr.c_str()); } STRING mkgroupref = STRING("$(") + (*mkgroup) + STRING(")"); if (std::string::npos == allgroups.find(mkgroupref)) allgroups = allgroups + STRING(" ") + mkgroupref; free(tokstr); } mksubd = getstring(master, KYRTL_MAKE_SUBD); mkgroup = getstring(master, KYRTL_MAKE_GROUP); if (NULL == mkgroup) mkgroup = new STRING(KYVFLIST); mkfiles = getstring(master, KYRTL_MAKE_FILES); mksubd = getstring(master, KYRTL_MAKE_SUBD); if (NULL != mkfiles) { if (mksubd && mksubd->size() > 0) { fprintf(fp, "%sD := %s\n", mkgroup->c_str(), mksubd->c_str()); fprintf(fp, "%s := $(addprefix $(%sD)/,%s) \\\t%s\n", mkgroup->c_str(), mkgroup->c_str(), mkfiles->c_str(), allgroups.c_str()); } else { fprintf(fp, "%s := %s //\t\t%s\n", mkgroup->c_str(), mkfiles->c_str(), allgroups.c_str()); } } else if (allgroups.size() > 0) { fprintf(fp, "%s := main.v %s\n", mkgroup->c_str(), allgroups.c_str()); } if (mksubd && mksubd->size() > 0) { bool prior_dir = false; for(auto k : subdirs) { if (mksubd->compare(*k)==0) { prior_dir = true; break; } } if (!prior_dir) subdirs.push_back(mksubd); } for(auto k : subdirs) vdirs = vdirs + STRING(" -y ") + (*k); mksubd = getstring(master, KYRTL_MAKE_VDIRS); if (NULL == mksubd) mksubd = new STRING(KYAUTOVDIRS); fprintf(fp, "%s := %s\n", mksubd->c_str(), vdirs.c_str()); } ================================================ FILE: sw/bldrtlmake.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldrtlmake.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To draw the information from the master hash database out in // to create a Makefile for an rtl/ directory. // // Builds: rtl.make.inc, for include'ing in your rtl Makefile // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef BLDRTLMAKE_H #define BLDRTLMAKE_H // #include #include "mapdhash.h" void build_rtl_make_inc(MAPDHASH &master, FILE *fp, STRING &fname); #endif ================================================ FILE: sw/bldsim.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldsim.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Builds a main_tb.cpp simulation file, which can then be called // from a master Verilator based simulation script. The primary // function of the simulation class defined herein is tick(), which // advances one of the clocks forward by one step while also simulating all // of the peripherals associated with that clock. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "keys.h" #include "legalnotice.h" #include "bldtestb.h" #include "msgs.h" extern void writeout(FILE *fp, MAPDHASH &master, const STRING &ky); bool tb_same_clock(MAPDHASH &info, STRINGP ckname) { MAPDHASH::iterator kvpair; STRINGP simclk; kvpair = findkey(info, KYSIM_CLOCK); if (info.end() != kvpair) { if (kvpair->second.m_typ == MAPT_MAP) kvpair = findkey(*kvpair->second.u.m_m, KY_NAME); if (info.end()== kvpair || kvpair->second.m_typ != MAPT_STRING) return false; simclk = kvpair->second.u.m_s; return (NULL != simclk) && (ckname->compare(*simclk)==0); } kvpair = findkey(info, KYCLOCK_NAME); if (info.end() == kvpair || kvpair->second.m_typ != MAPT_STRING) return false; simclk = kvpair->second.u.m_s; if (NULL != simclk) { const char DELIMITERS[] = " \t\n,"; char *dstr, *tok; bool result; dstr = strdup(simclk->c_str()); tok = strtok(dstr, DELIMITERS); result = (ckname->compare(tok)==0); tok = strtok(NULL, DELIMITERS); if (tok) result = false; free(dstr); return result; } return false; } bool tb_tick(MAPDHASH &info, STRINGP ckname, FILE *fp) { MAPDHASH::iterator kvpair; bool result = false; const STRING *ky = &KYSIM_TICK; if ((ckname)&&(fp)) fprintf(fp, "\t\t//\n\t\t// SIM.TICK tags go here for SIM.CLOCK=%s\n\t\t//\n", ckname->c_str()); else if (fp) fprintf(fp, "\t\t//\n\t\t// SIM.TICK tags go here for the default clock\n\t\t//\n"); if (tb_same_clock(info, ckname)) { STRINGP tick = getstring(info, *ky); if (tick) { if (fp) { fprintf(fp, "\t\t// %s from master\n", ky->c_str()); fprintf(fp, "%s", tick->c_str()); } result = true; } } for(kvpair=info.begin(); kvpair!=info.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; MAPDHASH *p = kvpair->second.u.m_m; MAPDHASH::iterator ckp; STRINGP tick = getstring(*p, *ky); if (!tick) continue; ckp = findkey(*p, KYSIM_CLOCK); if (p->end() == ckp) gbl_msg.warning("%s defines SIM.TICK, but not SIM.CLOCK\n", kvpair->first.c_str()); if (!tb_same_clock(*p, ckname)) continue; if (fp) { fprintf(fp, "\t\t// %s from %s\n", ky->c_str(), kvpair->first.c_str()); fprintf(fp, "%s", tick->c_str()); } result = true; } if ((fp)&&(!result)) fprintf(fp, "\t\t// No %s tags defined\n", ky->c_str()); return result; } bool tb_dbg_condition(MAPDHASH &info, STRINGP ckname, FILE *fp) { MAPDHASH::iterator kvpair; bool result = true; const STRING *ky = &KYSIM_DBGCONDITION; if (fp) fprintf(fp, "\t\t//\n\t\t// SIM.DBGCONDITION\n" "\t\t// Set writeout to true here for debug by printf access\n" "\t\t// to this routine\n" "\t\t//\n"); if (tb_same_clock(info, ckname)) { STRINGP tick = getstring(info, *ky); if (tick) { if (fp) { fprintf(fp, "\t\t// %s from master\n", ky->c_str()); fprintf(fp, "%s", tick->c_str()); } result= true; } } for(kvpair=info.begin(); kvpair!=info.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; MAPDHASH *p = kvpair->second.u.m_m; STRINGP tick = getstring(*p, *ky); if (!tick) continue; if (NULL == getstring(*p, KYSIM_CLOCK)) gbl_msg.warning("%s defines SIM.DBGCONDITION, but not SIM.CLOCK\n", kvpair->first.c_str()); if (!tb_same_clock(*p, ckname)) continue; if (fp) { fprintf(fp, "%s", tick->c_str()); } result = true; } if ((fp)&&(!result)) fprintf(fp, "\t\t// No %s tags defined\n", ky->c_str()); return result; } bool tb_debug(MAPDHASH &info, STRINGP ckname, FILE *fp) { MAPDHASH::iterator kvpair; bool result = false; const STRING *ky = &KYSIM_DEBUG; if (fp) fprintf(fp, "\t\t\t//\n\t\t\t// SIM.DEBUG tags can print here, supporting\n" "\t\t\t// any attempts to debug by printf. Following any\n" "\t\t\t// code you place here, a newline will close the\n" "\t\t\t// debug section.\n" "\t\t\t//\n"); if (tb_same_clock(info, ckname)) { STRINGP tick = getstring(info, *ky); if (tick) { if (fp) { fprintf(fp, "\t\t\t// %s from master\n", ky->c_str()); fprintf(fp, "%s", tick->c_str()); } result = true; } } for(kvpair=info.begin(); kvpair!=info.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; MAPDHASH *p = kvpair->second.u.m_m; STRINGP tick = getstring(*p, KYSIM_DEBUG); if (!tick) continue; if (NULL == getstring(*p, KYSIM_CLOCK)) gbl_msg.warning("%s defines SIM.DEBUG, but not SIM.CLOCK\n", kvpair->first.c_str()); if (!tb_same_clock(*p, ckname)) continue; if (fp) { fprintf(fp, "\t\t\t// %s from %s\n", ky->c_str(), kvpair->first.c_str()); fprintf(fp, "%s", tick->c_str()); } result = true; } if ((fp)&&(!result)) fprintf(fp, "\t\t\t// No %s tags defined\n", ky->c_str()); return result; } void build_main_tb_cpp(MAPDHASH &master, FILE *fp, STRING &fname) { MAPDHASH::iterator kvpair; STRINGP str; legal_notice(master, fp, fname); fprintf(fp, "//\n// SIM.INCLUDE\n//\n"); fprintf(fp, "// Any SIM.INCLUDE tags you define will be pasted here.\n"); fprintf(fp, "// This is useful for guaranteeing any include functions\n"); fprintf(fp, "// your simulation needs are called.\n//\n"); writeout(fp, master, KYSIM_INCLUDE); fprintf(fp, "//\n// SIM.DEFINES\n//\n"); fprintf(fp, "// This tag is useful fr pasting in any #define values that\n"); fprintf(fp, "// might then control the simulation following.\n//\n"); writeout(fp, master, KYSIM_DEFINES); // Class definitions fprintf(fp, "class\tMAINTB : public TESTB {\npublic:\n"); fprintf(fp, "\t\t// SIM.DEFNS\n\t\t//\n"); fprintf(fp, "\t\t// If you have any simulation components, create a\n"); fprintf(fp, "\t\t// SIM.DEFNS tag to have those components defined here\n"); fprintf(fp, "\t\t// as part of the main_tb.cpp function.\n"); writeout(fp, master, KYSIM_DEFNS); fprintf(fp, "\tMAINTB(void) {\n"); /* // Pre-Initial stuffs .... { bool have_initial = false; str = getstring(master, KYSIM_PREINITIAL); if (NULL != str) { fprintf(fp, ":\n%s", str->c_str()); have_initial = true; } for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; str = getstring(kvpair->second, KYSIM_PREINITIAL); if (str == NULL) continue; if (!have_initial) fprintf(fp, ":\n"); else fprintf(fp, ",\n"); have_initial = true; fprintf(fp, "\t// From %s\n%s", kvpair->first.c_str(), str->c_str()); } } fprintf(fp, "\t{\n"); */ fprintf(fp, "\t\t// SIM.INIT\n\t\t//\n"); fprintf(fp, "\t\t// If your simulation components need to be initialized,\n"); fprintf(fp, "\t\t// create a SIM.INIT tag. That tag\'s value will be pasted\n"); fprintf(fp, "\t\t// here.\n\t\t//\n"); str = getstring(master, KYSIM_INIT); if (NULL != str) { fprintf(fp, "\t%s", str->c_str()); } for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; str = getstring(kvpair->second, KYSIM_INIT); if (str == NULL) continue; fprintf(fp, "\t\t// From %s\n%s", kvpair->first.c_str(), str->c_str()); } fprintf(fp, "\t}\n\n"); fprintf(fp, "\tvoid\treset(void) {\n" "\t\t// SIM.SETRESET\n" "\t\t// If your simulation component needs logic before the\n" "\t\t// tick with reset set, that logic can be placed into\n" "\t\t// the SIM.SETRESET tag and thus pasted here.\n" "\t\t//\n"); writeout(fp, master, KYSIM_SETRESET); fprintf(fp, "\t\tTESTB::reset();\n"); fprintf(fp, "\t\t// SIM.CLRRESET\n" "\t\t// If your simulation component needs logic following the\n" "\t\t// reset tick, that logic can be placed into the\n" "\t\t// SIM.CLRRESET tag and thus pasted here.\n" "\t\t//\n"); writeout(fp, master, KYSIM_CLRRESET); fprintf(fp, "\t}\n"); fprintf(fp, "\n" "\tvoid trace(const char *vcd_trace_file_name) {\n" "\t\tfprintf(stderr, \"Opening TRACE(%%s)\\n\",\n" "\t\t vcd_trace_file_name);\n" "\t\topentrace(vcd_trace_file_name);\n" "\t\tm_time_ps = 0;\n" "\t}\n\n"); fprintf(fp, " void close(void) {\n" " m_done = true;\n" " }\n\n"); fprintf(fp, " void tick(void) {\n"); fprintf(fp, "\t\tTESTB::tick(); // Clock.size = %ld\n\t}\n\n", cklist.size()); for(unsigned i=0; ic_str()); have_debug = tb_debug(master, cklist[i].m_name, NULL); have_condition = tb_dbg_condition(master, cklist[i].m_name, NULL); have_sim_tick = tb_tick(master, cklist[i].m_name, NULL); if ((!have_sim_tick)&&(!have_condition)&&(!have_debug)) continue; fprintf(fp, "\n\t// sim_%s_tick() will be called from" " TESTB::tick()\n" "\t// following any falling edge of clock " "%s\n", cklist[i].m_name->c_str(), cklist[i].m_name->c_str()); fprintf(fp, "\tvirtual\tvoid\tsim_%s_tick(void) {\n", cklist[i].m_name->c_str()); if (0 == i) fprintf(fp, "\t\t// Default clock tick\n"); if ((have_debug)&&(have_condition)) fprintf(fp, "\t\tbool\twriteout;\n\n"); tb_tick(master, cklist[i].m_name, fp); if (!have_sim_tick) fprintf(fp, "\t\tm_changed = false;\n"); if ((have_debug)&&(have_condition)) { fprintf(fp, "\t\twriteout = false;\n"); tb_dbg_condition(master, cklist[i].m_name, fp); fprintf(fp, "\t\tif (writeout) {\n"); tb_debug(master, cklist[i].m_name, fp); fprintf(fp, "\t\t}\n"); } fprintf(fp, "\t}\n"); } if (cklist.size()>1) { for(unsigned i=0; ic_str()); fprintf(fp, "\tvirtual\tvoid\ttick_%s(void) {\n", cklist[i].m_name->c_str()); if (0 == i) fprintf(fp, "\t\t// Advance until the default clock ticks\n"); fprintf(fp, "\t\tdo {\n" "\t\t\ttick();\n" "\t\t} while(!m_%s.rising_edge());\n", cklist[i].m_name->c_str()); fprintf(fp, "\t}\n\n"); } } else { fprintf(fp, "\tinline\tvoid\ttick_%s(void) {\ttick();\t}\n\n", cklist[0].m_name->c_str()); } fprintf(fp, "\t//\n\t// The load function\n" "\t//\n" "\t// This function is required by designs that need the flash or memory\n" "\t// set prior to run time. The test harness should be able to call\n" "\t// this function to load values into any (memory-type) location\n" "\t// on the bus.\n" "\t//\n" "\tbool\tload(uint32_t addr, const char *buf, uint32_t len) {\n"); STRING prestr = STRING("\t\tuint32_t\tstart, offset, wlen, base, adrln;\n\n"); for(kvpair = master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; MAPDHASH *dev = kvpair->second.u.m_m, *bus; int base, naddr, dw; STRINGP accessp; const char *accessptr; str = getstring(kvpair->second, KYSIM_LOAD); if (str == NULL) continue; if (!getvalue(*dev, KYREGBASE, base)) continue; if (!getvalue(*dev, KYNADDR, naddr)) continue; if (NULL == (bus = getmap(*dev, KYSLAVE_BUS))) { gbl_msg.error("No map found for %s\n", kvpair->first.c_str()); continue; } if (!getvalue(*bus, KY_WIDTH, dw)) { gbl_msg.error("No bus width found for %s\n", kvpair->first.c_str()); continue; } accessp = getstring(*dev, KYACCESS); if (prestr[0]) { fprintf(fp, "%s", prestr.c_str()); prestr[0] = '\0'; } fprintf(fp, "\t\t//\n\t\t// Loading the %s component\n\t\t//\n", kvpair->first.c_str()); fprintf(fp, "\t\tbase = 0x%08x; // in octets\n" "\t\tadrln = 0x%08x;\n\n", base, naddr * (dw/8)); fprintf(fp, "\t\tif ((addr >= base)&&(addr < base + adrln)) {\n"); fprintf(fp, "\t\t\t// If the start access is in %s\n", kvpair->first.c_str()); fprintf(fp, "\t\t\tstart = (addr > base) ? (addr-base) : 0;\n"); fprintf(fp, "\t\t\toffset = (start + base) - addr;\n"); fprintf(fp, "\t\t\twlen = (len-offset > adrln - start)\n\t\t\t\t? (adrln - start) : len - offset;\n"); if (accessp) { accessptr = accessp->c_str(); if (accessptr[0] == '!') accessptr++; fprintf(fp, "#ifdef\t%s\n", accessptr); } else accessptr = NULL; fprintf(fp, "\t\t\t// FROM %s.%s\n", kvpair->first.c_str(), KYSIM_LOAD.c_str()); fprintf(fp, "%s", str->c_str()); fprintf(fp, "\t\t\t// AUTOFPGA::Now clean up anything else\n"); fprintf(fp, "\t\t\t// Was there more to write than we wrote?\n"); fprintf(fp, "\t\t\tif (addr + len > base + adrln)\n"); fprintf(fp, "\t\t\t\treturn load(base + adrln, &buf[offset+wlen], len-wlen);\n"); fprintf(fp, "\t\t\treturn true;\n"); if (accessp) { fprintf(fp, "#else\t// %s\n", accessptr); fprintf(fp, "\t\t\treturn false;\n"); fprintf(fp, "#endif\t// %s\n", accessptr); } fprintf(fp, "\t\t//\n" "\t\t// End of components with a SIM.LOAD tag, and a\n" "\t\t// non-zero number of addresses (NADDR)\n" "\t\t//\n"); fprintf(fp, "\t\t}\n\n"); } fprintf(fp, "\t\treturn false;\n"); fprintf(fp, "\t}\n\n"); fprintf(fp, "\t//\n\t// KYSIM.METHODS\n\t//\n" "\t// If your simulation code will need to call any of its own function\n" "\t// define this tag by those functions (or other sim code), and\n" "\t// it will be pasated here.\n" "\t//\n"); writeout(fp, master, KYSIM_METHODS); fprintf(fp, "\n};\n"); } ================================================ FILE: sw/bldsim.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldsim.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To build the main_tb.cpp file. // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef BLDSIM_H #define BLDSIM_H #include #include #include "parser.h" extern void writeout(FILE *fp, MAPDHASH &master, const STRING &ky); extern bool tb_same_clock(MAPDHASH &info, STRINGP ckname); extern bool tb_tick(MAPDHASH &info, STRINGP ckname, FILE *fp); extern void tb_dbg_condition(MAPDHASH &info, STRINGP ckname, FILE *fp); extern void tb_debug(MAPDHASH &info, STRINGP ckname, FILE *fp); extern void build_main_tb_cpp(MAPDHASH &master, FILE *fp, STRING &fname) ; #endif ================================================ FILE: sw/bldtestb.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldtestb.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To build a test framework that can be used with Verilator for // handling multiple clocks. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include "parser.h" #include "mapdhash.h" #include "keys.h" #include "bldtestb.h" #include "legalnotice.h" #include "clockinfo.h" void build_testb_h(MAPDHASH &master, FILE *fp, STRING &fname) { bool multiclock = false; // Find all the clocks in the design, and categorize them find_clocks(master); legal_notice(master, fp, fname); fprintf(fp, "" "#ifndef TESTB_H\n" "#define TESTB_H\n" "\n" "// #define TRACE_FST\n" "\n" "#include \n" "#include \n" "#ifdef TRACE_FST\n" "#define\tTRACECLASS\tVerilatedFstC\n" "#include \n" "#else // TRACE_FST\n" "#define\tTRACECLASS\tVerilatedVcdC\n" "#include \n" "#endif\n"); if (cklist.size() == 0) { fprintf(stderr, "ERR: No clocks defined!\n"); exit(EXIT_FAILURE); } if (cklist.size() > 1) multiclock = true; else if (cklist[0].m_simclass != NULL) multiclock = true; else multiclock = false; if (multiclock) fprintf(fp, "#include \n"); fprintf(fp, "\n" "\t//\n" "\t// The TESTB class is a useful wrapper for interacting with a Verilator\n" "\t// based design. Key to its capabilities are the tick() method for\n" "\t// advancing the simulation timestep, and the opentrace() and\n" "\t// closetrace() methods for handling VCD tracefile generation. To\n" "\t// use a non-VCD trace, redefine TRACECLASS before calling this\n" "\t// function to the trace class you wish to use.\n//\n" "template class TESTB {\n" "public:\n" " VA *m_core;\n" " bool m_changed;\n" " TRACECLASS* m_trace;\n" " bool m_done, m_paused_trace;\n" " uint64_t m_time_ps;\n"); if (multiclock) { fprintf(fp, "\t// TBCLOCK is a clock support class, enabling" " multiclock simulation\n\t// operation.\n"); for(unsigned i=0; ic_str() : "TBCLOCK", cklist[i].m_name->c_str()); } else { fprintf(fp, "\n" "\t//\n" "\t// Since design has only one clock within it, we won't need to use the\n" "\t// multiclock techniques, and so those aren't included here at this time.\n" "\t//\n"); } fprintf(fp, "\n" " TESTB(void) {\n" " // {{{\n" " m_core = new VA;\n" " m_time_ps = 0ul;\n" " m_trace = NULL;\n" " m_done = false;\n" " m_paused_trace = false;\n" " Verilated::traceEverOn(true);\n"); if (multiclock) { fprintf(fp, "// Set the initial clock periods\n"); for(unsigned i=0; ic_str(), cklist[i].interval_ps()); freq = 1e6 / cklist[i].interval_ps(); fprintf(fp, "\t//%8.2f MHz\n", freq); } } fprintf(fp, " }\n" " // }}}\n" "\n" " virtual ~TESTB(void) {\n" " // {{{\n" " if (m_trace) m_trace->close();\n" " delete m_core;\n" " m_core = NULL;\n" " }\n" " // }}}\n" "\n" "\t//\n" "\t// opentrace()\n" "\t// {{{\n" "\t//\n" "\t// Useful for beginning a (VCD) trace. To open such a trace, just call\n" "\t// opentrace() with the name of the VCD file you'd like to trace\n" "\t// everything into\n" " virtual void opentrace(const char *vcdname, int depth=99) {\n" " if (!m_trace) {\n" " m_trace = new TRACECLASS;\n" " m_core->trace(m_trace, 99);\n" " m_trace->spTrace()->set_time_resolution(\"ps\");\n" " m_trace->spTrace()->set_time_unit(\"ps\");\n" " m_trace->open(vcdname);\n" " m_paused_trace = false;\n" " }\n" " }\n" "\t// }}}\n" "\n" "\t//\n" "\t// trace()\n" "\t// {{{\n" "\t// A synonym for opentrace() above.\n" "\t//\n" " void trace(const char *vcdname) {\n" " opentrace(vcdname);\n" " }\n" "\t// }}}\n" "\n" "\t//\n" "\t// pausetrace(pause)\n" "\t// {{{\n" "\t// Set/clear a flag telling us whether or not to write to the VCD trace\n" "\t// file. The default is to write to the file, but this can be changed\n" "\t// by calling pausetrace. pausetrace(false) will resume tracing,\n" "\t// whereas pausetrace(true) will stop all calls to Verilator's trace()\n" "\t// function\n" "\t//\n" " virtual bool pausetrace(bool pausetrace) {\n" " m_paused_trace = pausetrace;\n" " return m_paused_trace;\n" " }\n" "\t// }}}\n" "\n" "\t//\n" "\t// pausetrace()\n" "\t// {{{\n" "\t// Like pausetrace(bool) above, except that pausetrace() will return\n" "\t// the current status of the pausetrace flag above. Specifically, it\n" "\t// will return true if the trace has been paused or false otherwise.\n" " virtual bool pausetrace(void) {\n" " return m_paused_trace;\n" " }\n" "\t// }}}\n" "\n" "\t//\n" "\t// closetrace()\n" "\t// {{{\n" "\t// Closes the open trace file. No more information will be written\n" "\t// to it\n" " virtual void closetrace(void) {\n" " if (m_trace) {\n" " m_trace->close();\n" " delete m_trace;\n" " m_trace = NULL;\n" " }\n" " }\n" "\t// }}}\n" "\n" "\t//\n" "\t// eval()\n" "\t// {{{\n" "\t// This is a synonym for Verilator's eval() function. It evaluates all\n" "\t// of the logic within the design. AutoFPGA based designs shouldn't\n" "\t// need to be calling this, they should call tick() instead. However,\n" "\t// in the off chance that your design inputs depend upon combinatorial\n" "\t// expressions that would be output based upon other input expressions,\n" "\t// you might need to call this function.\n" " virtual void eval(void) {\n" " m_core->eval();\n" " }\n" "\t// }}}\n" "\n" "\t//\n" "\t// tick()\n" "\t// {{{\n" "\t// tick() is the main entry point into this helper core. In general,\n" "\t// tick() will advance the clock by one clock tick. In a multiple clock\n" "\t// design, this will advance the clocks up until the nearest clock\n" "\t// transition.\n" " virtual void tick(void) {\n"); if (multiclock) { fprintf(fp, "" "\t\tunsigned mintime = m_%s.time_to_edge();\n\n", cklist[0].m_name->c_str()); for(unsigned i=1; ic_str(), cklist[i].m_name->c_str()); fprintf(fp, "\t\tassert(mintime > 1);\n\n"); fprintf(fp, "\t\t// Pre-evaluate, to give verilator a chance" " to settle any\n\t\t// combinatorial logic that" "that may have changed since the\n\t\t// last clock" "evaluation, and then record that in the trace.\n"); fprintf(fp, "\t\teval();\n" "\t\tif (m_trace && !m_paused_trace) m_trace->dump(m_time_ps+1);\n\n"); fprintf(fp, "\t\t// Advance each clock\n"); for(unsigned i=0; i%s = m_%s.advance(mintime);\n", cklist[i].m_wire->c_str(), cklist[i].m_name->c_str()); fprintf(fp, "\n\t\tm_time_ps += mintime;\n"); } else { unsigned long clock_duration_ps, quarter_tick, half_tick; clock_duration_ps = cklist[0].interval_ps(); half_tick = clock_duration_ps / 2; quarter_tick = half_tick / 2; fprintf(fp, "\t\t// Pre-evaluate, to give verilator a chance\n" "\t\t// to settle any combinatorial logic that\n" "\t\t// that may have changed since the last clock\n" "\t\t// evaluation, and then record that in the\n" "\t\t// trace.\n"); fprintf(fp, "\t\teval();\n" "\t\tif (m_trace && !m_paused_trace) m_trace->dump(m_time_ps+%ld);\n\n", quarter_tick); fprintf(fp, "\t\t// Advance the one simulation clock, %s\n", cklist[0].m_name->c_str()); fprintf(fp, "\t\tm_time_ps+= %ld;\n", half_tick); fprintf(fp, "\t\tm_core->%s = 1;\n", cklist[0].m_wire->c_str()); } fprintf(fp, "\t\teval();\n" "\t\t// If we are keeping a trace, dump the current state to " "that\n\t\t// trace now\n" "\t\tif (m_trace && !m_paused_trace) {\n" "\t\t\tm_trace->dump(m_time_ps);\n" "\t\t\tm_trace->flush();\n" "\t\t}\n\n"); if (multiclock) { for(unsigned i=0; ic_str(), cklist[i].m_name->c_str()); } else { unsigned long clock_duration_ps, previous; clock_duration_ps = cklist[0].interval_ps(); previous = clock_duration_ps/2; fprintf(fp, "\t\t// :\n" "\t\t// Advance the clock again, so that it has " "its negative edge\n"); fprintf(fp, "\t\tm_core->%s = 0;\n" "\t\tm_time_ps+= %ld;\n" "\t\teval();\n" "\t\tif (m_trace && !m_paused_trace) m_trace->dump(m_time_ps);\n\n", cklist[0].m_wire->c_str(), clock_duration_ps-previous); fprintf(fp, "\t\t// Call to see if any simulation components need\n" "\t\t// to advance their inputs based upon this clock\n"); fprintf(fp, "\t\tsim_%s_tick();\n", cklist[0].m_name->c_str()); } fprintf(fp, "\t}\n" "\t// }}}\n" "\n"); for(unsigned i=0; ic_str()); } fprintf(fp, "" "\tvirtual bool done(void) {\n" "\t\t// {{{\n" "\t\tif (m_done)\n" "\t\t\treturn true;\n" "\n" "\t\tif (Verilated::gotFinish())\n" "\t\t\tm_done = true;\n" "\n" "\t\treturn m_done;\n" "\t}\n" "\t// }}}\n" "\n"); fprintf(fp, "" "\t//\n" "\t// reset()\n" "\t// {{{\n" "\t// Sets the i_reset input for one clock tick. It's really just a\n" "\t// function for the capabilies shown below. You'll want to reset any\n" "\t// external input values before calling this though.\n" "\tvirtual void reset(void) {\n" "\t m_core->i_reset = 1;\n" "\t tick();\n"); if (cklist.size() > 1) { fprintf(fp, "" "\t while(!m_core->i_clk)\n" "\t tick();\n"); } fprintf(fp, "" "\t m_core->i_reset = 0;\n" "\t // printf(\"RESET\\n\");\n" "\t}\n" "\t// }}}\n" "};\n" "\n" "#endif\t// TESTB\n" "\n"); } ================================================ FILE: sw/bldtestb.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bldtestb.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To build a test framework that can be used with Verilator for // handling multiple clocks. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef BLDTESTB_H #define BLDTESTB_H #include "parser.h" #include "mapdhash.h" #include "clockinfo.h" // Build the test bench sim driver helper, that handles clocks and clock ticks. extern void build_testb_h(MAPDHASH &master, FILE *fp, STRING &fname); #endif // BLDTESTB_H ================================================ FILE: sw/bus/axi.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bus/axi.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // Tags used: // // BUS.WIDTH // BUS.AWID // // SLAVE.TYPE: // - SINGLE // - DOUBLE // - OTHER/MEMORY/BUS // SLAVE.OPTIONS= // // string of case-insensitive options // ROM (slave has no write ports) // WOM (slave has no read ports) // FULL (default:slave has no all ports, not just the ports used) // SLAVE.SHARE= // // slave shares parts of the interface with the other listed slaves // // MASTER.TYPE= // (currently ignored) // // INTERCONNECT.TYPE // - SINGLE // - CROSSBAR // // INTERCONNECT.MASTERS // = list of the PREFIXs of all of the masters of this bus // // INTERCONNECT.OPTIONS // = string of case-insensitive options // OPT_STARVATION_TIMEOUT // OPT_LOWPOWER // OPT_DBLBUFFER // // // INTERCONNECT.OPTVAL= // = Options that require values // - OPT_TIMEOUT // - LGMAXBURST // // Creates tags: // // BLIST: A list of bus interconnect parameters, somewhat like: // @$(SLAVE.BUS)_cyc, // @$(SLAVE.BUS)_stb, // (if !ROM&!WOM) @$(SLAVE.BUS)_we, // (if AWID>0) @$(SLAVE.BUS)_addr[@$(SLAVE.AWID)-1:0], // (if !ROM) @$(SLAVE.BUS)_data, // (if !ROM) @$(SLAVE.BUS)_sel, // @$(PREFIX)_stall, // @$(PREFIX)_ack, // (if !WOM) @$(PREFIX)_data, // (and possibly) @$(PREFIX)_err // // ASCBLIST.PREFIX: [%io] prefix // ASCBLIST.SUFFIX: // ASCBLIST.CAPS: // ASCBLIST.DATA: // .@$(ASCBLIST.PREFIX)cyc@$(ASCBLIST.SUFFIX)(@$SLAVE.BUS)_cyc), // .@$(ASCBLIST.PREFIX)stb@$(ASCBLIST.SUFFIX)(@$SLAVE.BUS)_stb), // .@$(ASCBLIST.PREFIX)we@$(ASCBLIST.SUFFIX)(@$SLAVE.BUS)_we), // . // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include "../parser.h" #include "../mapdhash.h" #include "../keys.h" #include "../kveval.h" #include "../legalnotice.h" #include "../bldtestb.h" #include "../bitlib.h" #include "../plist.h" #include "../bldregdefs.h" #include "../ifdefs.h" #include "../bldsim.h" #include "../predicates.h" #include "../businfo.h" #include "../globals.h" #include "../subbus.h" #include "../msgs.h" #include "../genbus.h" #include "axil.h" #include "axi.h" #define PREFIX extern AXIBUSCLASS axiclass; const unsigned AXI_MIN_ADDRESS_WIDTH = 12; AXIBUS::AXIBUS(BUSINFO *bi) : AXILBUS(bi) { // {{{ m_info = bi; m_slist = NULL; m_dlist = NULL; m_is_single = false; m_is_double = false; m_num_single = 0; m_num_double = 0; m_num_total = 0; } // }}} void AXIBUS::allocate_subbus(void) { // {{{ PLIST *pl = m_info->m_plist; BUSINFO *sbi = NULL, *dbi = NULL; if (NULL == pl || pl->size() == 0) { gbl_msg.warning("Bus %s has no attached slaves\n", (name()) ? name()->c_str() : "(No-name)"); } gbl_msg.info("Generating AXI4 bus logic generator for %s\n", (name()) ? name()->c_str() : "(No-name)"); countsio(); if (m_num_single == m_num_total) { m_num_single = 0; m_is_single = true; } else if ((m_num_single <= 2)&&(m_num_double > 0)) { // Merge single and double busses, making single // slaves into double slaves m_num_double += m_num_single; m_num_single = 0; } if (!m_is_single && m_num_single + m_num_double == m_num_total) { m_num_single = 0; m_num_double = 0; m_is_double = true; } assert(!m_is_single || !m_is_double); assert(m_num_single < 50); assert(m_num_double < 50); assert(m_num_total >= m_num_single + m_num_double); // // Master of multiple classes // if (!m_is_single && m_num_single > 0) { sbi = create_sio(); m_num_total++; } if (!m_is_double && m_num_double > 0) { m_num_total++; dbi = create_dio(); } if (!m_is_single && !m_is_double && pl) { // // There exist peripherals that are neither singles nor doubles // for(unsigned pi = 0; pi< pl->size(); pi++) { PERIPHP p = (*pl)[pi]; STRINGP ptyp; ptyp = getstring(p->p_phash, KYSLAVE_TYPE); if (m_slist && ptyp != NULL && ptyp->compare(KYSINGLE) == 0) { m_info->m_plist->erase(pl->begin()+pi); pi--; m_slist->add(p); } else if (m_dlist && ptyp != NULL && ptyp->compare(KYDOUBLE) == 0) { m_info->m_plist->erase(pl->begin()+pi); pi--; m_dlist->add(p); } else { // Leave this peripheral in m_info->m_plist } } } if (sbi) setstring(sbi->m_hash, KY_TYPE, axiclass.name()); if (dbi) setstring(dbi->m_hash, KY_TYPE, axiclass.name()); REHASH; } // }}} int AXIBUS::address_width(void) { // {{{ assert(m_info); return m_info->m_address_width; } // }}} bool AXIBUS::get_base_address(MAPDHASH *phash, unsigned &base) { // {{{ if (!m_info || !m_info->m_plist) { gbl_msg.error("BUS[%s] has no peripherals!\n", (name()) ? name()->c_str() : "(No name)"); return false; } else return m_info->m_plist->get_base_address(phash, base); } // }}} bool compare_idwidths(BMASTERP a, BMASTERP b) { int aidw, bidw; assert(a); assert(b); if (!getvalue(a->m_hash, KYMASTER_IDWIDTH, aidw)) { aidw = 0; gbl_msg.error("Bus master %s has no required ID width specified, assuming 0 bits\n", a->name()->c_str()); } if (!getvalue(a->m_hash, KYMASTER_IDWIDTH, bidw)) { bidw = 0; gbl_msg.error("Bus master %s has no required ID width specified, assuming 0 bits\n", b->name()->c_str()); } return (aidw < bidw); } /* void AXIBUS::assign_ids(void) { int id_width; if (!m_info) return; if (m_info->m_ids_assigned) return; gbl_msg.info("AXI4: Assigning IDs for bus %s\n", (name()) ? name()->c_str() : "(No name bus)"); if (m_info->m_list->size() == 0) { m_id_width = 0; return; } else if (m_info->m_list->size() == 0) { BMASTERP m = (*m_info->m_list)[0]; if (!getvalue(m->m_hash, KYMASTER_IDWIDTH, m_id_width)) { gbl_msg.warning("Bus master %s has no required ID width specified, assuming 0 bits\n", m->name()->c_str()); gbl_msg.info("This is a warning since bus %s has only one master", name()->c_str()); m_id_width = 0; } return; } sort(m_info->m_list->begin(), m_info->m_list->end(), compare_idwidths); base = 0; for(auto p=m_info->m_list->begin(); p!=m_info->m_list->end(); p++) { if (!getvalue((*m_info->m_list)[0]->m_hash, KYMASTER_IDWIDTH, iw) iw = 1; id = base + ((1<m_list)[0]->m_hash, KYMASTER_BUSID, id); } setvalue(m_info->m_hash, KY_IDWIDTH, nextlg(base)); } */ void AXIBUS::assign_addresses(void) { // {{{ int address_width; if (m_info->m_addresses_assigned) return; if ((NULL == m_slist)&&(NULL == m_dlist)) allocate_subbus(); if (!m_info) return; gbl_msg.info("AXI4: Assigning addresses for bus %s\n", (name()) ? name()->c_str() : "(No name bus)"); if (!m_info->m_plist||(m_info->m_plist->size() < 1)) { m_info->m_address_width = 0; } else if (!m_info->m_addresses_assigned) { int dw = m_info->data_width(), nullsz; if (m_slist) m_slist->assign_addresses(dw, 0); if (m_dlist) m_dlist->assign_addresses(dw, 0); if (!getvalue(*m_info->m_hash, KY_NULLSZ, nullsz)) nullsz = 0; m_info->m_plist->assign_addresses(dw, nullsz, AXI_MIN_ADDRESS_WIDTH); address_width = m_info->m_plist->get_address_width(); m_info->m_address_width = address_width; if (m_info->m_hash) { setvalue(*m_info->m_hash, KY_AWID, m_info->m_address_width); REHASH; } } m_info->m_addresses_assigned = true; } // }}} BUSINFO *AXIBUS::create_sio(void) { // {{{ assert(m_info); BUSINFO *sbi; SUBBUS *subp; STRINGP sioname; MAPDHASH *bushash, *shash; MAPT elm; sioname = new STRING(STRING("" PREFIX) + (*name()) + "_sio"); bushash = new MAPDHASH(); shash = new MAPDHASH(); setstring(*shash, KYPREFIX, sioname); setstring(*shash, KYSLAVE_TYPE, new STRING(KYDOUBLE)); setstring(*shash, KYSLAVE_PREFIX, sioname); elm.m_typ = MAPT_MAP; elm.u.m_m = bushash; shash->insert(KEYVALUE(KYSLAVE_BUS, elm)); elm.u.m_m = m_info->m_hash; shash->insert(KEYVALUE(KYMASTER_BUS, elm)); setstring(shash, KYMASTER_TYPE, KYARBITER); sbi = new BUSINFO(sioname); sbi->prefix(new STRING("_sio")); setstring(bushash, KY_TYPE, new STRING("axi4")); sbi->m_data_width = m_info->m_data_width; sbi->m_clock = m_info->m_clock; sbi->addmaster(m_info->m_hash); subp = new SUBBUS(shash, sioname, sbi); subp->p_slave_bus = m_info; // subp->p_master_bus = set by the SUBBUS to be sbi m_info->m_plist->add(subp); // m_plist->integrity_check(); sbi->add(); m_slist = sbi->m_plist; return sbi; } // }}} BUSINFO *AXIBUS::create_dio(void) { // {{{ assert(m_info); BUSINFO *dbi; SUBBUS *subp; STRINGP dioname; MAPDHASH *bushash, *shash; MAPT elm; dioname = new STRING(STRING("" PREFIX) + (*name()) + "_dio"); bushash = new MAPDHASH(); shash = new MAPDHASH(); setstring(*bushash, KY_NAME, dioname); setstring(*shash, KYPREFIX, dioname); setstring(*shash, KYSLAVE_TYPE, new STRING(KYOTHER)); setstring(*shash, KYSLAVE_PREFIX, dioname); elm.m_typ = MAPT_MAP; elm.u.m_m = m_info->m_hash; shash->insert(KEYVALUE(KYSLAVE_BUS, elm)); elm.u.m_m = bushash; shash->insert(KEYVALUE(KYMASTER_BUS, elm)); setstring(shash, KYMASTER_TYPE, KYARBITER); dbi = new BUSINFO(dioname); dbi->prefix(new STRING("_dio")); setstring(bushash, KY_TYPE, new STRING("axi4")); setvalue(*bushash, KY_WIDTH, m_info->data_width()); dbi->m_data_width = m_info->m_data_width; dbi->m_clock = m_info->m_clock; dbi->addmaster(m_info->m_hash); subp = new SUBBUS(shash, dioname, dbi); subp->p_slave_bus = m_info; m_info->m_plist->add(subp); // subp->p_master_bus = set by the slave to be dbi dbi->add(); m_dlist = dbi->m_plist; return dbi; } // }}} int AXIBUS::id_width(void) { int value; if (m_info && getvalue(m_info->m_hash, KY_IDWIDTH, value)) return m_id_width = value; return m_id_width; } void AXIBUS::writeout_defn_v(FILE *fp, const char *mstype, const char *pname, const char* busp, const char *btyp){ // {{{ STRINGP n = name(); int aw = address_width(); int iw = id_width(); fprintf(fp, "\t// AXI4 %s definitions for bus %s%s,\n" "\t// component %s, with prefix %s\n" "\t// {{{\n", mstype, n->c_str(), btyp, pname, busp); fprintf(fp, "\t// Verilator lint_off UNUSED\n"); fprintf(fp, "\twire\t\t%s_awvalid;\n", busp); fprintf(fp, "\twire\t\t%s_awready;\n", busp); fprintf(fp, "\twire\t[%d:0]\t%s_awid;\n", iw-1, busp); fprintf(fp, "\twire\t[%d:0]\t%s_awaddr;\n", aw-1, busp); fprintf(fp, "\twire\t[7:0]\t%s_awlen;\n", busp); fprintf(fp, "\twire\t[2:0]\t%s_awsize;\n", busp); fprintf(fp, "\twire\t[1:0]\t%s_awburst;\n", busp); fprintf(fp, "\twire\t\t%s_awlock;\n", busp); fprintf(fp, "\twire\t[3:0]\t%s_awcache;\n", busp); fprintf(fp, "\twire\t[2:0]\t%s_awprot;\n", busp); fprintf(fp, "\twire\t[3:0]\t%s_awqos;\n", busp); fprintf(fp, "\t//\n"); // fprintf(fp, "\twire\t\t%s_wvalid;\n", busp); fprintf(fp, "\twire\t\t%s_wready;\n", busp); fprintf(fp, "\twire\t[%d:0]\t%s_wdata;\n\n", m_info->data_width()-1, busp); fprintf(fp, "\twire\t[%d:0]\t%s_wstrb;\n\n", m_info->data_width()/8-1, busp); fprintf(fp, "\twire\t\t%s_wlast;\n\n", busp); // fprintf(fp, "\twire\t\t%s_bvalid;\n", busp); fprintf(fp, "\twire\t\t%s_bready;\n", busp); fprintf(fp, "\twire\t[%d:0]\t%s_bid;\n", iw-1, busp); fprintf(fp, "\twire\t[1:0]\t%s_bresp;\n", busp); // fprintf(fp, "\twire\t\t%s_arvalid;\n", busp); fprintf(fp, "\twire\t\t%s_arready;\n", busp); fprintf(fp, "\twire\t[%d:0]\t%s_arid;\n", iw-1, busp); fprintf(fp, "\twire\t[%d:0]\t%s_araddr;\n", aw-1, busp); fprintf(fp, "\twire\t[7:0]\t%s_arlen;\n", busp); fprintf(fp, "\twire\t[2:0]\t%s_arsize;\n", busp); fprintf(fp, "\twire\t[1:0]\t%s_arburst;\n", busp); fprintf(fp, "\twire\t\t%s_arlock;\n", busp); fprintf(fp, "\twire\t[3:0]\t%s_arcache;\n", busp); fprintf(fp, "\twire\t[2:0]\t%s_arprot;\n", busp); fprintf(fp, "\twire\t[3:0]\t%s_arqos;\n", busp); fprintf(fp, "\t//\n"); // fprintf(fp, "\twire\t\t%s_rvalid;\n", busp); fprintf(fp, "\twire\t\t%s_rready;\n", busp); fprintf(fp, "\twire\t[%d:0]\t%s_rid;\n", iw-1, busp); fprintf(fp, "\twire\t[%d:0]\t%s_rdata;\n\n", m_info->data_width()-1, busp); fprintf(fp, "\twire\t\t%s_rlast;\n\n", busp); fprintf(fp, "\twire\t[1:0]\t%s_rresp;\n", busp); fprintf(fp, "\t// Verilator lint_on UNUSED\n" "\t// }}}\n"); } // }}} // Inherited from AXI-lite void AXIBUS::writeout_bus_slave_defns_v(FILE *fp) { // {{{ PLIST *p = m_info->m_plist; STRINGP n = name(); if (m_slist) { for(PLIST::iterator pp=m_slist->begin(); pp != m_slist->end(); pp++) { writeout_defn_v(fp, "slave", (*pp)->p_name->c_str(), (*pp)->bus_prefix()->c_str(), "(SIO)"); } } else if (!m_is_single) fprintf(fp, "\n\t// Bus %s has no SINGLE slaves\n\t//\n", n->c_str()); else fprintf(fp, "\n\t// Bus %s is all SINGLE slaves\n\t//\n", n->c_str()); if (m_dlist) { for(PLIST::iterator pp=m_dlist->begin(); pp != m_dlist->end(); pp++) { writeout_defn_v(fp, "slave", (*pp)->p_name->c_str(), (*pp)->bus_prefix()->c_str(), "(DIO)"); } } else if (!m_is_double) fprintf(fp, "\n\t// Bus %s has no DOUBLE slaves\n\t//\n", n->c_str()); else fprintf(fp, "\n\t// Bus %s is all DOUBLE slaves\n\t//\n", n->c_str()); if (p) { for(PLIST::iterator pp=p->begin(); pp != p->end(); pp++) { writeout_defn_v(fp, "slave", (*pp)->p_name->c_str(), (*pp)->bus_prefix()->c_str()); } } else { gbl_msg.error("%s has no slaves\n", n->c_str()); } } // }}} void AXIBUS::writeout_bus_master_defns_v(FILE *fp) { // {{{ MLIST *m = m_info->m_mlist; STRINGP n = name(); if (m) { for(MLIST::iterator pp=m->begin(); pp != m->end(); pp++) { writeout_defn_v(fp, "master", (*pp)->name()->c_str(), (*pp)->bus_prefix()->c_str()); } } else { gbl_msg.warning("Bus %s has no masters\n", n->c_str()); } } // }}} // void AXIBUS::write_addr_range(FILE *fp, const PERIPHP p, const int dalines) // void AXIBUS::writeout_no_slave_v(FILE *fp, STRINGP prefix) // void AXIBUS::writeout_no_master_v(FILE *fp) // STRINGP AXIBUS::master_name(int k) // // Connect this master to the crossbar. Specifically, we want to output // a list of master connections to fill the given port. // // void AXILBUS::xbarcon_master(FILE *fp, const char *tabs, // // Output a list of connections to slave bus wires. Used in connecting the // slaves to the various crossbar inputs. // // void AXILBUS::xbarcon_slave(FILE *fp, PLIST *pl, const char *tabs, // const char *pfx,const char *sig, bool comma) void AXIBUS::writeout_bus_logic_v(FILE *fp) { STRINGP n = name(), rst; CLOCKINFO *c = m_info->m_clock; PLIST::iterator pp; PLISTP pl; // unsigned unused_lsbs; MLISTP m_mlist = m_info->m_mlist; if (NULL == m_info->m_plist) return; if (NULL == m_info->m_mlist) { gbl_msg.warning("No masters assigned to bus %s\n", n->c_str()); } if (NULL == (rst = m_info->reset_wire())) { gbl_msg.warning("Bus %s has no associated reset wire, using \'i_reset\'\n", n->c_str()); rst = new STRING("i_reset"); setstring(m_info->m_hash, KY_RESET, rst); REHASH; } if (NULL == c || NULL == c->m_wire) { gbl_msg.fatal("Bus %s has no associated clock\n", n->c_str()); } // unused_lsbs = nextlg(m_info->data_width())-3; if (m_info->m_plist->size() == 0) { // No slaves // {{{ fprintf(fp, "\t//\n" "\t// Bus %s has no slaves\n" "\t//\n\n", n->c_str()); // Since this bus has no slaves, any attempt to access it // needs to cause a bus error. // // Need to loop through all possible masters ... for(unsigned m=0; m_info && m < m_info->m_mlist->size(); m++) { STRINGP mstr = master_name(m); const char *mp = mstr->c_str(); // const char *pfx = (*m_info->m_mlist)[m]->bus_prefix()->c_str(); fprintf(fp, "\t//\n" "\t// The %s bus has no slaves assigned to it\n" "\t//\n", mp); fprintf(fp, "\t// The no-slave peripheral\n" "\t//\n" "\taxiempty #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d),\n" "\t\t.C_AXI_ID_WIDTH(%d),\n" "\t\t// }}}\n", address_width(), m_info->data_width(), id_width()); fprintf(fp, "\t) %s_no_slavep (\n" "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s), .S_AXI_ARESETN(%s),\n" "\t\t//\n", mp, c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t.S_AXI_AWVALID(%s_awvalid), .S_AXI_AWREADY(%s_awready),\n" "\t\t\t.S_AXI_AWID(%s_awid),\n" "\t\t//\n" "\t\t.S_AXI_WVALID(%s_wvalid), .S_AXI_WREADY(%s_wready),\n" "\t\t\t.S_AXI_WLAST(%s_wlast),\n" "\t\t//\n" "\t\t.S_AXI_BVALID(%s_bvalid), .S_AXI_BREADY(%s_bready),\n" "\t\t\t.S_AXI_BID(%s_bid), .S_AXI_BRESP(%s_bresp),\n" "\t\t//\n" "\t\t.S_AXI_ARVALID(%s_arvalid), .S_AXI_ARREADY(%s_arready),\n" "\t\t\t.S_AXI_ARLEN(%s_arlen), .S_AXI_ARID(%s_awid),\n" "\t\t//\n" "\t\t.S_AXI_RVALID(%s_rvalid), .S_AXI_RREADY(%s_rready),\n" "\t\t\t.S_AXI_RID(%s_rid), .S_AXI_RDATA(%s_rdata),\n" "\t\t\t.S_AXI_RLAST(%s_rlast), .S_AXI_RRESP(%s_rresp)\n" "\t);\n\n", mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp); } return; // }}} } else if (NULL == m_mlist || m_mlist->size() == 0) { // No masters // {{{ for(unsigned p=0; p < m_info->m_plist->size(); p++) { STRINGP pstr = (*m_info->m_plist)[p]->bus_prefix(); fprintf(fp, "\t//\n" "\t// The %s bus has no masters assigned to it\n" "\t//\n" "\tassign %s_awvalid = 1\'b0;\n" "\tassign %s_awid = 0;\n" "\tassign %s_awaddr = 0;\n" "\tassign %s_awlen = 8\'h00;\n" "\tassign %s_awsize = 3\'b000;\n" "\tassign %s_awburst = 2\'b00;\n" "\tassign %s_awlock = 1\'b0;\n" "\tassign %s_awcache = 4\'h0;\n" "\tassign %s_awprot = 3\'h0;\n" "\tassign %s_awqos = 4\'h0;\n" "\t//\n", pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str()); fprintf(fp, "\tassign %s_wvalid = 1\'b0;\n" "\tassign %s_wdata = 0;\n" "\tassign %s_wstrb = 0;\n" "\tassign %s_wlast = 1\'b1;\n" "\t//\n", pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str()); fprintf(fp, "\tassign %s_bready = 1\'b0;\n", pstr->c_str()); fprintf(fp, "\t//\n" "\tassign %s_arvalid = 1\'b0;\n" "\tassign %s_arid = 0;\n" "\tassign %s_araddr = 0;\n" "\tassign %s_arlen = 8\'h00;\n" "\tassign %s_arsize = 3\'b000;\n" "\tassign %s_arburst = 2\'b00;\n" "\tassign %s_arlock = 1\'b0;\n" "\tassign %s_arcache = 4\'h0;\n" "\tassign %s_arprot = 3\'h0;\n" "\tassign %s_arqos = 4\'h0;\n" "\t//\n", pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str()); fprintf(fp, "\tassign %s_rready = 1\'b1;\n", pstr->c_str()); fprintf(fp, "\t//\n" "\t//\n" "\twire %s_unused;\n" "\tassign %s_unused = &{ 1\'b0, %s_awready, %s_wready,\n" "\t\t%s_bvalid, %s_bid, %s_bresp,\n" "\t\t%s_arready,\n" "\t\t%s_rvalid, %s_rid, %s_rdata,\n" "\t\t\t%s_rlast, %s_rresp\n" "\t\t};\n", pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str() ); } return; // }}} } else if ((m_info->m_plist->size() == 1)&&(m_mlist && m_mlist->size() == 1)) { // {{{ // Only one master connected to only one slave--skip all the // extra connection logic. // // Can only simplify if there's only one peripheral and only // one master // STRINGP slv = (*m_info->m_plist)[0]->bus_prefix(); STRINGP mstr = (*m_mlist)[0]->bus_prefix(); const char *sp = slv->c_str(), *mp = mstr->c_str(); fprintf(fp, "\t//\n" "\t// Bus %s has only one master (%s) and one slave (%s)\n" "\t// connected to it -- skipping the interconnect\n" "\t//\n", n->c_str(), master_name(0)->c_str(), sp); fprintf(fp, "\tassign %s_awvalid = %s_awvalid;\n" "\tassign %s_awready = %s_awready;\n" "\tassign %s_awid = %s_awid;\n" "\tassign %s_awaddr = %s_awaddr;\n" "\tassign %s_awlen = %s_awlen;\n" "\tassign %s_awsize = %s_awsize;\n" "\tassign %s_awburst = %s_awburst;\n" "\tassign %s_awlock = %s_awlock;\n" "\tassign %s_awcache = %s_awcache;\n" "\tassign %s_awprot = %s_awprot;\n" "\tassign %s_awqos = %s_awqos;\n" "\t//\n", sp, mp, mp, sp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp); fprintf(fp, "\tassign %s_wvalid = %s_wvalid;\n" "\tassign %s_wready = %s_wready;\n" "\tassign %s_wdata = %s_wdata;\n" "\tassign %s_wstrb = %s_wstrb;\n" "\tassign %s_wlast = %s_wlast;\n" "\t//\n", sp, mp, mp, sp, sp, mp, sp, mp, sp, mp); fprintf(fp, "\tassign %s_bvalid = %s_bvalid;\n" "\tassign %s_bready = %s_bready;\n" "\tassign %s_bid = %s_bid;\n" "\tassign %s_bresp = %s_bresp;\n", mp, sp, sp, mp, mp, sp, mp, sp); fprintf(fp, "\t//\n" "\t//\n" "\tassign %s_arvalid = %s_arvalid;\n" "\tassign %s_arready = %s_arready;\n" "\tassign %s_arid = %s_arid;\n" "\tassign %s_araddr = %s_araddr;\n" "\tassign %s_arlen = %s_arlen;\n" "\tassign %s_arsize = %s_arsize;\n" "\tassign %s_arburst = %s_arburst;\n" "\tassign %s_arlock = %s_arlock;\n" "\tassign %s_arcache = %s_arcache;\n" "\tassign %s_arprot = %s_arprot;\n" "\tassign %s_arqos = %s_arqos;\n" "\t//\n", sp, mp, mp, sp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp, sp, mp); fprintf(fp, "\tassign %s_rvalid = %s_rvalid;\n" "\tassign %s_rready = %s_rready;\n" "\tassign %s_rid = %s_rid;\n" "\tassign %s_rdata = %s_rdata;\n" "\tassign %s_rlast = %s_rlast;\n" "\tassign %s_rresp = %s_rresp;\n\n", mp, sp, sp, mp, mp, sp, mp, sp, mp, sp, mp, sp); return; // }}} } // Start with the slist if (m_is_single || m_slist) { // {{{ assert(1 == m_info->m_mlist->size()); PLIST *slist = (m_is_single) ? m_info->m_plist : m_slist; const char *np = n->c_str(); STRING s = STRING(*(*m_mlist)[0]->bus_prefix()); int aw = nextlg(slist->size())+nextlg(m_info->data_width())-3; gbl_msg.error("AXI-Single logic hasn\'t yet been implemented\n"); fprintf(fp, "\t// (AXI-Single isn\'t yet written)\n" "\taxisingle #(\n" "\t\t// {{{\n" "\t\t// .C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d),\n" "\t\t.NS(%ld)", aw, m_info->data_width(), slist->size()); xbar_option(fp, KY_OPT_LOWPOWER, ",\n\t\t.OPT_LOWPOWER(%)", "1\'b1"); fprintf(fp, "\n\t\t// }}}\n" "\t) %s_axisingle(\n", np); fprintf(fp, "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s),\n" "\t\t.S_AXI_ARESETN(%s),\n", c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t// Connect our SIO slave wires to axisingle\n" "\t\t// {{{\n"); fprintf(fp, "\t\t.S_AXI_AWVALID(%s_awvalid),\n" "\t\t.S_AXI_AWREADY(%s_awready),\n" "\t\t.S_AXI_AWID( %s_awid),\n" "\t\t.S_AXI_AWADDR( %s_awaddr[%d:0]),\n" "\t\t.S_AXI_AWLEN( %s_awlen),\n" "\t\t.S_AXI_AWSIZE( %s_awsize),\n" "\t\t.S_AXI_AWBURST(%s_awburst),\n" "\t\t.S_AXI_AWLOCK( %s_awlock),\n" "\t\t.S_AXI_AWCACHE(%s_awcache),\n" "\t\t.S_AXI_AWPROT( %s_awprot),\n" "\t\t.S_AXI_AWQOS( %s_awqos),\n" "\t\t//\n" "\t\t.S_AXI_WVALID( %s_wvalid),\n" "\t\t.S_AXI_WREADY( %s_wready),\n" "\t\t.S_AXI_WDATA( %s_wdata),\n" "\t\t.S_AXI_WSTRB( %s_wstrb),\n" "\t\t.S_AXI_WLAST( %s_wlast),\n" "\t\t//\n" "\t\t.S_AXI_BVALID( %s_bvalid),\n" "\t\t.S_AXI_BREADY( %s_bready),\n" "\t\t.S_AXI_BID( %s_bid),\n" "\t\t.S_AXI_BRESP( %s_bresp),\n" "\t\t//\n", s.c_str(), s.c_str(), s.c_str(), s.c_str(), aw-1, s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), // s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), // s.c_str(), s.c_str(), s.c_str(), s.c_str()); fprintf(fp, "\t\t// Read connections\n" "\t\t.S_AXI_ARVALID(%s_arvalid),\n" "\t\t.S_AXI_ARREADY(%s_arready),\n" "\t\t.S_AXI_ARID( %s_arid),\n" "\t\t.S_AXI_ARADDR( %s_araddr[%d:0]),\n" "\t\t.S_AXI_ARLEN( %s_arlen),\n" "\t\t.S_AXI_ARSIZE( %s_arsize),\n" "\t\t.S_AXI_ARBURST(%s_arburst),\n" "\t\t.S_AXI_ARLOCK( %s_arlock),\n" "\t\t.S_AXI_ARCACHE(%s_arcache),\n" "\t\t.S_AXI_ARPROT( %s_arprot),\n" "\t\t.S_AXI_ARQOS( %s_arqos),\n" "\t\t//\n" "\t\t.S_AXI_RVALID( %s_rvalid),\n" "\t\t.S_AXI_RREADY( %s_rready),\n" "\t\t.S_AXI_RID( %s_rid),\n" "\t\t.S_AXI_RDATA( %s_rdata),\n" "\t\t.S_AXI_RLAST( %s_rlast),\n" "\t\t.S_AXI_RRESP( %s_rresp),\n" "\t\t// }}}\n" "\t\t// Connections to varous AXI (SINGLE) slaves\n" "\t\t// {{{\n", s.c_str(), s.c_str(), s.c_str(), s.c_str(), aw-1, s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), // s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str()); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","AWVALID"); fprintf(fp, "\t\t.M_AXI_AWPROT(%s_siow_awprot),\n" "\t\t.M_AXI_WDATA( %s_siow_wdata),\n" "\t\t.M_AXI_WSTRB( %s_siow_wstrb),\n", n->c_str(), n->c_str(), n->c_str()); fprintf(fp, "\t\t//\n" "\t\t//\n"); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","BRESP"); fprintf(fp, "\t\t// Read connections\n"); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","ARVALID"); fprintf(fp, "\t\t.M_AXI_ARPROT(%s_siow_arprot),\n" "\t\t//\n", n->c_str()); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","RDATA"); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","RRESP", false); fprintf(fp, "\t\t// }}}\n" "\t\t// }}}\n" "\t);\n\n"); fprintf(fp,"\t//\n\t// Now connecting the extra slaves wires " "to the AXISINGLE controller\n" "\t// {{{\n"); for(int k=slist->size(); k>0; k--) { PERIPHP p = (*slist)[k-1]; const char *pn = p->p_name->c_str(), *ns = n->c_str(); fprintf(fp, "\t// %s\n", pn); pn = p->bus_prefix()->c_str(); fprintf(fp, "\tassign %s_awaddr = 0;\n", pn); fprintf(fp, "\tassign %s_awprot = %s_siow_awprot;\n", pn, ns); fprintf(fp, "\tassign %s_wvalid = %s_awvalid;\n", pn, pn); fprintf(fp, "\tassign %s_wdata = %s_siow_wdata;\n", pn, ns); fprintf(fp, "\tassign %s_wstrb = %s_siow_wstrb;\n", pn, ns); fprintf(fp, "\tassign %s_bready = 1\'b1;\n", pn); fprintf(fp, "\tassign %s_araddr = 0;\n", pn); fprintf(fp, "\tassign %s_arprot = %s_siow_arprot;\n", pn, ns); fprintf(fp, "\tassign %s_rready = 1\'b1;\n", pn); } fprintf(fp, "\t// }}}\n"); // }}} return; // }}} } else if (!m_slist) fprintf(fp, "\t//\n\t// No class SINGLE peripherals on the \"%s\" bus\n\t//\n\n", n->c_str()); // Then the dlist if (m_is_double || m_dlist) { // {{{ if (m_dlist) pl = m_dlist; else pl = m_info->m_plist; STRING s = STRING(*(*m_mlist)[0]->bus_prefix()); int aw = address_width(); if (!m_is_double) s = (*n) + "_dio"; fprintf(fp, "\t//\n" "\t// %s Bus logic to handle %ld DOUBLE slaves\n" "\t//\n" "\t//\n", n->c_str(), pl->size()); fprintf(fp, "\t// Some extra wires to capture combined values--values\n" "\t// that will be the same across all slaves of the\n" "\t// class\n" "\twire [0:0]\t%s_diow_awid;\n" "\twire [%d:0]\t%s_diow_awaddr;\n" "\twire [7:0]\t%s_diow_awlen;\n" "\twire [2:0]\t%s_diow_awsize;\n" "\twire [1:0]\t%s_diow_awburst;\n" "\twire\t%s_diow_awlock;\n" "\twire [3:0]\t%s_diow_awcache;\n" "\twire [2:0]\t%s_diow_awprot;\n" "\twire [3:0]\t%s_diow_awqos;\n" "\t//\n", n->c_str(), address_width()-1, n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str()); fprintf(fp, "\twire [%d:0]\t%s_diow_wdata;\n" "\twire [%d:0]\t%s_diow_wstrb;\n" "\twire\t%s_diow_wlast;\n" "\t//\n" "\twire\t%s_diow_bready;\n" "\t//\n", m_info->data_width()-1, n->c_str(), m_info->data_width()/8-1, n->c_str(), n->c_str(), n->c_str()); fprintf(fp, "\twire [0:0]\t%s_diow_arid;\n" "\twire [%d:0]\t%s_diow_araddr;\n" "\twire [7:0]\t%s_diow_arlen;\n" "\twire [2:0]\t%s_diow_arsize;\n" "\twire [1:0]\t%s_diow_arburst;\n\n" "\twire\t%s_diow_arlock;\n" "\twire [3:0]\t%s_diow_arcache;\n" "\twire [2:0]\t%s_diow_arprot;\n" "\twire [3:0]\t%s_diow_arqos;\n" "\t//\n" "\twire\t%s_diow_rready;\n" "\t//\n", n->c_str(), address_width()-1, n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str()); fprintf(fp, "\taxidouble #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d),\n" "\t\t.C_AXI_ID_WIDTH(%d),\n" "\t\t.NS(%ld),\n", address_width(), m_info->data_width(), id_width(), pl->size()); xbar_option(fp, KY_OPT_LOWPOWER, "\t\t.OPT_LOWPOWER(%),\n", "1\'b1"); slave_addr(fp, pl); fprintf(fp, ",\n"); slave_mask(fp, pl); fprintf(fp, "\n"); fprintf(fp, "\t\t// }}}\n" "\t) %s_axidouble(\n", n->c_str()); fprintf(fp, "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s),\n" "\t\t.S_AXI_ARESETN(%s),\n", c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t//\n"); fprintf(fp, "\t\t// Slave port\n" "\t\t// {{{\n" "\t\t.S_AXI_AWVALID(%s_awvalid),\n" "\t\t.S_AXI_AWREADY(%s_awready),\n" "\t\t.S_AXI_AWID( %s_awid),\n" "\t\t.S_AXI_AWADDR( %s_awaddr[%d:0]),\n" "\t\t.S_AXI_AWLEN( %s_awlen),\n" "\t\t.S_AXI_AWSIZE( %s_awsize),\n" "\t\t.S_AXI_AWBURST(%s_awburst),\n" "\t\t.S_AXI_AWLOCK( %s_awlock),\n" "\t\t.S_AXI_AWCACHE(%s_awcache),\n" "\t\t.S_AXI_AWPROT( %s_awprot),\n" "\t\t.S_AXI_AWQOS( %s_awqos),\n" "\t\t//\n" "\t\t.S_AXI_WVALID( %s_wvalid),\n" "\t\t.S_AXI_WREADY( %s_wready),\n" "\t\t.S_AXI_WDATA( %s_wdata),\n" "\t\t.S_AXI_WSTRB( %s_wstrb),\n" "\t\t.S_AXI_WLAST( %s_wlast),\n" "\t\t//\n" "\t\t.S_AXI_BVALID( %s_bvalid),\n" "\t\t.S_AXI_BREADY( %s_bready),\n" "\t\t.S_AXI_BID( %s_bid),\n" "\t\t.S_AXI_BRESP( %s_bresp),\n" "\t\t//\n", // AW s.c_str(), s.c_str(), s.c_str(), s.c_str(), aw-1, s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), // W s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), // B s.c_str(), s.c_str(), s.c_str(), s.c_str()); fprintf(fp, "\t\t// Read connections\n" "\t\t.S_AXI_ARVALID(%s_arvalid),\n" "\t\t.S_AXI_ARREADY(%s_arready),\n" "\t\t.S_AXI_ARID( %s_arid),\n" "\t\t.S_AXI_ARADDR( %s_araddr[%d:0]),\n" "\t\t.S_AXI_ARLEN( %s_arlen),\n" "\t\t.S_AXI_ARSIZE( %s_arsize),\n" "\t\t.S_AXI_ARBURST(%s_arburst),\n" "\t\t.S_AXI_ARLOCK( %s_arlock),\n" "\t\t.S_AXI_ARCACHE(%s_arcache),\n" "\t\t.S_AXI_ARPROT( %s_arprot),\n" "\t\t.S_AXI_ARQOS( %s_arqos),\n" "\t\t//\n" "\t\t.S_AXI_RVALID( %s_rvalid),\n" "\t\t.S_AXI_RREADY( %s_rready),\n" "\t\t.S_AXI_RID( %s_rid),\n" "\t\t.S_AXI_RDATA( %s_rdata),\n" "\t\t.S_AXI_RLAST( %s_rlast),\n" "\t\t.S_AXI_RRESP( %s_rresp),\n" "\t\t// }}}\n" "\t\t// Connections to slaves\n" "\t\t// {{{\n", // AR s.c_str(), s.c_str(), s.c_str(), s.c_str(), aw-1, s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), // R s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str()); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWVALID"); fprintf(fp, "\t\t.M_AXI_AWID( %s_diow_awid), // == 1\'b0\n" "\t\t.M_AXI_AWADDR( %s_diow_awaddr),\n" "\t\t.M_AXI_AWLEN( %s_diow_awlen), // == 0\n" "\t\t.M_AXI_AWSIZE( %s_diow_awsize),\n" "\t\t.M_AXI_AWBURST(%s_diow_awburst), // ==INC==2\'b01\n" "\t\t.M_AXI_AWLOCK( %s_diow_awlock), // == 0\n" "\t\t.M_AXI_AWCACHE(%s_diow_awcache),\n" "\t\t.M_AXI_AWPROT( %s_diow_awprot),\n" "\t\t.M_AXI_AWQOS( %s_diow_awqos),\n", n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str()); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WVALID"); fprintf(fp, "\t\t.M_AXI_WDATA( %s_diow_wdata),\n" "\t\t.M_AXI_WSTRB( %s_diow_wstrb),\n" "\t\t.M_AXI_WLAST( %s_diow_wlast), // == 1\n", n->c_str(), n->c_str(), n->c_str()); fprintf(fp, "\t\t//\n"); fprintf(fp, "\t\t//\n"); fprintf(fp, "\t\t.M_AXI_BREADY( %s_diow_bready),\n", n->c_str()); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","BRESP"); fprintf(fp, "\t\t// Read connections\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARVALID"); fprintf(fp, "\t\t.M_AXI_ARID( %s_diow_arid), // == 1\'b0\n" "\t\t.M_AXI_ARADDR( %s_diow_araddr),\n" "\t\t.M_AXI_ARLEN( %s_diow_arlen), // == 0\n" "\t\t.M_AXI_ARSIZE( %s_diow_arsize),\n" "\t\t.M_AXI_ARBURST(%s_diow_arburst),//==INC==2\'b01\n" "\t\t.M_AXI_ARLOCK( %s_diow_arlock),// == 0\n" "\t\t.M_AXI_ARCACHE(%s_diow_arcache),//== 0\n" "\t\t.M_AXI_ARPROT( %s_diow_arprot),\n" "\t\t.M_AXI_ARQOS( %s_diow_arqos), //== 0\n" "\t\t//\n", n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str()); // Read returns fprintf(fp, "\t\t.M_AXI_RREADY( %s_diow_rready),\n", n->c_str()); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RDATA"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RRESP", false); fprintf(fp, "\t\t// }}}\n" "\t\t// }}}\n" "\t);\n\n"); fprintf(fp,"\t//\n\t// Now connecting the extra slaves wires " "to the AXIDOUBLE controller\n\t//\n"); for(int k=pl->size(); k>0; k--) { PERIPHP p = (*pl)[k-1]; const char *pn = p->p_name->c_str(), *pfx = p->bus_prefix()->c_str(); int // aw = p->p_awid + unused_lsbs, iw = id_width(); fprintf(fp, "\t// %s\n" "\t// {{{\n", pn); fprintf(fp, "\tassign %s_awid = {(%d){1\'b0}};\n", pfx, iw); fprintf(fp, "\tassign %s_awaddr = %s_diow_awaddr;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_awlen = %s_diow_awlen;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_awsize = %s_diow_awsize;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_awburst= %s_diow_awburst;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_awlock = %s_diow_awlock;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_awcache= %s_diow_awcache;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_awprot = %s_diow_awprot;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_awqos = %s_diow_awqos;\n", pfx, n->c_str()); // fprintf(fp, "\tassign %s_wdata = %s_diow_wdata;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_wstrb = %s_diow_wstrb;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_wlast = %s_diow_wlast;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_bready = 1\'b1;\n", pfx); // arready is set by the slave ... and ignored fprintf(fp, "\tassign %s_arid = {(%d){1\'b0}};\n", pfx, iw); fprintf(fp, "\tassign %s_araddr = %s_diow_araddr;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arlen = %s_diow_arlen;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arsize = %s_diow_arsize;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arburst= %s_diow_arburst;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arlock = %s_diow_arlock;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arcache= %s_diow_arcache;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arprot = %s_diow_arprot;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arqos = %s_diow_arqos;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arprot = %s_diow_arprot;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arprot = %s_diow_arprot;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_rready = 1\'b1;\n" "\t// }}}\n", pfx); } if (m_is_double) return; // }}} } else if (!m_dlist) fprintf(fp, "\t//\n\t// No class DOUBLE peripherals on the \"%s\" bus\n\t//\n\n", n->c_str()); // // // Now for the main set of slaves // // pl = m_info->m_plist; unsigned slave_name_width = 4; // Find the maximum width of any slaves name, for our comment tables // below for(unsigned k=0; km_plist->size(); k++) { PERIPHP p = (*m_info->m_plist)[k]; unsigned sz; sz = p->name()->size(); if (slave_name_width < sz) slave_name_width = sz; } // // Now create the crossbar interconnect // fprintf(fp, "\t////////////////////////////////////////////////////////////////////////\n" "\t//\n" "\t// Connect the %s bus components together using the axixbar()\n" "\t// {{{\n" "\t//\n", n->c_str()); fprintf(fp, "\taxixbar #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d),\n" "\t\t.C_AXI_ID_WIDTH(%d),\n" "\t\t.NM(%ld), .NS(%ld),\n", address_width(), m_info->data_width(), id_width(), m_mlist->size(), m_info->m_plist->size()); /* fprintf(fp, "\t\t.READ_ACCESS(%ld\'b", m_info->m_plist->size()); for(unsigned k=0; km_plist->size(); k++) { PERIPHP p = (*m_info->m_plist)[k]; if (p->write_only()) { putc('0', fp); if (p->read_only()) gbl_msg.error("Slave %s cannot be both write-only and read-only\n", p->name()->c_str()); } else putc('1', fp); } fprintf(fp, "),\n\t\t.WRITE_ACCESS(%ld\'b", m_info->m_plist->size()); for(unsigned k=0; km_plist->size(); k++) { PERIPHP p = (*m_info->m_plist)[k]; if (p->write_only()) putc('0', fp); else putc('1', fp); } fprintf(fp, "),\n"); */ slave_addr(fp, m_info->m_plist); fprintf(fp, ",\n"); slave_mask(fp, m_info->m_plist); xbar_option(fp, KY_OPT_LOWPOWER, ",\n\t\t.OPT_LOWPOWER(%)", "1\'b1"); xbar_option(fp, KY_OPT_LINGER, ",\n\t\t.OPT_LINGER(%)"); xbar_option(fp, KY_OPT_LGMAXBURST,",\n\t\t.LGMAXBURST(%)"); // fprintf(fp, "\n\t\t// }}}\n" "\t) %s_xbar(\n" "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s),\n", n->c_str(), m_info->m_clock->m_wire->c_str()); fprintf(fp, "\t\t.S_AXI_ARESETN(%s),\n", rst->c_str()); fprintf(fp, "\t\t// Connections from masters\n" "\t\t// {{{\n"); xbarcon_master(fp, "\t\t",".S_AXI_","AWVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","AWREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","AWID"); xbarcon_master(fp, "\t\t",".S_AXI_","AWADDR"); xbarcon_master(fp, "\t\t",".S_AXI_","AWLEN"); xbarcon_master(fp, "\t\t",".S_AXI_","AWSIZE"); xbarcon_master(fp, "\t\t",".S_AXI_","AWBURST"); xbarcon_master(fp, "\t\t",".S_AXI_","AWLOCK"); xbarcon_master(fp, "\t\t",".S_AXI_","AWCACHE"); xbarcon_master(fp, "\t\t",".S_AXI_","AWPROT"); xbarcon_master(fp, "\t\t",".S_AXI_","AWQOS"); fprintf(fp, "\t\t//\n"); xbarcon_master(fp, "\t\t",".S_AXI_","WVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","WREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","WDATA"); xbarcon_master(fp, "\t\t",".S_AXI_","WSTRB"); xbarcon_master(fp, "\t\t",".S_AXI_","WLAST"); fprintf(fp, "\t\t//\n"); xbarcon_master(fp, "\t\t",".S_AXI_","BVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","BREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","BID"); xbarcon_master(fp, "\t\t",".S_AXI_","BRESP"); fprintf(fp, "\t\t//\n"); fprintf(fp, "\t\t// Read connections\n"); xbarcon_master(fp, "\t\t",".S_AXI_","ARVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","ARREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","ARID"); xbarcon_master(fp, "\t\t",".S_AXI_","ARADDR"); xbarcon_master(fp, "\t\t",".S_AXI_","ARLEN"); xbarcon_master(fp, "\t\t",".S_AXI_","ARSIZE"); xbarcon_master(fp, "\t\t",".S_AXI_","ARBURST"); xbarcon_master(fp, "\t\t",".S_AXI_","ARLOCK"); xbarcon_master(fp, "\t\t",".S_AXI_","ARCACHE"); xbarcon_master(fp, "\t\t",".S_AXI_","ARPROT"); xbarcon_master(fp, "\t\t",".S_AXI_","ARQOS"); fprintf(fp, "\t\t//\n"); xbarcon_master(fp, "\t\t",".S_AXI_","RVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","RREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","RID"); xbarcon_master(fp, "\t\t",".S_AXI_","RDATA"); xbarcon_master(fp, "\t\t",".S_AXI_","RLAST"); xbarcon_master(fp, "\t\t",".S_AXI_","RRESP"); fprintf(fp, "\t\t// }}}\n"); fprintf(fp, "\t\t// Connections to slaves\n"); fprintf(fp, "\t\t// {{{\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWADDR"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWLEN"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWSIZE"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWBURST"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWLOCK"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWCACHE"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWPROT"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWQOS"); fprintf(fp, "\t\t//\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WDATA"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WSTRB"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WLAST"); fprintf(fp, "\t\t//\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","BVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","BREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","BID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","BRESP"); fprintf(fp, "\t\t//\n"); fprintf(fp, "\t\t// Read connections\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARADDR"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARLEN"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARSIZE"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARBURST"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARLOCK"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARCACHE"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARPROT"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARQOS"); fprintf(fp, "\t\t//\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RDATA"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RLAST"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RRESP", false); fprintf(fp, "\t\t// }}}\n" "\t\t// }}}\n\t);\n\n"); for(unsigned k=0; k < m_info->m_plist->size(); k++) { // Handle read only or write only slaves // {{{ PERIPHP p = (*m_info->m_plist)[k]; STRINGP busp = p->bus_prefix(); const char *bp = busp->c_str(); if (p->write_only()) { fprintf(fp, "\taxiempty #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d),\n" "\t\t.C_AXI_ID_WIDTH(%d)\n" "\t\t// }}}\n", address_width(), m_info->data_width(), id_width()); fprintf(fp, "\t) %s_no_slavep (\n" "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s), .S_AXI_ARESETN(%s),\n" "\t\t//\n", bp, c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t// Verilator lint_off PINCONNECTEMPTY\n" "\t\t.S_AXI_AWVALID(1\'b0), .S_AXI_AWREADY(),\n" "\t\t.S_AXI_WVALID(1\'b0), .S_AXI_WREADY(),\n" "\t\t.S_AXI_WLAST(1\'b0),\n" "\t\t//\n" "\t\t.S_AXI_BVALID(), .S_AXI_BREADY(1\'b1),\n" "\t\t.S_AXI_BID(), .S_AXI_BRESP(),\n" "\t\t// Verilator lint_on PINCONNECTEMPTY\n" "\t\t//\n" "\t\t.S_AXI_ARVALID(%s_arvalid), .S_AXI_ARREADY(%s_arready),\n" "\t\t.S_AXI_ARID(%s_arid), .S_AXI_ARLEN(%s_arlen),\n" "\t\t.S_AXI_RVALID(%s_rvalid), .S_AXI_RREADY(%s_rready),\n" "\t\t.S_AXI_RDATA(%s_rdata), .S_AXI_RLAST(%s_rlast),\n" "\t\t.S_AXI_RRESP(%s_rresp)\n" "\t\t// }}}\n" "\t);\n\n", // AW, W, B // bp, bp, bp, bp, bp, bp, bp, bp, bp); } if (p->read_only()) { fprintf(fp, "\taxiempty #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d),\n" "\t\t.C_AXI_ID_WIDTH(%d)\n" "\t\t// }}}\n", address_width(), m_info->data_width(), id_width()); fprintf(fp, "\t) %s_no_slavep (\n" "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s), .S_AXI_ARESETN(%s),\n" "\t\t//\n", bp, c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t.S_AXI_AWVALID(%s_awvalid), .S_AXI_AWREADY(%s_awready),\n" "\t\t\t.S_AXI_AWID(%s_awid),\n" "\t\t.S_AXI_WVALID(%s_wvalid), .S_AXI_WREADY(%s_wready),\n" "\t\t.S_AXI_WLAST(%s_wlast),\n" "\t\t//\n" "\t\t.S_AXI_BVALID(%s_bvalid), .S_AXI_BREADY(%s_bready),\n" "\t\t.S_AXI_BID(%s_bid), .S_AXI_BRESP(%s_bresp),\n" "\t\t//\n" "\t\t// Verilator lint_off PINCONNECTEMPTY\n" "\t\t.S_AXI_ARVALID(1\'b0), .S_AXI_ARREADY(),\n" "\t\t.S_AXI_ARID(0), .S_AXI_ARLEN(8'h00),\n" "\t\t//\n" "\t\t.S_AXI_RVALID(), .S_AXI_RREADY(1\'b1),\n" "\t\t.S_AXI_RDATA(), .S_AXI_RLAST(),\n" "\t\t.S_AXI_RRESP()\n" "\t\t// Verilator lint_on PINCONNECTEMPTY\n" "\t\t// }}}\n" "\t);\n\n", // AW, W bp, bp, bp, bp, bp, bp, // B bp, bp, bp, bp); } // }}} } fprintf(fp, "\t\t// }}}\n"); } STRINGP AXIBUS::master_portlist(BMASTERP m) { // {{{ STRING str; if (m->write_only()) str = str + STRING("// Master is write-only\n"); if (m->read_only()) str = str + STRING("// Master is read only\n\t\t"); else str = str + STRING( "@$(MASTER.PREFIX)_awvalid,\n" "\t\t@$(MASTER.PREFIX)_awready,\n" "\t\t@$(MASTER.PREFIX)_awid,\n" "\t\t@$(MASTER.PREFIX)_awaddr[@$(MASTER.BUS.AWID)-1:0],\n" "\t\t@$(MASTER.PREFIX)_awlen,\n" "\t\t@$(MASTER.PREFIX)_awsize,\n" "\t\t@$(MASTER.PREFIX)_awburst,\n" "\t\t@$(MASTER.PREFIX)_awlock,\n" "\t\t@$(MASTER.PREFIX)_awcache,\n" "\t\t@$(MASTER.PREFIX)_awprot,\n" "\t\t@$(MASTER.PREFIX)_awqos,\n" "\t\t//\n" "\t\t@$(MASTER.PREFIX)_wvalid,\n" "\t\t@$(MASTER.PREFIX)_wready,\n" "\t\t@$(MASTER.PREFIX)_wdata,\n" "\t\t@$(MASTER.PREFIX)_wstrb,\n" "\t\t@$(MASTER.PREFIX)_wlast,\n" "\t\t//\n" "\t\t@$(MASTER.PREFIX)_bvalid,\n" "\t\t@$(MASTER.PREFIX)_bready,\n" "\t\t@$(MASTER.PREFIX)_bid,\n" "\t\t@$(MASTER.PREFIX)_bresp"); if (!m->read_only() && !m->write_only()) str = str + STRING(",\n\t\t// Read connections\n\t\t"); if (!m->write_only()) str = str + STRING( "@$(MASTER.PREFIX)_arvalid,\n" "\t\t@$(MASTER.PREFIX)_arready,\n" "\t\t@$(MASTER.PREFIX)_arid,\n" "\t\t@$(MASTER.PREFIX)_araddr[@$(MASTER.BUS.AWID)-1:0],\n" "\t\t@$(MASTER.PREFIX)_arlen,\n" "\t\t@$(MASTER.PREFIX)_arsize,\n" "\t\t@$(MASTER.PREFIX)_arburst,\n" "\t\t@$(MASTER.PREFIX)_arlock,\n" "\t\t@$(MASTER.PREFIX)_arcache,\n" "\t\t@$(MASTER.PREFIX)_arprot,\n" "\t\t@$(MASTER.PREFIX)_arqos,\n" "\t\t//\n" "\t\t@$(MASTER.PREFIX)_rvalid,\n" "\t\t@$(MASTER.PREFIX)_rready,\n" "\t\t@$(MASTER.PREFIX)_rid,\n" "\t\t@$(MASTER.PREFIX)_rdata,\n" "\t\t@$(MASTER.PREFIX)_rlast,\n" "\t\t@$(MASTER.PREFIX)_rresp"); return new STRING(str); } // }}} STRINGP AXIBUS::iansi(BMASTERP m) { return new STRING(""); } STRINGP AXIBUS::oansi(BMASTERP m) { return new STRING(""); } STRINGP AXIBUS::master_ansprefix(BMASTERP m) { return new STRING("M_AXI_"); } STRINGP AXIBUS::master_ansi_portlist(BMASTERP m) { // {{{ STRING str; if (!m->read_only()) str = str + STRING( ".@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWVALID(@$(MASTER.PREFIX)_awvalid),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)AWREADY(@$(MASTER.PREFIX)_awready),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWID( @$(MASTER.PREFIX)_awid),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWADDR( @$(MASTER.PREFIX)_awaddr[@$(MASTER.BUS.AWID)-1:0]),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWLEN( @$(MASTER.PREFIX)_awlen),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWSIZE( @$(MASTER.PREFIX)_awsize),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWBURST(@$(MASTER.PREFIX)_awburst),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWLOCK( @$(MASTER.PREFIX)_awlock),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWCACHE(@$(MASTER.PREFIX)_awcache),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWPROT( @$(MASTER.PREFIX)_awprot),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWQOS( @$(MASTER.PREFIX)_awqos),\n" "\t\t//\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)WVALID(@$(MASTER.PREFIX)_wvalid),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)WREADY(@$(MASTER.PREFIX)_wready),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)WDATA( @$(MASTER.PREFIX)_wdata),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)WSTRB( @$(MASTER.PREFIX)_wstrb),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)WLAST( @$(MASTER.PREFIX)_wlast),\n" "\t\t//\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)BVALID(@$(MASTER.PREFIX)_bvalid),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)BREADY(@$(MASTER.PREFIX)_bready),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)BID( @$(MASTER.PREFIX)_bid),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)BRESP( @$(MASTER.PREFIX)_bresp)"); if (!m->read_only() && !m->write_only()) str = str + STRING(",\n\t\t// Read connections\n\t\t"); if (!m->write_only()) str = str + STRING( ".@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARVALID(@$(MASTER.PREFIX)_arvalid),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)ARREADY(@$(MASTER.PREFIX)_arready),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARID( @$(MASTER.PREFIX)_arid),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARADDR( @$(MASTER.PREFIX)_araddr[@$(MASTER.BUS.AWID)-1:0]),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARLEN( @$(MASTER.PREFIX)_arlen),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARSIZE( @$(MASTER.PREFIX)_arsize),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARBURST(@$(MASTER.PREFIX)_arburst),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARLOCK( @$(MASTER.PREFIX)_arlock),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARCACHE(@$(MASTER.PREFIX)_arcache),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARPROT( @$(MASTER.PREFIX)_arprot),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARQOS( @$(MASTER.PREFIX)_arqos),\n" "//\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)RVALID(@$(MASTER.PREFIX)_rvalid),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)RREADY(@$(MASTER.PREFIX)_rready),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)RID( @$(MASTER.PREFIX)_rid),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)RDATA( @$(MASTER.PREFIX)_rdata),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)RLAST( @$(MASTER.PREFIX)_rlast),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)RRESP( @$(MASTER.PREFIX)_rresp)"); return new STRING(str); } // }}} STRINGP AXIBUS::slave_ansprefix(PERIPHP p) { return new STRING("S_AXI_"); } STRINGP AXIBUS::slave_portlist(PERIPHP p) { // {{{ STRING str; if (p->write_only()) str = str + STRING("// Slave is write-only\n\t\t"); if (p->read_only()) str = str + STRING("// Slave is read only\n\t\t"); else { str = str + STRING( "//\n" "\t\t@$(SLAVE.PREFIX)_awvalid,\n" "\t\t@$(SLAVE.PREFIX)_awready,\n" "\t\t@$(SLAVE.PREFIX)_awid,\n" "\t\t@$(SLAVE.PREFIX)_awaddr[") + std::to_string(p->get_slave_address_width()) + STRING("-1:0],\n" "\t\t@$(SLAVE.PREFIX)_awlen,\n" "\t\t@$(SLAVE.PREFIX)_awsize,\n" "\t\t@$(SLAVE.PREFIX)_awburst,\n" "\t\t@$(SLAVE.PREFIX)_awlock,\n" "\t\t@$(SLAVE.PREFIX)_awcache,\n" "\t\t@$(SLAVE.PREFIX)_awprot,\n" "\t\t@$(SLAVE.PREFIX)_awqos,\n" "//\n" "\t\t@$(SLAVE.PREFIX)_wvalid,\n" "\t\t@$(SLAVE.PREFIX)_wready,\n" "\t\t@$(SLAVE.PREFIX)_wdata,\n" "\t\t@$(SLAVE.PREFIX)_wstrb,\n" "\t\t@$(SLAVE.PREFIX)_wlast,\n" "//\n" "\t\t@$(SLAVE.PREFIX)_bvalid,\n" "\t\t@$(SLAVE.PREFIX)_bready,\n" "\t\t@$(SLAVE.PREFIX)_bid,\n" "\t\t@$(SLAVE.PREFIX)_bresp"); } if (!p->read_only() && !p->write_only()) str = str + STRING(",\n\t\t// Read connections\n"); if (!p->write_only()) str = str + STRING( "\t\t@$(SLAVE.PREFIX)_arvalid,\n" "\t\t@$(SLAVE.PREFIX)_arready,\n" "\t\t@$(SLAVE.PREFIX)_arid,\n" "\t\t@$(SLAVE.PREFIX)_araddr[") + std::to_string(p->get_slave_address_width()) + STRING("-1:0],\n" "\t\t@$(SLAVE.PREFIX)_arlen,\n" "\t\t@$(SLAVE.PREFIX)_arsize,\n" "\t\t@$(SLAVE.PREFIX)_arburst,\n" "\t\t@$(SLAVE.PREFIX)_arlock,\n" "\t\t@$(SLAVE.PREFIX)_arcache,\n" "\t\t@$(SLAVE.PREFIX)_arprot,\n" "\t\t@$(SLAVE.PREFIX)_arqos,\n" "//\n" "\t\t@$(SLAVE.PREFIX)_rvalid,\n" "\t\t@$(SLAVE.PREFIX)_rready,\n" "\t\t@$(SLAVE.PREFIX)_rid,\n" "\t\t@$(SLAVE.PREFIX)_rdata,\n" "\t\t@$(SLAVE.PREFIX)_rlast,\n" "\t\t@$(SLAVE.PREFIX)_rresp"); return new STRING(str); } // }}} STRINGP AXIBUS::slave_ansi_portlist(PERIPHP p) { // {{{ STRING str; if (!p->read_only()) str = str + STRING( ".@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWVALID(@$(SLAVE.PREFIX)_awvalid),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)AWREADY(@$(SLAVE.PREFIX)_awready),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWID( @$(SLAVE.PREFIX)_awid),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWADDR( @$(SLAVE.PREFIX)_awaddr[") + std::to_string(p->get_slave_address_width()) + STRING("-1:0]),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWLEN( @$(SLAVE.PREFIX)_awlen),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWSIZE( @$(SLAVE.PREFIX)_awsize),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWBURST(@$(SLAVE.PREFIX)_awburst),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWLOCK( @$(SLAVE.PREFIX)_awlock),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWCACHE(@$(SLAVE.PREFIX)_awcache),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWPROT( @$(SLAVE.PREFIX)_awprot),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWQOS( @$(SLAVE.PREFIX)_awqos),\n" "\t\t//\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)WVALID(@$(SLAVE.PREFIX)_wvalid),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)WREADY(@$(SLAVE.PREFIX)_wready),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)WDATA( @$(SLAVE.PREFIX)_wdata),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)WSTRB( @$(SLAVE.PREFIX)_wstrb),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)WLAST( @$(SLAVE.PREFIX)_wlast),\n" "\t\t//\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)BVALID(@$(SLAVE.PREFIX)_bvalid),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)BREADY(@$(SLAVE.PREFIX)_bready),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)BID( @$(SLAVE.PREFIX)_bid),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)BRESP( @$(SLAVE.PREFIX)_bresp)"); if (!p->read_only() && !p->write_only()) str = str + STRING(",\n\t\t// Read connections\n"); if (!p->write_only()) str = str + STRING( "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARVALID(@$(SLAVE.PREFIX)_arvalid),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)ARREADY(@$(SLAVE.PREFIX)_arready),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARID( @$(SLAVE.PREFIX)_arid),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARADDR( @$(SLAVE.PREFIX)_araddr[") + std::to_string(p->get_slave_address_width()) + STRING("-1:0]),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARLEN( @$(SLAVE.PREFIX)_arlen),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARSIZE( @$(SLAVE.PREFIX)_arsize),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARBURST(@$(SLAVE.PREFIX)_arburst),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARLOCK( @$(SLAVE.PREFIX)_arlock),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARCACHE(@$(SLAVE.PREFIX)_arcache),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARPROT( @$(SLAVE.PREFIX)_arprot),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARQOS( @$(SLAVE.PREFIX)_arqos),\n" "//\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)RVALID(@$(SLAVE.PREFIX)_rvalid),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)RREADY(@$(SLAVE.PREFIX)_rready),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)RID( @$(SLAVE.PREFIX)_rid),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)RDATA( @$(SLAVE.PREFIX)_rdata),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)RLAST( @$(SLAVE.PREFIX)_rlast),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)RRESP( @$(SLAVE.PREFIX)_rresp)"); return new STRING(str); } // }}} //////////////////////////////////////////////////////////////////////// // // Bus class logic // // The bus class describes the logic above in a way that it can be // chosen, selected, and enacted within a design. Hence if a design // has four wishbone buses and one AXI4 bus, the bus class logic // will recognize the four WB buses and generate WB bus generators, // and then an AXI4 bus and bus generator, etc. // //////////////////////////////////////////////////////////////////////// STRINGP AXIBUSCLASS::name(void) { return new STRING("axil"); } STRINGP AXIBUSCLASS::longname(void) { return new STRING("AXI4"); } bool AXIBUSCLASS::matchtype(STRINGP str) { if (!str) // We are not the default return false; if (strcasecmp(str->c_str(), "axi")==0) return true; if (strcasecmp(str->c_str(), "axi4")==0) return true; if (strcasecmp(str->c_str(), "axi4full")==0) return true; // printf("ERR: No match for bus type %s\n",str->c_str()); return false; } bool AXIBUSCLASS::matchfail(MAPDHASH *bhash) { return false; } GENBUS *AXIBUSCLASS::create(BUSINFO *bi) { AXIBUS *busclass; busclass = new AXIBUS(bi); return busclass; } ================================================ FILE: sw/bus/axi.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bus/axi.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: AXI4 (full) interface--for high speed AXI4 cores--or any AXI4 // specification compliant cores. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef AXI_H #define AXI_H #include "../genbus.h" #include "axil.h" class AXIBUS : public AXILBUS { int m_id_width; // PLIST *m_slist, *m_dlist; // MAPDHASH *m_interconnect; // unsigned m_num_total, m_num_double, m_num_single; // bool m_is_single, m_is_double; // void xbarcon_master(FILE *fp, const char *, const char *, // const char *, bool comma=true); // void xbarcon_slave(FILE *fp, PLIST *pl, // const char *, const char *, const char *, bool comma=true); // virtual STRINGP master_name(int k); void allocate_subbus(void); BUSINFO *create_sio(void); BUSINFO *create_dio(void); // void countsio(void); public: AXIBUS(BUSINFO *bi); ~AXIBUS() {}; virtual int id_width(void); virtual int address_width(void); virtual bool word_addressing(void) { return false; }; // virtual void assign_addresses(void); virtual bool get_base_address(MAPDHASH *phash, unsigned &base); // void write_addr_range(FILE *fp, const PERIPHP p, // const int dalines); virtual void writeout_defn_v(FILE *fp, const char *mstype, const char *pname, const char *busp, const char *btyp = ""); virtual void writeout_bus_slave_defns_v(FILE *fp); virtual void writeout_bus_master_defns_v(FILE *fp); virtual void writeout_bus_logic_v(FILE *fp); // virtual void writeout_no_slave_v(FILE *fp, STRINGP prefix); // virtual void writeout_no_master_v(FILE *fp); // // virtual STRINGP iansi(BMASTERP); virtual STRINGP oansi(BMASTERP); virtual STRINGP master_ansprefix(BMASTERP); virtual STRINGP master_portlist(BMASTERP); virtual STRINGP master_ansi_portlist(BMASTERP); virtual STRINGP slave_ansprefix(PERIPHP); virtual STRINGP slave_portlist(PERIPHP); virtual STRINGP slave_ansi_portlist(PERIPHP); // virtual void integrity_check(void); }; class AXIBUSCLASS : public BUSCLASS { public: virtual STRINGP name(void); // i.e. WB virtual STRINGP longname(void); // i.e. "Wishbone" virtual bool matchtype(STRINGP strp); virtual bool matchfail(MAPDHASH *); // virtual bool matches(BUSINFO *bi); GENBUS *create(BUSINFO *bi); }; #endif ================================================ FILE: sw/bus/axil.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bus/axil.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // Tags used: // // BUS.WIDTH // BUS.AWID // // SLAVE.TYPE: // - SINGLE // - DOUBLE // - OTHER/MEMORY/BUS // SLAVE.OPTIONS= // // string of case-insensitive options // ROM (slave has no write ports) // WOM (slave has no read ports) // FULL (default:slave has no all ports, not just the ports used) // SLAVE.SHARE= // // slave shares parts of the interface with the other listed slaves // // MASTER.TYPE= // (currently ignored) // // INTERCONNECT.TYPE // - SINGLE // - CROSSBAR // // INTERCONNECT.MASTERS // = list of the PREFIXs of all of the masters of this bus // // INTERCONNECT.OPTIONS // = string of case-insensitive options // OPT_STARVATION_TIMEOUT // OPT_LOWPOWER // OPT_DBLBUFFER // // // INTERCONNECT.OPTVAL= // = Options that require values // - OPT_TIMEOUT // - LGMAXBURST // // Creates tags: // // BLIST: A list of bus interconnect parameters, somewhat like: // @$(SLAVE.BUS)_cyc, // @$(SLAVE.BUS)_stb, // (if !ROM&!WOM) @$(SLAVE.BUS)_we, // (if AWID>0) @$(SLAVE.BUS)_addr[@$(SLAVE.AWID)-1:0], // (if !ROM) @$(SLAVE.BUS)_data, // (if !ROM) @$(SLAVE.BUS)_sel, // @$(PREFIX)_stall, // @$(PREFIX)_ack, // (if !WOM) @$(PREFIX)_data, // (and possibly) @$(PREFIX)_err // // ASCBLIST.PREFIX: [%io] prefix // ASCBLIST.SUFFIX: // ASCBLIST.CAPS: // ASCBLIST.DATA: // .@$(ASCBLIST.PREFIX)cyc@$(ASCBLIST.SUFFIX)(@$SLAVE.BUS)_cyc), // .@$(ASCBLIST.PREFIX)stb@$(ASCBLIST.SUFFIX)(@$SLAVE.BUS)_stb), // .@$(ASCBLIST.PREFIX)we@$(ASCBLIST.SUFFIX)(@$SLAVE.BUS)_we), // . // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include "../parser.h" #include "../mapdhash.h" #include "../keys.h" #include "../kveval.h" #include "../legalnotice.h" #include "../bldtestb.h" #include "../bitlib.h" #include "../plist.h" #include "../bldregdefs.h" #include "../ifdefs.h" #include "../bldsim.h" #include "../predicates.h" #include "../businfo.h" #include "../globals.h" #include "../subbus.h" #include "../msgs.h" #include "../genbus.h" #include "axil.h" #define PREFIX extern AXILBUSCLASS axilclass; const unsigned AXI_MIN_ADDRESS_WIDTH = 12; AXILBUS::AXILBUS(BUSINFO *bi) { // {{{ m_info = bi; m_slist = NULL; m_dlist = NULL; m_is_single = false; m_is_double = false; m_num_single = 0; m_num_double = 0; m_num_total = 0; } // }}} void AXILBUS::allocate_subbus(void) { // {{{ PLIST *pl = m_info->m_plist; BUSINFO *sbi = NULL, *dbi = NULL; if (NULL == pl || pl->size() == 0) { gbl_msg.warning("Bus %s has no attached slaves\n", (name()) ? name()->c_str() : "(No-name)"); } gbl_msg.info("Generating AXI-Lite bus logic generator for %s\n", (name()) ? name()->c_str() : "(No-name)"); countsio(); if (m_num_single == m_num_total) { m_num_single = 0; m_is_single = true; } else if ((m_num_single <= 2)&&(m_num_double > 0)) { // Merge single and double busses, making single // slaves into double slaves m_num_double += m_num_single; m_num_single = 0; } if (!m_is_single && m_num_single + m_num_double == m_num_total) { m_is_double = true; m_num_double = 0; } assert(!m_is_single || !m_is_double); assert(m_num_single < 50); assert(m_num_double < 50); assert(m_num_total >= m_num_single + m_num_double); // // Master of multiple classes // if (!m_is_single && m_num_single > 0) { sbi = create_sio(); m_num_total++; } if (!m_is_double && m_num_double > 0) { m_num_total++; dbi = create_dio(); } if (!m_is_single && !m_is_double && pl) { // // There exist peripherals that are neither singles nor doubles // for(unsigned pi = 0; pi< pl->size(); pi++) { PERIPHP p = (*pl)[pi]; STRINGP ptyp; ptyp = getstring(p->p_phash, KYSLAVE_TYPE); if (m_slist && ptyp != NULL && ptyp->compare(KYSINGLE) == 0) { m_info->m_plist->erase(pl->begin()+pi); pi--; m_slist->add(p); } else if (m_dlist && ptyp != NULL && ((ptyp->compare(KYDOUBLE) == 0) || (ptyp->compare(KYSINGLE) == 0))) { m_info->m_plist->erase(pl->begin()+pi); pi--; m_dlist->add(p); } else { // Leave this peripheral in m_info->m_plist } } } if (sbi) setstring(sbi->m_hash, KY_TYPE, axilclass.name()); if (dbi) setstring(dbi->m_hash, KY_TYPE, axilclass.name()); REHASH; } // }}} int AXILBUS::address_width(void) { // {{{ assert(m_info); return m_info->m_address_width; } // }}} bool AXILBUS::get_base_address(MAPDHASH *phash, unsigned &base) { // {{{ if (!m_info || !m_info->m_plist) { gbl_msg.error("BUS[%s] has no peripherals!\n", (name()) ? name()->c_str() : "(No name)"); return false; } else return m_info->m_plist->get_base_address(phash, base); } // }}} void AXILBUS::assign_addresses(void) { // {{{ int address_width; if (m_info->m_addresses_assigned) return; if ((NULL == m_slist)&&(NULL == m_dlist)) allocate_subbus(); if (!m_info) return; gbl_msg.info("AXIL: Assigning addresses for bus %s\n", (name()) ? name()->c_str() : "(No name bus)"); if (!m_info->m_plist||(m_info->m_plist->size() < 1)) { m_info->m_address_width = 0; } else if (!m_info->m_addresses_assigned) { int dw = m_info->data_width(), nullsz; if (m_slist) m_slist->assign_addresses(dw, 0); if (m_dlist) m_dlist->assign_addresses(dw, 0); if (!getvalue(*m_info->m_hash, KY_NULLSZ, nullsz)) nullsz = 0; m_info->m_plist->assign_addresses(dw, nullsz, AXI_MIN_ADDRESS_WIDTH); address_width = m_info->m_plist->get_address_width(); m_info->m_address_width = address_width; if (m_info->m_hash) { setvalue(*m_info->m_hash, KY_AWID, m_info->m_address_width); REHASH; } } m_info->m_addresses_assigned = true; } // }}} BUSINFO *AXILBUS::create_sio(void) { // {{{ assert(m_info); BUSINFO *sbi; SUBBUS *subp; STRINGP sioname; MAPDHASH *bushash, *shash; MAPT elm; sioname = new STRING(STRING("" PREFIX) + (*name()) + "_sio"); bushash = new MAPDHASH(); shash = new MAPDHASH(); setstring(*shash, KYPREFIX, sioname); setstring(*shash, KYSLAVE_TYPE, new STRING(KYDOUBLE)); setstring(*shash, KYSLAVE_PREFIX, sioname); elm.m_typ = MAPT_MAP; elm.u.m_m = bushash; shash->insert(KEYVALUE(KYSLAVE_BUS, elm)); elm.u.m_m = m_info->m_hash; shash->insert(KEYVALUE(KYMASTER_BUS, elm)); setstring(shash, KYMASTER_TYPE, KYARBITER); sbi = new BUSINFO(sioname); sbi->prefix(new STRING("_sio")); setstring(bushash, KY_TYPE, new STRING("axil")); sbi->m_data_width = m_info->m_data_width; sbi->m_clock = m_info->m_clock; sbi->addmaster(m_info->m_hash); subp = new SUBBUS(shash, sioname, sbi); subp->p_slave_bus = m_info; // subp->p_master_bus = set by the SUBBUS to be sbi m_info->m_plist->add(subp); assert(subp->p_master_bus); assert(subp->p_slave_bus == m_info); assert(subp->p_master_bus == sbi); // m_plist->integrity_check(); sbi->add(); m_slist = sbi->m_plist; return sbi; } // }}} BUSINFO *AXILBUS::create_dio(void) { // {{{ assert(m_info); BUSINFO *dbi; SUBBUS *subp; STRINGP dioname; MAPDHASH *bushash, *shash; MAPT elm; dioname = new STRING(STRING("" PREFIX) + (*name()) + "_dio"); bushash = new MAPDHASH(); shash = new MAPDHASH(); setstring(*bushash, KY_NAME, dioname); setstring(*shash, KYPREFIX, dioname); setstring(*shash, KYSLAVE_TYPE, new STRING(KYOTHER)); setstring(*shash, KYSLAVE_PREFIX, dioname); elm.m_typ = MAPT_MAP; elm.u.m_m = m_info->m_hash; shash->insert(KEYVALUE(KYSLAVE_BUS, elm)); elm.u.m_m = bushash; shash->insert(KEYVALUE(KYMASTER_BUS, elm)); setstring(shash, KYMASTER_TYPE, KYARBITER); dbi = new BUSINFO(dioname); dbi->prefix(new STRING("_dio")); setstring(bushash, KY_TYPE, new STRING("axil")); assert(m_info->data_width() > 0); setvalue(*bushash, KY_WIDTH, m_info->data_width()); dbi->m_data_width = m_info->m_data_width; dbi->m_clock = m_info->m_clock; dbi->addmaster(m_info->m_hash); subp = new SUBBUS(shash, dioname, dbi); subp->p_slave_bus = m_info; m_info->m_plist->add(subp); assert(subp->p_master_bus); assert(subp->p_master_bus == dbi); assert(subp->p_slave_bus == m_info); // subp->p_master_bus = set by the slave to be dbi dbi->add(); m_dlist = dbi->m_plist; assert(isbusmaster(*shash)); assert(isarbiter(*shash)); return dbi; } // }}} void AXILBUS::countsio(void) { // {{{ PLIST *pl = m_info->m_plist; STRINGP strp; m_num_single = 0; m_num_double = 0; m_num_total = 0; if (NULL == pl) return; for(unsigned pi=0; pi< pl->size(); pi++) { strp = getstring((*pl)[pi]->p_phash, KYSLAVE_TYPE); if (NULL != strp) { if (0==strp->compare(KYSINGLE)) { m_num_single++; } else if (0==strp->compare(KYDOUBLE)) { m_num_double++; } m_num_total++; } else m_num_total++; // Default to OTHER if no type is given } } // }}} void AXILBUS::integrity_check(void) { // {{{ // GENBUS::integrity_check(); if (m_info && m_info->m_data_width <= 0) { gbl_msg.error("ERR: BUS width not defined for %s\n", name()->c_str()); } } // }}} void AXILBUS::writeout_defn_v(FILE *fp, const char *mstype, const char *pname, const char* busp, const char *btyp){ // {{{ STRINGP n = name(); int aw = address_width(); fprintf(fp, "\t//\n\t// AXI-lite %s definitions for bus %s%s,\n" "\t// component %s, with prefix %s\n\t// {{{\n", mstype, n->c_str(), btyp, pname, busp); fprintf(fp, "\t// Verilator lint_off UNUSED\n"); fprintf(fp, "\twire\t\t%s_awready, %s_wready,\n\t\t\t%s_arready;\n", busp, busp, busp); fprintf(fp, "\twire\t\t%s_bvalid, %s_rvalid;\n", busp, busp); fprintf(fp, "\twire\t[1:0]\t%s_bresp, %s_rresp;\n", busp, busp); fprintf(fp, "\twire\t[%d:0]\t%s_rdata;\n\n", m_info->data_width()-1, busp); fprintf(fp, "\twire\t\t%s_awvalid, %s_wvalid,\n\t\t\t%s_arvalid,\n" "\t\t\t%s_bready, %s_rready;\n" "\twire\t[%d:0]\t%s_araddr, %s_awaddr;\n" "\twire\t[2:0]\t%s_arprot, %s_awprot;\n" "\twire\t[%d:0]\t%s_wdata;\n" "\twire\t[%d:0]\t%s_wstrb;\n\n", busp, busp, busp, busp, busp, aw-1, busp, busp, busp, busp, m_info->data_width()-1, busp, (m_info->data_width()/8)-1, busp); fprintf(fp, "\t// Verilator lint_on UNUSED\n" "\t// }}}\n"); } // }}} void AXILBUS::writeout_bus_slave_defns_v(FILE *fp) { // {{{ PLIST *p = m_info->m_plist; STRINGP n = name(); if (m_slist) { for(PLIST::iterator pp=m_slist->begin(); pp != m_slist->end(); pp++) { writeout_defn_v(fp, "slave", (*pp)->p_name->c_str(), (*pp)->bus_prefix()->c_str(), "(SIO)"); } } else if (!m_is_single) fprintf(fp, "\n\t// Bus %s has no SINGLE slaves\n\t//\n", n->c_str()); else fprintf(fp, "\n\t// Bus %s is all SINGLE slaves\n\t//\n", n->c_str()); if (m_dlist) { for(PLIST::iterator pp=m_dlist->begin(); pp != m_dlist->end(); pp++) { writeout_defn_v(fp, "slave", (*pp)->p_name->c_str(), (*pp)->bus_prefix()->c_str(), "(DIO)"); } } else if (!m_is_double) fprintf(fp, "\n\t// Bus %s has no DOUBLE slaves\n\t//\n", n->c_str()); else fprintf(fp, "\n\t// Bus %s is all DOUBLE slaves\n\t//\n", n->c_str()); if (p) { for(PLIST::iterator pp=p->begin(); pp != p->end(); pp++) { writeout_defn_v(fp, "slave", (*pp)->p_name->c_str(), (*pp)->bus_prefix()->c_str()); } } else { gbl_msg.error("%s has no slaves\n", n->c_str()); } } // }}} void AXILBUS::writeout_bus_master_defns_v(FILE *fp) { // {{{ MLIST *m = m_info->m_mlist; STRINGP n = name(); if (m) { for(MLIST::iterator pp=m->begin(); pp != m->end(); pp++) { writeout_defn_v(fp, "master", (*pp)->name()->c_str(), (*pp)->bus_prefix()->c_str()); } } else { gbl_msg.warning("Bus %s has no masters\n", n->c_str()); } } // }}} void AXILBUS::write_addr_range(FILE *fp, const PERIPHP p, const int dalines) { // {{{ unsigned w = address_width(); w = (w+3)/4; if (p->p_naddr == 1) fprintf(fp, " // 0x%0*lx", w, p->p_base); else fprintf(fp, " // 0x%0*lx - 0x%0*lx", w, p->p_base, w, p->p_base + (p->p_naddr << (dalines))-1); } // }}} void AXILBUS::writeout_no_slave_v(FILE *fp, STRINGP prefix) { // {{{ } // }}} void AXILBUS::writeout_no_master_v(FILE *fp) { if (!m_info || !name()) gbl_msg.error("(Unnamed bus) has no name!\n"); } STRINGP AXILBUS::master_name(int k) { // {{{ MLISTP ml = m_info->m_mlist; return (*ml)[k]->name(); } // }}} // // Connect this master to the crossbar. Specifically, we want to output // a list of master connections to fill the given port. // void AXILBUS::xbarcon_master(FILE *fp, const char *tabs, const char *pfx,const char *sig, bool comma) { STRING lcase = STRING(sig); for(unsigned k=0; km_mlist->size()-1; k> 0; k--) { BMASTER *m = (*m_info->m_mlist)[k]; STRINGP busp = m->bus_prefix(); fprintf(fp, "%s\t%s_%s,\n", tabs, busp->c_str(), lcase.c_str()); } fprintf(fp, "%s\t%s_%s\n", tabs, (*m_info->m_mlist)[0]->bus_prefix()->c_str(), lcase.c_str()); fprintf(fp, "%s})%s\n", tabs, comma ? ",":""); } // // Output a list of connections to slave bus wires. Used in connecting the // slaves to the various crossbar inputs. // void AXILBUS::xbarcon_slave(FILE *fp, PLIST *pl, const char *tabs, const char *pfx,const char *sig, bool comma) { STRING lcase = STRING(sig); for(unsigned k=0; ksize()-1; k> 0; k--) fprintf(fp, "%s\t%s_%s,\n", tabs, (*pl)[k]->bus_prefix()->c_str(), lcase.c_str()); fprintf(fp, "%s\t%s_%s\n", tabs, (*pl)[0]->bus_prefix()->c_str(), lcase.c_str()); fprintf(fp, "%s})%s\n", tabs, comma ? ",":""); } void AXILBUS::writeout_bus_logic_v(FILE *fp) { STRINGP n = name(), rst; CLOCKINFO *c = m_info->m_clock; PLIST::iterator pp; PLISTP pl; // unsigned unused_lsbs; MLISTP m_mlist = m_info->m_mlist; if (NULL == m_info->m_plist) return; if (NULL == m_info->m_mlist) { gbl_msg.warning("No masters assigned to bus %s\n", n->c_str()); } if (NULL == (rst = m_info->reset_wire())) { gbl_msg.warning("Bus %s has no associated reset wire, using \'i_reset\'\n", n->c_str()); rst = new STRING("i_reset"); setstring(m_info->m_hash, KY_RESET, rst); REHASH; } if (NULL == c || NULL == c->m_wire) { gbl_msg.fatal("Bus %s has no associated clock\n", n->c_str()); } // unused_lsbs = nextlg(m_info->data_width())-3; if (m_info->m_plist->size() == 0) { // No slaves // {{{ fprintf(fp, "\t//\n" "\t// Bus %s has no slaves\n" "\t//\n\n", n->c_str()); // Since this bus has no slaves, any attempt to access it // needs to cause a bus error. // // Need to loop through all possible masters ... for(unsigned m=0; m_info && m < m_info->m_mlist->size(); m++) { STRINGP mstr = master_name(m); const char *mp = mstr->c_str(); fprintf(fp, "\t//\n" "\t// The %s bus has no slaves assigned to it\n" "\t//\n", mp); fprintf(fp, "\t// The no-slave peripheral\n" "\t//\n" "\taxilempty #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d)\n" "\t\t// }}}\n", address_width(), m_info->data_width()); fprintf(fp, "\t) %s_no_slavep (\n" "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s), .S_AXI_ARESETN(%s),\n" "\t\t//\n", mp, c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t.S_AXI_AWVALID(%s_awvalid), .S_AXI_AWREADY(%s_awready),\n" "\t\t.S_AXI_WVALID(%s_wvalid), .S_AXI_WREADY(%s_wready),\n" "\t\t.S_AXI_BVALID(%s_bvalid), .S_AXI_BREADY(%s_bready),\n" "\t\t.S_AXI_BRESP(%s_bresp),\n" "\t\t//\n" "\t\t.S_AXI_ARVALID(%s_arvalid), .S_AXI_ARREADY(%s_arready),\n" "\t\t.S_AXI_RVALID(%s_rvalid), .S_AXI_RREADY(%s_rready),\n" "\t\t.S_AXI_RDATA(%s_rdata), .S_AXI_RRESP(%s_rresp)\n" "\t);\n\n", mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp, mp); } return; // }}} } else if (NULL == m_mlist || m_mlist->size() == 0) { // No masters // {{{ for(unsigned p=0; p < m_info->m_plist->size(); p++) { STRINGP pstr = (*m_info->m_plist)[p]->bus_prefix(); fprintf(fp, "\t//\n" "\t// The %s bus has no masters assigned to it\n" "\t//\n" "\tassign %s_awvalid = 1\'b0;\n" "\tassign %s_awaddr = 0;\n" "\tassign %s_awprot = 3\'h0;\n" "\t//\n", pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str()); fprintf(fp, "\tassign %s_wvalid = 1\'b0;\n" "\tassign %s_wdata = 0;\n" "\tassign %s_wstrb = 0;\n" "\t//\n", pstr->c_str(), pstr->c_str(), pstr->c_str()); fprintf(fp, "\tassign %s_bready = 1\'b0;\n", pstr->c_str()); fprintf(fp, "\t//\n" "\tassign %s_arvalid = 1\'b0;\n" "\tassign %s_araddr = 0;\n" "\tassign %s_arprot = 3\'h0;\n" "\t//\n", pstr->c_str(), pstr->c_str(), pstr->c_str()); fprintf(fp, "\tassign %s_rready = 1\'b1;\n", pstr->c_str()); fprintf(fp, "\t//\n" "\t//\n" "\twire %s_unused;\n" "\tassign %s_unused = &{ 1\'b0, %s_awready, %s_wready,\n" "\t\t%s_bvalid, %s_bresp,\n" "\t\t%s_arready,\n" "\t\t%s_rvalid, %s_rdata, %s_rresp\n" "\t\t};\n", pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(),pstr->c_str(),pstr->c_str() ); } return; // }}} } else if ((m_info->m_plist->size() == 1)&&(m_mlist && m_mlist->size() == 1)) { // {{{ // Only one master connected to only one slave--skip all the // extra connection logic. // // Can only simplify if there's only one peripheral and only // one master // STRINGP slv = (*m_info->m_plist)[0]->bus_prefix(); STRINGP mstr = (*m_mlist)[0]->bus_prefix(); const char *sp = slv->c_str(), *mp = mstr->c_str(); fprintf(fp, "\t//\n" "\t// Bus %s has only one master (%s) and one slave (%s)\n" "\t// connected to it -- skipping the interconnect\n" "\t//\n", n->c_str(), master_name(0)->c_str(), sp); fprintf(fp, "\tassign %s_awvalid = %s_awvalid;\n" "\tassign %s_awready = %s_awready;\n" "\tassign %s_awaddr = %s_awaddr;\n" "\tassign %s_awprot = %s_awprot;\n" "\t//\n", sp, mp, mp, sp, sp, mp, sp, mp); fprintf(fp, "\tassign %s_wvalid = %s_wvalid;\n" "\tassign %s_wready = %s_wready;\n" "\tassign %s_wdata = %s_wdata;\n" "\tassign %s_wstrb = %s_wstrb;\n" "\t//\n", sp, mp, mp, sp, sp, mp, sp, mp); fprintf(fp, "\tassign %s_bvalid = %s_bvalid;\n" "\tassign %s_bready = %s_bready;\n" "\tassign %s_bresp = %s_bresp;\n", mp, sp, sp, mp, mp, sp); fprintf(fp, "\t//\n" "\tassign %s_arvalid = %s_arvalid;\n" "\tassign %s_arready = %s_arready;\n" "\tassign %s_araddr = %s_araddr;\n" "\tassign %s_arprot = %s_arprot;\n" "\t//\n", sp, mp, mp, sp, sp, mp, sp, mp); fprintf(fp, "\tassign %s_rvalid = %s_rvalid;\n" "\tassign %s_rready = %s_rready;\n" "\tassign %s_rdata = %s_rdata;\n" "\tassign %s_rresp = %s_rresp;\n\n", mp, sp, sp, mp, mp, sp, mp, sp); return; // }}} } // Start with the slist if (m_is_single || m_slist) { // {{{ assert(1 == m_info->m_mlist->size()); PLIST *slist = (m_is_single) ? m_info->m_plist : m_slist; const char *np = n->c_str(); STRING s = STRING(*(*m_mlist)[0]->bus_prefix()); int aw = nextlg(slist->size())+nextlg(m_info->data_width())-3; fprintf(fp, "\t// Some extra wires to capture combined values--values\n" "\t// that will be the same across all slaves of the\n" "\t// class\n" "\twire [2:0]\t%s_siow_awprot;\n" "\twire [%d:0]\t%s_siow_wdata;\n" "\twire [%d:0]\t%s_siow_wstrb;\n" "\twire [2:0]\t%s_siow_arprot;\n\n", n->c_str(), m_info->data_width()-1, n->c_str(), m_info->data_width()/8-1, n->c_str(), n->c_str()); fprintf(fp, "\taxilsingle #(\n" "\t\t// {{{\n" "\t\t// .C_AXI_ADDR_WIDTH(%d), // must be only one word address\n" "\t\t.C_AXI_DATA_WIDTH(%d),\n" "\t\t.NS(%ld)", aw, m_info->data_width(), slist->size()); xbar_option(fp, KY_OPT_LOWPOWER, ",\n\t\t.OPT_LOWPOWER(%)", "1\'b1"); fprintf(fp, "\n\t\t// }}}\n" "\t) %s_axilsingle(\n", np); fprintf(fp, "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s),\n" "\t\t.S_AXI_ARESETN(%s),\n", c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t// Connect our SIO slave wires to axilsingle\n" "\t\t// {{{\n"); fprintf(fp, "\t\t.S_AXI_AWVALID(%s_awvalid),\n" "\t\t.S_AXI_AWREADY(%s_awready),\n" "\t\t.S_AXI_AWADDR( %s_awaddr[%d:0]),\n" "\t\t.S_AXI_AWPROT( %s_awprot),\n" "\t\t//\n" "\t\t.S_AXI_WVALID( %s_wvalid),\n" "\t\t.S_AXI_WREADY( %s_wready),\n" "\t\t.S_AXI_WDATA( %s_wdata),\n" "\t\t.S_AXI_WSTRB( %s_wstrb),\n" "\t\t//\n" "\t\t.S_AXI_BVALID( %s_bvalid),\n" "\t\t.S_AXI_BREADY( %s_bready),\n" "\t\t.S_AXI_BRESP( %s_bresp),\n" "\t\t// Read connections\n" "\t\t.S_AXI_ARVALID(%s_arvalid),\n" "\t\t.S_AXI_ARREADY(%s_arready),\n" "\t\t.S_AXI_ARADDR( %s_araddr[%d:0]),\n" "\t\t.S_AXI_ARPROT( %s_arprot),\n" "\t\t//\n" "\t\t.S_AXI_RVALID( %s_rvalid),\n" "\t\t.S_AXI_RREADY( %s_rready),\n" "\t\t.S_AXI_RDATA( %s_rdata),\n" "\t\t.S_AXI_RRESP( %s_rresp),\n" "\t\t// }}}\n" "\t\t// Connections to varous AXI-lite (SINGLE) slaves\n" "\t\t// {{{\n", s.c_str(), s.c_str(), s.c_str(), aw-1, s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(), aw-1, s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str()); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","AWVALID"); fprintf(fp, "\t\t.M_AXI_AWPROT(%s_siow_awprot),\n" "\t\t.M_AXI_WDATA( %s_siow_wdata),\n" "\t\t.M_AXI_WSTRB( %s_siow_wstrb),\n", n->c_str(), n->c_str(), n->c_str()); fprintf(fp, "\t\t//\n" "\t\t//\n"); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","BRESP"); fprintf(fp, "\t\t// Read connections\n"); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","ARVALID"); fprintf(fp, "\t\t.M_AXI_ARPROT(%s_siow_arprot),\n" "\t\t//\n", n->c_str()); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","RDATA"); xbarcon_slave(fp, slist, "\t\t",".M_AXI_","RRESP", false); fprintf(fp, "\t\t// }}}\n" "\t\t// }}}\n" "\t);\n\n"); fprintf(fp,"\t//\n\t// Now connecting the extra slaves wires " "to the AXILSINGLE controller\n" "\t// {{{\n"); for(int k=slist->size(); k>0; k--) { PERIPHP p = (*slist)[k-1]; const char *pn = p->p_name->c_str(), *ns = n->c_str(); fprintf(fp, "\t// %s\n", pn); pn = p->bus_prefix()->c_str(); fprintf(fp, "\tassign %s_awaddr = 0;\n", pn); fprintf(fp, "\tassign %s_awprot = %s_siow_awprot;\n", pn, ns); fprintf(fp, "\tassign %s_wvalid = %s_awvalid;\n", pn, pn); fprintf(fp, "\tassign %s_wdata = %s_siow_wdata;\n", pn, ns); fprintf(fp, "\tassign %s_wstrb = %s_siow_wstrb;\n", pn, ns); fprintf(fp, "\tassign %s_bready = 1\'b1;\n", pn); fprintf(fp, "\tassign %s_araddr = 0;\n", pn); fprintf(fp, "\tassign %s_arprot = %s_siow_arprot;\n", pn, ns); fprintf(fp, "\tassign %s_rready = 1\'b1;\n", pn); } fprintf(fp, "\t// }}}\n"); // }}} return; // }}} } else if (!m_slist) fprintf(fp, "\t//\n\t// No class SINGLE peripherals on the \"%s\" bus\n\t//\n\n", n->c_str()); // Then the dlist if (m_is_double || m_dlist) { // {{{ if (m_dlist) pl = m_dlist; else pl = m_info->m_plist; STRING s = STRING(*(*m_mlist)[0]->bus_prefix()); int aw = address_width(); if (!m_is_double) s = (*n) + "_dio"; fprintf(fp, "\t//\n" "\t// %s Bus logic to handle %ld DOUBLE slaves\n" "\t//\n" "\t//\n", n->c_str(), pl->size()); fprintf(fp, "\t// Some extra wires to capture combined values--values\n" "\t// that will be the same across all slaves of the\n" "\t// class\n" "\twire [%d:0]\t%s_diow_awaddr;\n" "\twire [2:0]\t%s_diow_awprot;\n" "\twire [%d:0]\t%s_diow_wdata;\n" "\twire [%d:0]\t%s_diow_wstrb;\n" "\twire [%d:0]\t%s_diow_araddr;\n" "\twire [2:0]\t%s_diow_arprot;\n\n", address_width()-1, n->c_str(), n->c_str(), m_info->data_width()-1, n->c_str(), m_info->data_width()/8-1, n->c_str(), address_width()-1, n->c_str(), n->c_str()); fprintf(fp, "\taxildouble #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d),\n" "\t\t.NS(%ld),\n", address_width(), m_info->data_width(), pl->size()); xbar_option(fp, KY_OPT_LOWPOWER, "\t\t.OPT_LOWPOWER(%),\n", "1\'b1"); slave_addr(fp, pl); fprintf(fp, ",\n"); slave_mask(fp, pl); fprintf(fp, "\n"); fprintf(fp, "\t\t// }}}\n" "\t) %s_axildouble(\n", n->c_str()); fprintf(fp, "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s),\n" "\t\t.S_AXI_ARESETN(%s),\n", c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t//\n"); fprintf(fp, "\t\t// Slave port\n" "\t\t// {{{\n" "\t\t.S_AXI_AWVALID(%s_awvalid),\n" "\t\t.S_AXI_AWREADY(%s_awready),\n" "\t\t.S_AXI_AWADDR( %s_awaddr[%d:0]),\n" "\t\t.S_AXI_AWPROT( %s_awprot),\n" "\t\t//\n" "\t\t.S_AXI_WVALID( %s_wvalid),\n" "\t\t.S_AXI_WREADY( %s_wready),\n" "\t\t.S_AXI_WDATA( %s_wdata),\n" "\t\t.S_AXI_WSTRB( %s_wstrb),\n" "\t\t//\n" "\t\t.S_AXI_BVALID( %s_bvalid),\n" "\t\t.S_AXI_BREADY( %s_bready),\n" "\t\t.S_AXI_BRESP( %s_bresp),\n" "\t\t//\n", // AW s.c_str(), s.c_str(), s.c_str(), aw-1, s.c_str(), // W s.c_str(), s.c_str(), s.c_str(), s.c_str(), // B s.c_str(), s.c_str(), s.c_str()); fprintf(fp, "\t\t// Read connections\n" "\t\t.S_AXI_ARVALID(%s_arvalid),\n" "\t\t.S_AXI_ARREADY(%s_arready),\n" "\t\t.S_AXI_ARADDR( %s_araddr[%d:0]),\n" "\t\t.S_AXI_ARPROT( %s_arprot),\n" "\t\t//\n" "\t\t.S_AXI_RVALID( %s_rvalid),\n" "\t\t.S_AXI_RREADY( %s_rready),\n" "\t\t.S_AXI_RDATA( %s_rdata),\n" "\t\t.S_AXI_RRESP( %s_rresp),\n" "\t\t// }}}\n" "\t\t// Connections to slaves\n" "\t\t// {{{\n", // AR s.c_str(), s.c_str(), s.c_str(), aw-1, s.c_str(), // R s.c_str(), s.c_str(), s.c_str(), s.c_str()); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWVALID"); fprintf(fp, "\t\t.M_AXI_AWADDR( %s_diow_awaddr),\n" "\t\t.M_AXI_AWPROT( %s_diow_awprot),\n", n->c_str(), n->c_str()); fprintf(fp, "\t\t.M_AXI_WDATA( %s_diow_wdata),\n" "\t\t.M_AXI_WSTRB( %s_diow_wstrb),\n", n->c_str(), n->c_str()); fprintf(fp, "\t\t//\n"); fprintf(fp, "\t\t//\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","BRESP"); fprintf(fp, "\t\t// Read connections\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARVALID"); fprintf(fp, "\t\t.M_AXI_ARADDR( %s_diow_araddr),\n" "\t\t.M_AXI_ARPROT( %s_diow_arprot),\n" "\t\t//\n", n->c_str(), n->c_str()); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RDATA"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RRESP", false); fprintf(fp, "\t\t// }}}\n" "\t\t// }}}\n" "\t);\n\n"); fprintf(fp,"\t//\n\t// Now connecting the extra slaves wires " "to the AXILDOUBLE controller\n\t//\n"); for(int k=pl->size(); k>0; k--) { PERIPHP p = (*pl)[k-1]; const char *pn = p->p_name->c_str(), *pfx = p->bus_prefix()->c_str(); // int aw = p->p_awid + unused_lsbs; fprintf(fp, "\t// %s\n" "\t// {{{\n", pn); fprintf(fp, "\tassign %s_awaddr = %s_diow_awaddr;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_awprot = %s_diow_awprot;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_wvalid = %s_awvalid;\n", pfx, pfx); fprintf(fp, "\tassign %s_wdata = %s_diow_wdata;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_wstrb = %s_diow_wstrb;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_bready = 1\'b1;\n", pfx); fprintf(fp, "\tassign %s_araddr = %s_diow_araddr;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_arprot = %s_diow_arprot;\n", pfx, n->c_str()); fprintf(fp, "\tassign %s_rready = 1\'b1;\n" "\t// }}}\n", pfx); } if (m_is_double) return; // }}} } else if (!m_dlist) fprintf(fp, "\t//\n\t// No class DOUBLE peripherals on the \"%s\" bus\n\t//\n\n", n->c_str()); // // // Now for the main set of slaves // // pl = m_info->m_plist; unsigned slave_name_width = 4; // Find the maximum width of any slaves name, for our comment tables // below for(unsigned k=0; km_plist->size(); k++) { PERIPHP p = (*m_info->m_plist)[k]; unsigned sz; sz = p->name()->size(); if (slave_name_width < sz) slave_name_width = sz; } // // Now create the crossbar interconnect // // if ((m_mlist->size() == 1)&&(m_info->m_plist->size() == 1)) // special case we dealt with above fprintf(fp, "\t////////////////////////////////////////////////////////////////////////\n" "\t//\n" "\t// Connect the %s bus components together using the axilxbar()\n" "\t// {{{\n" "\t//\n", n->c_str()); fprintf(fp, "\taxilxbar #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d),\n" "\t\t.NM(%ld), .NS(%ld),\n", address_width(), m_info->data_width(), m_mlist->size(), m_info->m_plist->size()); slave_addr(fp, m_info->m_plist); fprintf(fp, ",\n"); slave_mask(fp, m_info->m_plist); xbar_option(fp, KY_OPT_LOWPOWER, ",\n\t\t.OPT_LOWPOWER(%)", "1\'b1"); xbar_option(fp, KY_OPT_LINGER, ",\n\t\t.OPT_LINGER(%)"); xbar_option(fp, KY_OPT_LGMAXBURST,",\n\t\t.LGMAXBURST(%)"); // fprintf(fp, "\n\t\t// }}}\n" "\t) %s_xbar(\n" "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s),\n", n->c_str(), m_info->m_clock->m_wire->c_str()); fprintf(fp, "\t\t.S_AXI_ARESETN(%s),\n", rst->c_str()); fprintf(fp, "\t\t// Connections from masters\n" "\t\t// {{{\n"); xbarcon_master(fp, "\t\t",".S_AXI_","AWVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","AWREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","AWADDR"); xbarcon_master(fp, "\t\t",".S_AXI_","AWPROT"); fprintf(fp, "\t\t//\n"); xbarcon_master(fp, "\t\t",".S_AXI_","WVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","WREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","WDATA"); xbarcon_master(fp, "\t\t",".S_AXI_","WSTRB"); fprintf(fp, "\t\t//\n"); xbarcon_master(fp, "\t\t",".S_AXI_","BVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","BREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","BRESP"); fprintf(fp, "\t\t// Read connections\n"); xbarcon_master(fp, "\t\t",".S_AXI_","ARVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","ARREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","ARADDR"); xbarcon_master(fp, "\t\t",".S_AXI_","ARPROT"); fprintf(fp, "\t\t//\n"); xbarcon_master(fp, "\t\t",".S_AXI_","RVALID"); xbarcon_master(fp, "\t\t",".S_AXI_","RREADY"); xbarcon_master(fp, "\t\t",".S_AXI_","RDATA"); xbarcon_master(fp, "\t\t",".S_AXI_","RRESP"); fprintf(fp, "\t\t// }}}\n"); fprintf(fp, "\t\t// Connections to slaves\n"); fprintf(fp, "\t\t// {{{\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWADDR"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","AWPROT"); fprintf(fp, "\t\t//\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WDATA"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","WSTRB"); fprintf(fp, "\t\t//\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","BVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","BREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","BRESP"); fprintf(fp, "\t\t// Read connections\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARADDR"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","ARPROT"); fprintf(fp, "\t\t//\n"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RVALID"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RREADY"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RDATA"); xbarcon_slave(fp, pl, "\t\t",".M_AXI_","RRESP", false); fprintf(fp, "\t\t// }}}\n" "\t\t// }}}\n\t);\n\n"); for(unsigned k=0; k < m_info->m_plist->size(); k++) { // Handle read only or write only slaves // {{{ PERIPHP p = (*m_info->m_plist)[k]; STRINGP busp = p->bus_prefix(); const char *bp = busp->c_str(); if (p->write_only()) { fprintf(fp, "\taxilempty #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d)\n" "\t\t// }}}\n", address_width(), m_info->data_width()); fprintf(fp, "\t) %s_no_slavep (\n" "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s), .S_AXI_ARESETN(%s),\n" "\t\t//\n", bp, c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t// Verilator lint_off PINCONNECTEMPTY\n" "\t\t.S_AXI_AWVALID(1\'b0), .S_AXI_AWREADY(),\n" "\t\t.S_AXI_WVALID(1\'b0), .S_AXI_WREADY(),\n" "\t\t//\n" "\t\t.S_AXI_BVALID(), .S_AXI_BREADY(1\'b1),\n" "\t\t.S_AXI_BRESP(),\n" "\t\t// Verilator lint_on PINCONNECTEMPTY\n" "\t\t//\n" "\t\t.S_AXI_ARVALID(%s_arvalid), .S_AXI_ARREADY(%s_arready),\n" "\t\t.S_AXI_RVALID(%s_rvalid), .S_AXI_RREADY(%s_rready),\n" "\t\t.S_AXI_RDATA(%s_rdata), .S_AXI_RRESP(%s_rresp)\n" "\t\t// }}}\n" "\t);\n\n", // AW, W, B // AR bp, bp, // R bp, bp, bp, bp); } if (p->read_only()) { fprintf(fp, "\taxilempty #(\n" "\t\t// {{{\n" "\t\t.C_AXI_ADDR_WIDTH(%d),\n" "\t\t.C_AXI_DATA_WIDTH(%d)\n" "\t\t// }}}\n", address_width(), m_info->data_width()); fprintf(fp, "\t) %s_no_slavep (\n" "\t\t// {{{\n" "\t\t.S_AXI_ACLK(%s), .S_AXI_ARESETN(%s),\n" "\t\t//\n", bp, c->m_wire->c_str(), rst->c_str()); fprintf(fp, "\t\t.S_AXI_AWVALID(%s_awvalid), .S_AXI_AWREADY(%s_awready),\n" "\t\t.S_AXI_WVALID(%s_wvalid), .S_AXI_WREADY(%s_wready),\n" "\t\t//\n" "\t\t.S_AXI_BVALID(%s_bvalid), .S_AXI_BREADY(%s_bready),\n" "\t\t.S_AXI_BRESP(%s_bresp),\n" "\t\t//\n" "\t\t// Verilator lint_off PINCONNECTEMPTY\n" "\t\t.S_AXI_ARVALID(1\'b0), .S_AXI_ARREADY(),\n" "\t\t.S_AXI_RVALID(), .S_AXI_RREADY(1\'b1),\n" "\t\t.S_AXI_RDATA(), .S_AXI_RRESP()\n" "\t\t// Verilator lint_on PINCONNECTEMPTY\n" "\t);\n\n", // AW, W, B bp, bp, bp, bp, bp, bp, bp); } // }}} } fprintf(fp, "\t\t// }}}\n"); } STRINGP AXILBUS::master_portlist(BMASTERP m) { // {{{ STRING str; if (m->write_only()) str = str + STRING("// Master is write-only\n"); if (m->read_only()) str = str + STRING("// Master is read only\n\t\t"); else str = str + STRING( "@$(MASTER.PREFIX)_awvalid,\n" "\t\t@$(MASTER.PREFIX)_awready,\n" "\t\t@$(MASTER.PREFIX)_awaddr[@$(MASTER.BUS.AWID)-1:0],\n" "\t\t@$(MASTER.PREFIX)_awprot,\n" "\t\t//\n" "\t\t@$(MASTER.PREFIX)_wvalid,\n" "\t\t@$(MASTER.PREFIX)_wready,\n" "\t\t@$(MASTER.PREFIX)_wdata,\n" "\t\t@$(MASTER.PREFIX)_wstrb,\n" "\t\t//\n" "\t\t@$(MASTER.PREFIX)_bvalid,\n" "\t\t@$(MASTER.PREFIX)_bready,\n" "\t\t@$(MASTER.PREFIX)_bresp"); if (!m->read_only() && !m->write_only()) str = str + STRING(",\n\t\t// Read connections\n\t\t"); if (!m->write_only()) str = str + STRING( "@$(MASTER.PREFIX)_arvalid,\n" "\t\t@$(MASTER.PREFIX)_arready,\n" "\t\t@$(MASTER.PREFIX)_araddr[@$(MASTER.BUS.AWID)-1:0],\n" "\t\t@$(MASTER.PREFIX)_arprot,\n" "\t\t//\n" "\t\t@$(MASTER.PREFIX)_rvalid,\n" "\t\t@$(MASTER.PREFIX)_rready,\n" "\t\t@$(MASTER.PREFIX)_rdata,\n" "\t\t@$(MASTER.PREFIX)_rresp"); return new STRING(str); } // }}} STRINGP AXILBUS::iansi(BMASTERP m) { return new STRING(""); } STRINGP AXILBUS::oansi(BMASTERP m) { return new STRING(""); } STRINGP AXILBUS::master_ansprefix(BMASTERP m) { return new STRING("M_AXI_"); } STRINGP AXILBUS::master_ansi_portlist(BMASTERP m) { // {{{ STRING str; if (!m->read_only()) str = str + STRING( ".@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWVALID(@$(MASTER.PREFIX)_awvalid),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)AWREADY(@$(MASTER.PREFIX)_awready),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWADDR( @$(MASTER.PREFIX)_awaddr[@$(MASTER.BUS.AWID)-1:0]),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)AWPROT( @$(MASTER.PREFIX)_awprot),\n" "\t\t//\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)WVALID(@$(MASTER.PREFIX)_wvalid),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)WREADY(@$(MASTER.PREFIX)_wready),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)WDATA( @$(MASTER.PREFIX)_wdata),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)WSTRB( @$(MASTER.PREFIX)_wstrb),\n" "\t\t//\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)BVALID(@$(MASTER.PREFIX)_bvalid),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)BREADY(@$(MASTER.PREFIX)_bready),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)BRESP( @$(MASTER.PREFIX)_bresp)"); if (!m->read_only() && !m->write_only()) str = str + STRING(",\n\t\t// Read connections\n\t\t"); if (!m->write_only()) str = str + STRING( ".@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARVALID(@$(MASTER.PREFIX)_arvalid),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)ARREADY(@$(MASTER.PREFIX)_arready),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARADDR( @$(MASTER.PREFIX)_araddr[@$(MASTER.BUS.AWID)-1:0]),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)ARPROT( @$(MASTER.PREFIX)_arprot),\n" "//\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)RVALID(@$(MASTER.PREFIX)_rvalid),\n" "\t\t.@$(MASTER.IANSI)@$(MASTER.ANSPREFIX)RREADY(@$(MASTER.PREFIX)_rready),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)RDATA( @$(MASTER.PREFIX)_rdata),\n" "\t\t.@$(MASTER.OANSI)@$(MASTER.ANSPREFIX)RRESP( @$(MASTER.PREFIX)_rresp)"); return new STRING(str); } // }}} STRINGP AXILBUS::slave_ansprefix(PERIPHP m) { return new STRING("S_AXI_"); } STRINGP AXILBUS::slave_portlist(PERIPHP p) { // {{{ STRING str; if (p->write_only()) str = str + STRING("// Slave is write-only\n\t\t"); if (p->read_only()) str = str + STRING("// Slave is read only\n\t\t"); else { str = str + STRING( "\t\t@$(SLAVE.PREFIX)_awvalid,\n" "\t\t@$(SLAVE.PREFIX)_awready,\n" "\t\t@$(SLAVE.PREFIX)_awaddr[") + std::to_string(p->get_slave_address_width()) + STRING("-1:0],\n" "\t\t@$(SLAVE.PREFIX)_awprot,\n" "//\n" "\t\t@$(SLAVE.PREFIX)_wvalid,\n" "\t\t@$(SLAVE.PREFIX)_wready,\n" "\t\t@$(SLAVE.PREFIX)_wdata,\n" "\t\t@$(SLAVE.PREFIX)_wstrb,\n" "//\n" "\t\t@$(SLAVE.PREFIX)_bvalid,\n" "\t\t@$(SLAVE.PREFIX)_bready,\n" "\t\t@$(SLAVE.PREFIX)_bresp"); } if (!p->read_only() && !p->write_only()) str = str + STRING(",\n\t\t// Read connections\n"); if (!p->write_only()) str = str + STRING( "\t\t@$(SLAVE.PREFIX)_arvalid,\n" "\t\t@$(SLAVE.PREFIX)_arready,\n" "\t\t@$(SLAVE.PREFIX)_araddr[") + std::to_string(p->get_slave_address_width()) + STRING("-1:0],\n" "\t\t@$(SLAVE.PREFIX)_arprot,\n" "//\n" "\t\t@$(SLAVE.PREFIX)_rvalid,\n" "\t\t@$(SLAVE.PREFIX)_rready,\n" "\t\t@$(SLAVE.PREFIX)_rdata,\n" "\t\t@$(SLAVE.PREFIX)_rresp"); return new STRING(str); } // }}} STRINGP AXILBUS::slave_ansi_portlist(PERIPHP p) { // {{{ STRING str; if (!p->read_only()) str = str + STRING( ".@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWVALID(@$(SLAVE.PREFIX)_awvalid),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)AWREADY(@$(SLAVE.PREFIX)_awready),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWADDR( @$(SLAVE.PREFIX)_awaddr[") + std::to_string(p->get_slave_address_width()) + STRING("-1:0]),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)AWPROT( @$(SLAVE.PREFIX)_awprot),\n" "//\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)WVALID(@$(SLAVE.PREFIX)_wvalid),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)WREADY(@$(SLAVE.PREFIX)_wready),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)WDATA( @$(SLAVE.PREFIX)_wdata),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)WSTRB( @$(SLAVE.PREFIX)_wstrb),\n" "//\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)BVALID(@$(SLAVE.PREFIX)_bvalid),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)BREADY(@$(SLAVE.PREFIX)_bready),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)BRESP( @$(SLAVE.PREFIX)_bresp),\n"); if (!p->read_only() && !p->write_only()) str = str + STRING("\t\t// Read connections\n"); if (!p->write_only()) str = str + STRING( "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARVALID(@$(SLAVE.PREFIX)_arvalid),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)ARREADY(@$(SLAVE.PREFIX)_arready),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARADDR( @$(SLAVE.PREFIX)_araddr[") + std::to_string(p->get_slave_address_width()) + STRING("-1:0]),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)ARPROT( @$(SLAVE.PREFIX)_arprot),\n" "//\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)RVALID(@$(SLAVE.PREFIX)_rvalid),\n" "\t\t.@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)RREADY(@$(SLAVE.PREFIX)_rready),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)RDATA( @$(SLAVE.PREFIX)_rdata),\n" "\t\t.@$(SLAVE.OANSI)@$(SLAVE.ANSPREFIX)RRESP( @$(SLAVE.PREFIX)_rresp)"); return new STRING(str); } // }}} //////////////////////////////////////////////////////////////////////// // // Bus class logic // // The bus class describes the logic above in a way that it can be // chosen, selected, and enacted within a design. Hence if a design // has four wishbone buses and one AXI-lite bus, the bus class logic // will recognize the four WB buses and generate WB bus generators, // and then an AXI-lite bus and bus generator, etc. // //////////////////////////////////////////////////////////////////////// STRINGP AXILBUSCLASS::name(void) { return new STRING("axil"); } STRINGP AXILBUSCLASS::longname(void) { return new STRING("AXI-lite"); } bool AXILBUSCLASS::matchtype(STRINGP str) { if (!str) // We are not the default return false; if (strcasecmp(str->c_str(), "axil")==0) return true; if (strcasecmp(str->c_str(), "axi-lite")==0) return true; if (strcasecmp(str->c_str(), "axi lite")==0) return true; // printf("ERR: No match for bus type %s\n",str->c_str()); return false; } bool AXILBUSCLASS::matchfail(MAPDHASH *bhash) { return false; } GENBUS *AXILBUSCLASS::create(BUSINFO *bi) { AXILBUS *busclass; busclass = new AXILBUS(bi); return busclass; } ================================================ FILE: sw/bus/axil.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bus/axil.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: AXI-lite interface--for high speed AXI-lite cores. (Slow speed // ones should work too if they follow the spec) // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef AXIL_H #define AXIL_H #include "../genbus.h" class AXILBUS : public GENBUS { protected: PLIST *m_slist, *m_dlist; MAPDHASH *m_interconnect; unsigned m_num_total, m_num_double, m_num_single; bool m_is_single, m_is_double; void xbarcon_master(FILE *fp, const char *, const char *, const char *, bool comma=true); void xbarcon_slave(FILE *fp, PLIST *pl, const char *, const char *, const char *, bool comma=true); STRINGP master_name(int k); void allocate_subbus(void); BUSINFO *create_sio(void); BUSINFO *create_dio(void); void countsio(void); public: AXILBUS(BUSINFO *bi); ~AXILBUS() {}; virtual int address_width(void); virtual bool word_addressing(void) { return false; }; // virtual void assign_addresses(void); virtual bool get_base_address(MAPDHASH *phash, unsigned &base); void write_addr_range(FILE *fp, const PERIPHP p, const int dalines); virtual void writeout_defn_v(FILE *fp, const char *mstype, const char *pname, const char *busp, const char *btyp = ""); virtual void writeout_bus_slave_defns_v(FILE *fp); virtual void writeout_bus_master_defns_v(FILE *fp); virtual void writeout_bus_logic_v(FILE *fp); virtual void writeout_no_slave_v(FILE *fp, STRINGP prefix); virtual void writeout_no_master_v(FILE *fp); // // virtual STRINGP iansi(BMASTERP); virtual STRINGP oansi(BMASTERP); virtual STRINGP master_ansprefix(BMASTERP); virtual STRINGP master_portlist(BMASTERP); virtual STRINGP master_ansi_portlist(BMASTERP); virtual STRINGP slave_ansprefix(PERIPHP); virtual STRINGP slave_portlist(PERIPHP); virtual STRINGP slave_ansi_portlist(PERIPHP); virtual void integrity_check(void); }; class AXILBUSCLASS : public BUSCLASS { public: virtual STRINGP name(void); // i.e. WB virtual STRINGP longname(void); // i.e. "Wishbone" virtual bool matchtype(STRINGP strp); virtual bool matchfail(MAPDHASH *); // virtual bool matches(BUSINFO *bi); GENBUS *create(BUSINFO *bi); }; #endif ================================================ FILE: sw/bus/wb.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bus/wb.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // Tags used: // // BUS.WIDTH // BUS.AWID // // SLAVE.TYPE: // - SINGLE // - DOUBLE // - OTHER/MEMORY/BUS // SLAVE.PREFIX: // A string to use to prefix all of the slave's bus wires when // naming // SLAVE.OPTIONS= (unused) // RO (read only slave) // WO (write only slave) // (default: read and write) // SLAVE.SHARE= // // slave shares parts of the interface with the other listed slaves // // MASTER.TYPE= // (currently ignored) // MASTER.PREFIX: // A string to use to prefix all of the master's bus wires when // naming // MASTER.OPTIONS= (unused) // RO (read only master) // WO (write only master) // (default: read and write) // // // INTERCONNECT.TYPE (Not used) // // - SINGLE (Deprecated interconnect) // // - CROSSBAR // // BUS.OPT_LOWPOWER // If set, forces bus wires to zero when stb (or ack) is low. // BUS.OPT_DBLBUFFER // If set, uses an extra clock on the return--for better clock // speed performance // BUS.OPT_LGMAXBURST // Log_2 of the maximum number of transactions "in-flight" at any // given time. This sets the bit-width of the internal transaction // counter // BUS.OPT_TIMEOUT // Bus cycles before timing out on any operation // BUS.OPT_STARVATION_TIMEOUT // (Currently ignored) // // Creates tags: // // SLAVE.PORTLIST: A list of bus interconnect parameters, somewhat like: // @$(SLAVE.PREFIX)_cyc, // @$(SLAVE.PREFIX)_stb, // (if !RO&!WO) @$(SLAVE.PREFIX)_we, // (if AWID>0) @$(SLAVE.PREFIX)_addr[@$(SLAVE.AWID)-1:0], // (if !RO) @$(SLAVE.PREFIX)_data, // (if !RO) @$(SLAVE.PREFIX)_sel, // @$(SLAVE.PREFIX)_stall, // @$(SLAVE.PREFIX)_ack, // (if !WO) @$(SLAVE.PREFIX)_data, // (and possibly) @$(SLAVE.PREFIX)_err // // ... only, I've currently chosen to do this in a slave independent // fashion, and so the ROM, WOM, and AWID strings get set as a default // // SLAVE.ANSIPORTLIST ... same thing, // // SLAVE.IANSI: i_ // SLAVE.OANSI: o_ // SLAVE.ANSPREFIX: // SLAVE.ANSSUFFIX: // .@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)cyc@$(SLAVE.ANSSUFFIX)(@$SLAVE.BUS)_cyc), // .@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)stb@$(SLAVE.ANSSUFFIX)(@$SLAVE.BUS)_stb), // .@$(SLAVE.IANSI)@$(SLAVE.ANSPREFIX)we@$(SLAVE.ANSSUFFIX)(@$SLAVE.BUS)_we), // . // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include "../parser.h" #include "../mapdhash.h" #include "../keys.h" #include "../kveval.h" #include "../legalnotice.h" #include "../bldtestb.h" #include "../bitlib.h" #include "../plist.h" #include "../bldregdefs.h" #include "../ifdefs.h" #include "../bldsim.h" #include "../predicates.h" #include "../businfo.h" #include "../globals.h" #include "../subbus.h" #include "../msgs.h" #include "../genbus.h" #include "wb.h" #define PREFIX extern WBBUSCLASS wbclass; WBBUS::WBBUS(BUSINFO *bi) { // {{{ m_info = bi; m_slist = NULL; m_dlist = NULL; m_is_single = false; m_is_double = false; m_num_single = 0; m_num_double = 0; m_num_total = 0; } // }}} void WBBUS::allocate_subbus(void) { // {{{ PLIST *pl = m_info->m_plist; BUSINFO *sbi = NULL, *dbi = NULL; if (NULL == pl || pl->size() == 0) { gbl_msg.warning("Bus %s has no attached slaves\n", (name()) ? name()->c_str() : "(No-name)"); } gbl_msg.info("Generating WB bus logic generator for %s\n", (name()) ? name()->c_str() : "(No-name)"); countsio(); if (m_num_single == m_num_total) { m_num_single = 0; m_is_single = true; } else if ((m_num_single <= 2)&&(m_num_double > 0)) { m_num_double += m_num_single; m_num_single = 0; } if (!m_is_single && m_num_single + m_num_double == m_num_total) { m_num_double = 0; m_is_double = true; } else if (m_num_double <= 2) m_num_double = 0; assert(!m_is_single || !m_is_double); assert(m_num_single < 50); assert(m_num_double < 50); assert(m_num_total >= m_num_single + m_num_double); // // Master of multiple classes // if (!m_is_single && m_num_single > 0) { sbi = create_sio(); m_num_total++; } if (!m_is_double && m_num_double > 0) { m_num_total++; dbi = create_dio(); } if (!m_is_double && !m_is_single && pl) { // // There exist peripherals that are neither singles nor doubles // for(unsigned pi = 0; pi< pl->size(); pi++) { PERIPHP p = (*pl)[pi]; STRINGP ptyp; ptyp = getstring(p->p_phash, KYSLAVE_TYPE); if (m_slist && ptyp != NULL && ptyp->compare(KYSINGLE) == 0) { m_info->m_plist->erase(pl->begin()+pi); pi--; m_slist->add(p); } else if (m_dlist && ptyp != NULL && ptyp->compare(KYDOUBLE) == 0) { m_info->m_plist->erase(pl->begin()+pi); pi--; m_dlist->add(p); } else { // Leave this peripheral in m_info->m_plist } } } // countsio(); if (sbi) setstring(sbi->m_hash, KY_TYPE, wbclass.name()); if (dbi) setstring(dbi->m_hash, KY_TYPE, wbclass.name()); REHASH; } // }}} int WBBUS::address_width(void) { assert(m_info); return m_info->m_address_width; } bool WBBUS::get_base_address(MAPDHASH *phash, unsigned &base) { // {{{ if (!m_info || !m_info->m_plist) { gbl_msg.error("BUS[%s] has no peripherals!\n", (name()) ? name()->c_str() : "(No name)"); return false; } else return m_info->m_plist->get_base_address(phash, base); } // }}} void WBBUS::assign_addresses(void) { // {{{ int address_width; if (m_info->m_addresses_assigned) return; if ((NULL == m_slist)&&(NULL == m_dlist)) allocate_subbus(); if (!m_info) return; gbl_msg.info("WB: Assigning addresses for bus %s\n", (name()) ? name()->c_str() : "(No name bus)"); if (!m_info->m_plist||(m_info->m_plist->size() < 1)) { m_info->m_address_width = 0; } else if (!m_info->m_addresses_assigned) { int dw = m_info->data_width(), nullsz; if (m_slist) m_slist->assign_addresses(dw, 0); if (m_dlist) m_dlist->assign_addresses(dw, 0); if (!getvalue(*m_info->m_hash, KY_NULLSZ, nullsz)) nullsz = 0; m_info->m_plist->assign_addresses(dw, nullsz); address_width = m_info->m_plist->get_address_width(); m_info->m_address_width = address_width; if (m_info->m_hash) { setvalue(*m_info->m_hash, KY_AWID, m_info->m_address_width); REHASH; } } m_info->m_addresses_assigned = true; } // }}} BUSINFO *WBBUS::create_sio(void) { // {{{ assert(m_info); BUSINFO *sbi; SUBBUS *subp; STRINGP sioname; MAPDHASH *bushash, *shash; MAPT elm; sioname = new STRING(STRING("" PREFIX) + (*name()) + "_sio"); bushash = new MAPDHASH(); shash = new MAPDHASH(); setstring(*shash, KYPREFIX, sioname); setstring(*shash, KYSLAVE_TYPE, new STRING(KYDOUBLE)); setstring(*shash, KYSLAVE_PREFIX, sioname); elm.m_typ = MAPT_MAP; elm.u.m_m = bushash; shash->insert(KEYVALUE(KYSLAVE_BUS, elm)); elm.u.m_m = m_info->m_hash; shash->insert(KEYVALUE(KYMASTER_BUS, elm)); setstring(shash, KYMASTER_TYPE, KYARBITER); sbi = new BUSINFO(sioname); sbi->prefix(new STRING("_sio")); setstring(bushash, KY_TYPE, new STRING("wb")); sbi->m_data_width = m_info->m_data_width; sbi->m_clock = m_info->m_clock; sbi->addmaster(m_info->m_hash); subp = new SUBBUS(shash, sioname, sbi); subp->p_slave_bus = m_info; // subp->p_master_bus = set by the SUBBUS to be sbi m_info->m_plist->add(subp); assert(subp->p_master_bus); assert(subp->p_slave_bus == m_info); assert(subp->p_master_bus == sbi); // m_plist->integrity_check(); sbi->add(); m_slist = sbi->m_plist; return sbi; } // }}} BUSINFO *WBBUS::create_dio(void) { // {{{ assert(m_info); BUSINFO *dbi; SUBBUS *subp; STRINGP dioname; MAPDHASH *bushash, *shash; MAPT elm; dioname = new STRING(STRING("" PREFIX) + (*name()) + "_dio"); bushash = new MAPDHASH(); shash = new MAPDHASH(); setstring(*bushash, KY_NAME, dioname); setstring(*shash, KYPREFIX, dioname); setstring(*shash, KYSLAVE_TYPE, new STRING(KYOTHER)); setstring(*shash, KYSLAVE_PREFIX, dioname); elm.m_typ = MAPT_MAP; elm.u.m_m = m_info->m_hash; shash->insert(KEYVALUE(KYSLAVE_BUS, elm)); elm.u.m_m = bushash; shash->insert(KEYVALUE(KYMASTER_BUS, elm)); setstring(shash, KYMASTER_TYPE, KYARBITER); dbi = new BUSINFO(dioname); dbi->prefix(new STRING("_dio")); setstring(bushash, KY_TYPE, new STRING("wb")); assert(m_info->data_width() > 0); setvalue(*bushash, KY_WIDTH, m_info->data_width()); dbi->m_data_width = m_info->m_data_width; dbi->m_clock = m_info->m_clock; dbi->addmaster(m_info->m_hash); subp = new SUBBUS(shash, dioname, dbi); subp->p_slave_bus = m_info; m_info->m_plist->add(subp); assert(subp->p_master_bus); assert(subp->p_master_bus == dbi); assert(subp->p_slave_bus == m_info); // subp->p_master_bus = set by the slave to be dbi dbi->add(); m_dlist = dbi->m_plist; assert(isbusmaster(*shash)); assert(isarbiter(*shash)); return dbi; } // }}} void WBBUS::countsio(void) { // {{{ PLIST *pl = m_info->m_plist; STRINGP strp; m_num_single = 0; m_num_double = 0; m_num_total = 0; if (NULL == pl) return; for(unsigned pi=0; pi< pl->size(); pi++) { strp = getstring((*pl)[pi]->p_phash, KYSLAVE_TYPE); if (NULL != strp) { if (0==strp->compare(KYSINGLE)) { m_num_single++; } else if (0==strp->compare(KYDOUBLE)) { m_num_double++; } m_num_total++; } else m_num_total++; // Default to OTHER if no type is given } } // }}} void WBBUS::integrity_check(void) { // {{{ // GENBUS::integrity_check(); if (m_info && m_info->m_data_width <= 0) { gbl_msg.error("ERR: BUS width not defined for %s\n", name()->c_str()); } } // }}} void WBBUS::writeout_defn_v(FILE *fp, const char* pname, const char *pfx, const int aw, const int dw, const char *errwire, const char *btyp) { // {{{ STRINGP n = name(); fprintf(fp, "\t// Wishbone definitions for bus %s%s, component %s\n", n->c_str(), btyp, pname); fprintf(fp, "\t// Verilator lint_off UNUSED\n"); fprintf(fp, "\twire\t\t%s_cyc, %s_stb, %s_we;\n", pfx, pfx, pfx); fprintf(fp, "\twire\t[%d:0]\t%s_addr;\n", address_width()-1, pfx); fprintf(fp, "\twire\t[%d:0]\t%s_data;\n", dw-1, pfx); fprintf(fp, "\twire\t[%d:0]\t%s_sel;\n", dw/8-1, pfx); fprintf(fp, "\twire\t\t%s_stall, %s_ack, %s_err", pfx, pfx, pfx); if ((errwire)&&(errwire[0] != '\0') &&(STRING(STRING(pfx)+"_err").compare(errwire)!=0)) fprintf(fp, ", %s;\n" "\tassign\t\t%s_err = %s; // P\n", errwire, pfx, errwire); else fprintf(fp, ";\n"); fprintf(fp, "\twire\t[%d:0]\t%s_idata;\n", dw-1, pfx); fprintf(fp, "\t// Verilator lint_on UNUSED\n"); } // }}} void WBBUS::writeout_bus_slave_defns_v(FILE *fp) { // {{{ PLIST *p = m_info->m_plist; STRINGP n = name(); if (m_slist) { for(PLIST::iterator pp=m_slist->begin(); pp != m_slist->end(); pp++) { STRINGP errwire = getstring((*pp)->p_phash, KYERROR_WIRE); STRINGP prefix = (*pp)->bus_prefix(); writeout_defn_v(fp, (*pp)->p_name->c_str(), prefix->c_str(), 0, m_info->data_width(), (errwire)?errwire->c_str(): NULL, "(SIO)"); } } if (m_dlist) { for(PLIST::iterator pp=m_dlist->begin(); pp != m_dlist->end(); pp++) { STRINGP errwire = getstring((*pp)->p_phash, KYERROR_WIRE); STRINGP prefix = (*pp)->bus_prefix(); writeout_defn_v(fp, (*pp)->p_name->c_str(), prefix->c_str(), (*pp)->p_awid, m_info->data_width(), (errwire)?errwire->c_str(): NULL, "(DIO)"); } } if (p) { for(PLIST::iterator pp=p->begin(); pp != p->end(); pp++) { STRINGP errwire = getstring((*pp)->p_phash, KYERROR_WIRE); STRINGP prefix = (*pp)->bus_prefix(); writeout_defn_v(fp, (*pp)->p_name->c_str(), prefix->c_str(), (*pp)->p_awid, m_info->data_width(), (errwire) ? errwire->c_str() : NULL); } } else { gbl_msg.error("%s has no slaves\n", n->c_str()); } } // }}} void WBBUS::writeout_bus_master_defns_v(FILE *fp) { // {{{ MLIST *m = m_info->m_mlist; if (m) { for(MLIST::iterator pp=m->begin(); pp != m->end(); pp++) { writeout_defn_v(fp, (*pp)->name()->c_str(), (*pp)->bus_prefix()->c_str(), address_width(), m_info->data_width(), NULL); } } else { gbl_msg.warning("Bus %s has no masters\n", name()->c_str()); } } // }}} void WBBUS::write_addr_range(FILE *fp, const PERIPHP p, const int dalines) { // {{{ unsigned w = address_width(); w = (w+3)/4; if (p->p_naddr == 1) fprintf(fp, " // 0x%0*lx", w, p->p_base); else fprintf(fp, " // 0x%0*lx - 0x%0*lx", w, p->p_base, w, p->p_base + (p->p_naddr << (dalines))-1); } // }}} void WBBUS::writeout_bus_select_v(FILE *fp) { // {{{ #ifdef DEPRECATED_CODE // {{{ STRINGP n = name(); STRING addrbus = STRING((*n)+"_addr"); unsigned sbaw = address_width(); unsigned dw = m_info->data_width(); unsigned dalines = nextlg(dw/8); unsigned unused_lsbs = 0, mask = 0; PLIST *p = m_info->m_plist; if (NULL == p) { gbl_msg.error("Bus[%s] has no peripherals\n", n->c_str()); return; } fprintf(fp, "\t//\n\t//\n\t//\n\t// Select lines for bus: %s\n\t//\n", n->c_str()); fprintf(fp, "\t// Address width: %d\n", p->get_address_width()); fprintf(fp, "\t// Data width: %d\n\t//\n\t//\n\t\n", m_info->data_width()); if (m_slist) { sbaw = m_slist->get_address_width(); mask = 0; unused_lsbs = 0; for(unsigned i=0; isize(); i++) mask |= (*m_slist)[i]->p_mask; for(unsigned tmp=mask; ((tmp)&&((tmp&1)==0)); tmp>>=1) unused_lsbs++; for(unsigned i=0; isize(); i++) { if ((*m_slist)[i]->p_mask == 0) { fprintf(fp, "\tassign\t%12s_sel = 1\'b0; // ERR: (SIO) address mask == 0\n", (*m_slist)[i]->p_name->c_str()); } else { assert(sbaw > unused_lsbs); assert(sbaw > 0); fprintf(fp, "\tassign\t%12s_sel = ((" PREFIX "%s_sio_sel)&&(%s_addr[%2d:%2d] == %2d\'h%0*lx)); ", (*m_slist)[i]->p_name->c_str(), n->c_str(), n->c_str(), sbaw-1, unused_lsbs, sbaw-unused_lsbs, (sbaw-unused_lsbs+3)/4, (*m_slist)[i]->p_base >> (unused_lsbs+dalines)); write_addr_range(fp, (*m_slist)[i], dalines); fprintf(fp, "\n"); } } } if (m_dlist) { sbaw = m_dlist->get_address_width(); mask = 0; unused_lsbs = 0; for(unsigned i=0; isize(); i++) mask |= (*m_dlist)[i]->p_mask; for(unsigned tmp=mask; ((tmp)&&((tmp&1)==0)); tmp>>=1) unused_lsbs++; for(unsigned i=0; isize(); i++) { if ((*m_dlist)[i]->p_mask == 0) { fprintf(fp, "\tassign\t%12s_sel = 1\'b0; // ERR: (DIO) address mask == 0\n", (*m_dlist)[i]->p_name->c_str()); } else { assert(sbaw > unused_lsbs); assert(sbaw > 0); fprintf(fp, "\tassign\t%12s_sel " "= ((" PREFIX "%s_dio_sel)&&((%s[%2d:%2d] & %2d\'h%lx) == %2d\'h%0*lx)); ", (*m_dlist)[i]->p_name->c_str(), n->c_str(), addrbus.c_str(), sbaw-1, unused_lsbs, sbaw-unused_lsbs, (*m_dlist)[i]->p_mask >> unused_lsbs, sbaw-unused_lsbs, (sbaw-unused_lsbs+3)/4, (*m_dlist)[i]->p_base>>(dalines+unused_lsbs)); write_addr_range(fp, (*m_dlist)[i], dalines); fprintf(fp, "\n"); } } } sbaw = address_width(); mask = 0; unused_lsbs = 0; for(unsigned i=0; i< p->size(); i++) mask |= (*p)[i]->p_mask; for(unsigned tmp=mask; ((tmp)&&((tmp&1)==0)); tmp>>=1) unused_lsbs++; if (m_info->m_plist->size() == 1) { if ((*m_info->m_plist)[0]->p_name) fprintf(fp, "\tassign\t%12s_sel = (%s_cyc); " "// Only one peripheral on this bus\n", (*m_info->m_plist)[0]->p_name->c_str(), n->c_str()); } else for(unsigned i=0; i< m_info->m_plist->size(); i++) { PERIPHP p = (*m_info->m_plist)[i]; const char *pn = p->p_name->c_str(); if (pn) { if (p->p_mask == 0) { fprintf(fp, "\tassign\t%12s_sel = 1\'b0; // ERR: address mask == 0\n", pn); } else { assert(sbaw > unused_lsbs); assert(sbaw > 0); fprintf(fp, "\tassign\t%12s_sel " "= ((%s[%2d:%2d] & %2d\'h%lx) == %2d\'h%0*lx);", pn, addrbus.c_str(), sbaw-1, unused_lsbs, sbaw-unused_lsbs, p->p_mask >> unused_lsbs, sbaw-unused_lsbs, (sbaw-unused_lsbs+3)/4, p->p_base>>(dalines+unused_lsbs)); write_addr_range(fp, p, dalines); fprintf(fp, "\n"); } } if (p->p_master_bus) { fprintf(fp, "//x2\tWas a master bus as well\n"); } } fprintf(fp, "\t//\n\n"); // }}} #endif } // }}} void WBBUS::writeout_no_slave_v(FILE *fp, STRINGP prefix) { // {{{ STRINGP n = m_info->name(); fprintf(fp, "\n\t//\n"); fprintf(fp, "\t// In the case that there is no %s peripheral\n" "\t// responding on the %s bus\n", prefix->c_str(), n->c_str()); fprintf(fp, "\tassign\t%s_ack = 1\'b0;\n", prefix->c_str()); fprintf(fp, "\tassign\t%s_err = (%s_stb);\n", prefix->c_str(), prefix->c_str()); fprintf(fp, "\tassign\t%s_stall = 0;\n", prefix->c_str()); fprintf(fp, "\tassign\t%s_idata = 0;\n", prefix->c_str()); fprintf(fp, "\n"); } // }}} void WBBUS::writeout_no_master_v(FILE *fp) { // {{{ /* if (!m_info || !m_info->m_name) gbl_msg.error("(Unnamed bus) has no name!\n"); // PLIST *p = m_info->m_plist; STRINGP p = m_info->bus_prefix(); fprintf(fp, "\n"); fprintf(fp, "\t// In the case that nothing drives the %s bus ...\n", n->c_str()); fprintf(fp, "\tassign\t%s_cyc = 1\'b0;\n", n->c_str()); fprintf(fp, "\tassign\t%s_stb = 1\'b0;\n", n->c_str()); fprintf(fp, "\tassign\t%s_we = 1\'b0;\n", n->c_str()); fprintf(fp, "\tassign\t%s_sel = 0;\n", n->c_str()); fprintf(fp, "\tassign\t%s_addr= 0;\n", n->c_str()); fprintf(fp, "\tassign\t%s_data= 0;\n", n->c_str()); fprintf(fp, "\t// verilator lint_off UNUSED\n"); fprintf(fp, "\twire\t[%d:0]\tunused_bus_%s;\n", 3+m_info->data_width(), n->c_str()); fprintf(fp, "\tassign\tunused_bus_%s = " "{ %s_ack, %s_stall, %s_err, %s_data };\n", n->c_str(), n->c_str(), n->c_str(), n->c_str(), n->c_str()); fprintf(fp, "\t// verilator lint_on UNUSED\n"); fprintf(fp, "\n"); */ } // }}} // // Connect this master to the crossbar. Specifically, we want to output // a list of master connections to fill the given port. // void WBBUS::xbarcon_master(FILE *fp, const char *tabs, const char *pfx, const char *sig, bool comma) { // {{{ fprintf(fp, "%s%s({\n", tabs, pfx); for(unsigned k = m_info->m_mlist->size()-1; k>0; k--) { BMASTERP m = (*m_info->m_mlist)[k]; STRINGP busp = m->bus_prefix(); fprintf(fp, "%s\t%s_%s,\n", tabs, busp->c_str(), sig); } fprintf(fp, "%s\t%s_%s\n%s})%s\n", tabs, (*m_info->m_mlist)[0]->bus_prefix()->c_str(), sig, tabs, (comma) ? ",":""); } // }}} // // Output a list of connections to slave bus wires. Used in connecting the // slaves to the various crossbar inputs. // void WBBUS::xbarcon_slave(FILE *fp, PLIST *pl, const char *tabs, const char *pfx, const char *sig, bool comma) { // {{{ fprintf(fp, "%s%s({\n", tabs, pfx); for(unsigned k = pl->size()-1; k>0; k--) { PERIPHP p = (*pl)[k]; STRINGP busp = p->bus_prefix(); fprintf(fp, "%s\t%s_%s,\n", tabs, busp->c_str(), sig); } fprintf(fp, "%s\t%s_%s\n%s})%s\n", tabs, (*pl)[0]->bus_prefix()->c_str(), sig, tabs, (comma) ? ",":""); } // }}} void WBBUS::writeout_bus_logic_v(FILE *fp) { // {{{ STRINGP n = name(), rst; CLOCKINFO *c = m_info->m_clock; PLIST::iterator pp; PLISTP pl; unsigned unused_lsbs; if (NULL == m_info->m_plist) return; if (NULL == m_info->m_mlist) { gbl_msg.warning("No masters assigned to bus %s\n", n->c_str()); // return; } if (NULL == (rst = m_info->reset_wire())) { gbl_msg.warning("Bus %s has no associated reset wire, using \'i_reset\'\n", n->c_str()); rst = new STRING("i_reset"); setstring(m_info->m_hash, KY_RESET, rst); REHASH; } if (NULL == c || NULL == c->m_wire) { gbl_msg.fatal("Bus %s has no associated clock\n", n->c_str()); } if (m_info->m_plist->size() == 0) { fprintf(fp, "\t//\n" "\t// Bus %s has no slaves\n" "\t//\n\n", n->c_str()); // Since this bus has no slaves, any attempt to access it // needs to cause a bus error. // // Need to loop through all possible masters ... for(MLIST::iterator pp=m_info->m_mlist->begin(); pp != m_info->m_mlist->end(); pp++) { STRINGP pfx= (*pp)->bus_prefix(); const char *pfxc = pfx->c_str(); fprintf(fp, "\t//\n" "\t// Master %s has no slaves attached to its bus, %s\n" "\t//\n" "\t\tassign\t%s_err = %s_stb;\n" "\t\tassign\t%s_stall = 1\'b0;\n" "\t\tassign\t%s_ack = 1\'b0;\n" "\t\tassign\t%s_idata = 0;\n", pfxc, m_info->name()->c_str(), pfxc, pfxc, pfxc, pfxc, pfxc); } return; } else if (NULL == m_info->m_mlist || m_info->m_mlist->size() == 0) { for(unsigned p=0; p < m_info->m_plist->size(); p++) { STRINGP pstr = (*m_info->m_plist)[p]->bus_prefix(); fprintf(fp, "\t//\n" "\t// The %s bus has no masters assigned to it\n" "\t//\n" "\tassign %s_cyc = 1\'b0;\n" "\tassign %s_stb = 1\'b0;\n" "\tassign %s_we = 1\'b0;\n" "\tassign %s_addr= 0;\n" "\tassign %s_data= 0;\n" "\tassign %s_sel = 0;\n\n", pstr->c_str(), // pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str(), pstr->c_str()); } return; } else if ((m_info->m_plist->size() == 1)&&(m_info->m_mlist->size() == 1)) { MLIST::iterator mp = m_info->m_mlist->begin(); PLIST::iterator pp = m_info->m_plist->begin(); STRINGP strp; // Only one master connected to only one slave--skip all the // extra connection logic. // // Can only simplify if there's only one peripheral and only // one master // STRINGP slv = (*m_info->m_plist)[0]->bus_prefix(); STRINGP mstr = (*m_info->m_mlist)[0]->bus_prefix(); fprintf(fp, "//\n" "// Bus %s has only one master (%s) and one slave (%s)\n" "// connected to it -- skipping the interconnect\n" "//\n", n->c_str(), mstr->c_str(), slv->c_str()); fprintf(fp, "\tassign\t%s_cyc = %s_cyc;\n" "\tassign\t%s_stb = %s_stb;\n" "\tassign\t%s_we = %s_we;\n" "\tassign\t%s_addr = %s_addr;\n" "\tassign\t%s_data = %s_data;\n" "\tassign\t%s_sel = %s_sel;\n", (*pp)->bus_prefix()->c_str(), (*mp)->bus_prefix()->c_str(), (*pp)->bus_prefix()->c_str(), (*mp)->bus_prefix()->c_str(), (*pp)->bus_prefix()->c_str(), (*mp)->bus_prefix()->c_str(), (*pp)->bus_prefix()->c_str(), (*mp)->bus_prefix()->c_str(), (*pp)->bus_prefix()->c_str(), (*mp)->bus_prefix()->c_str(), (*pp)->bus_prefix()->c_str(), (*mp)->bus_prefix()->c_str()); if (NULL != (strp = getstring((*m_info->m_plist)[0]->p_phash, KYERROR_WIRE))) { if (strp->compare(STRING(STRING(*(*pp)->bus_prefix()) + STRING("_err"))) != 0) fprintf(fp, "\tassign\t%s_err = %s; // X\n", (*pp)->bus_prefix()->c_str(), strp->c_str()); } else fprintf(fp, "\tassign\t%s_err = 1\'b0;\n", (*pp)->bus_prefix()->c_str()); fprintf(fp, "\tassign\t%s_err = %s_err; // Y\n", (*mp)->bus_prefix()->c_str(), (*pp)->bus_prefix()->c_str()); fprintf(fp, "\tassign\t%s_stall = %s_stall;\n" "\tassign\t%s_ack = %s_ack;\n" "\tassign\t%s_idata = %s_idata;\n", (*mp)->bus_prefix()->c_str(), (*pp)->bus_prefix()->c_str(), (*mp)->bus_prefix()->c_str(), (*pp)->bus_prefix()->c_str(), (*mp)->bus_prefix()->c_str(), (*pp)->bus_prefix()->c_str()); return; } // Start with the slist if (m_slist) { STRING sio_bus_prefix = STRING(*m_info->name()) + "_sio"; STRINGP slp = &sio_bus_prefix; fprintf(fp, "\t//\n" "\t// %s Bus logic to handle SINGLE slaves\n" "\t//\n", n->c_str()); fprintf(fp, "\treg\t\t" PREFIX "r_%s_ack;\n", slp->c_str()); fprintf(fp, "\treg\t[%d:0]\t" PREFIX "r_%s_data;\n\n", m_info->data_width()-1, slp->c_str()); fprintf(fp, "\tassign\t" PREFIX "%s_stall = 1\'b0;\n\n", slp->c_str()); fprintf(fp, "\tinitial " PREFIX "r_%s_ack = 1\'b0;\n" "\talways\t@(posedge %s)\n" "\t\t" PREFIX "r_%s_ack <= (%s_stb);\n", slp->c_str(), c->m_wire->c_str(), slp->c_str(), slp->c_str()); fprintf(fp, "\tassign\t" PREFIX "%s_ack = " PREFIX "r_%s_ack;\n\n", slp->c_str(), slp->c_str()); unsigned mask = 0, lgdw; unused_lsbs = 0; for(unsigned k=0; ksize(); k++) { mask |= (*m_slist)[k]->p_mask; } for(unsigned tmp=mask; ((tmp!=0)&&((tmp & 1)==0)); tmp >>= 1) unused_lsbs++; lgdw = nextlg(m_info->data_width())-3; fprintf(fp, "\talways\t@(posedge %s)\n", c->m_wire->c_str()); // "\t\t// mask = %08x\n" // "\t\t// lgdw = %d\n" // "\t\t// unused_lsbs = %d\n" fprintf(fp, "\tcasez( %s_addr[%d:%d] )\n", // mask, lgdw, unused_lsbs, slp->c_str(), nextlg(mask)-1, unused_lsbs); for(unsigned j=0; jsize(); j++) { fprintf(fp, "\t%d'h%lx: " PREFIX "r_%s_data <= %s_idata;\n", nextlg(mask)-unused_lsbs, ((*m_slist)[j]->p_base) >> (unused_lsbs + lgdw), slp->c_str(), (*m_slist)[j]->bus_prefix()->c_str()); } if (m_slist->size() != (1u<size()))) { // We need a default option if (bus_option(KY_OPT_LOWPOWER)) { int v; STRINGP str; if (getvalue(*m_info->m_hash, KY_OPT_LOWPOWER, v)) fprintf(fp, "\tdefault: " PREFIX "r_%s_data <= (%d) ? 0 : %s_idata;\n", slp->c_str(), v, (*m_slist)[m_slist->size()-1]->bus_prefix()->c_str()); else { str = getstring(*m_info->m_hash, KY_OPT_LOWPOWER); fprintf(fp, "\tdefault: " PREFIX "r_%s_data <= (%s) ? 0 : %s_idata;\n", slp->c_str(), (str) ? str->c_str() : "1\'b0", (*m_slist)[m_slist->size()-1]->bus_prefix()->c_str()); } } else { fprintf(fp, "\tdefault: " PREFIX "r_%s_data <= %s_idata;\n", slp->c_str(), (*m_slist)[m_slist->size()-1]->bus_prefix()->c_str()); }} else { fprintf(fp, "\t// No default: SIZE = %d, [Guru meditation: %d != %d]\n", (int)m_slist->size(), (int)nextlg(m_slist->size()-1), (int)nextlg(m_slist->size())); } fprintf(fp, "\tendcase\n"); fprintf(fp, "\tassign\t" PREFIX "%s_idata = " PREFIX "r_%s_data;\n\n", slp->c_str(), slp->c_str()); fprintf(fp, "\n\t//\n" "\t// Now to translate this logic to the various SIO slaves\n\t//\n" "\t// In this case, the SIO bus has the prefix %s\n" "\t// and all of the slaves have various wires beginning\n" "\t// with their own respective bus prefixes.\n" "\t// Our goal here is to make certain that all of\n" "\t// the slave bus inputs match the SIO bus wires\n", slp->c_str()); unsigned sbaw; unsigned dw = m_info->data_width(); unsigned dalines = nextlg(dw/8); mask = 0; sbaw = m_slist->get_address_width(); for(unsigned j=0; jsize(); j++) { const char *pn = (*m_slist)[j]->bus_prefix()->c_str(); fprintf(fp, "\tassign\t%s_cyc = %s_cyc;\n", pn, slp->c_str()); if ((*m_slist)[j]->p_mask == 0) { fprintf(fp, "\tassign\t%s_stb = 1\'b0; // ERR: (SIO) address mask == 0\n", pn); } else { assert(sbaw > unused_lsbs); assert(sbaw > 0); fprintf(fp, "\tassign\t%s_stb = %s_stb " "&& (%s_addr[%2d:%2d] == %2d\'h%0*lx); ", pn, slp->c_str(), slp->c_str(), sbaw-1, unused_lsbs, sbaw-unused_lsbs, (sbaw-unused_lsbs+3)/4, (*m_slist)[j]->p_base >> (unused_lsbs+dalines)); write_addr_range(fp, (*m_slist)[j], dalines); fprintf(fp, "\n"); } fprintf(fp, "\tassign\t%s_we = %s_we;\n" "\tassign\t%s_data= %s_data;\n" "\tassign\t%s_sel = %s_sel;\n", pn, slp->c_str(), pn, slp->c_str(), pn, slp->c_str()); } } else fprintf(fp, "\t//\n\t// No class SINGLE peripherals on the \"%s\" bus\n\t//\n\n", n->c_str()); // Then the dlist if (m_dlist) { STRING dio_bus_prefix = STRING(*m_info->name()) + "_dio"; STRINGP dlp = &dio_bus_prefix; fprintf(fp, "\t//\n" "\t// %s Bus logic to handle %ld DOUBLE slaves\n" "\t//\n" "\t//\n", n->c_str(), m_dlist->size()); unsigned mask = 0, lgdw, maskbits; unused_lsbs = 0; for(unsigned k=0; ksize(); k++) { mask |= (*m_dlist)[k]->p_mask; } for(unsigned tmp=mask; ((tmp!=0)&&((tmp & 1)==0)); tmp >>= 1) unused_lsbs++; maskbits = nextlg(mask)-unused_lsbs; if (maskbits < 1) maskbits=1; // lgdw is the log of the data width in bytes. We require it // here because the bus addresses words rather than the bytes // within them lgdw = nextlg(m_info->data_width())-3; fprintf(fp, "\treg\t[1:0]\t" PREFIX "r_%s_ack;\n", dlp->c_str()); fprintf(fp, "\t// # dlist = %d, nextlg(#dlist) = %d\n", (int)m_dlist->size(), nextlg(m_dlist->size())); fprintf(fp, "\treg\t[%d:0]\t" PREFIX "r_%s_bus_select;\n", nextlg((int)m_dlist->size())-1, dlp->c_str()); fprintf(fp, "\treg\t[%d:0]\t" PREFIX "r_%s_data;\n", m_info->data_width()-1, dlp->c_str()); fprintf(fp, "\n"); // // The stall line fprintf(fp, "\t// DOUBLE peripherals are not allowed to stall.\n" "\tassign\t" PREFIX "%s_stall = 1\'b0;\n\n", dlp->c_str()); // // The ACK line fprintf(fp, "\t// DOUBLE peripherals return their acknowledgments in two\n" "\t// clocks--always, allowing us to collect this logic together\n" "\t// in a slave independent manner. Here, the acknowledgment\n" "\t// is treated as a two stage shift register, cleared on any\n" "\t// reset, or any time the cycle line drops. (Dropping the\n" "\t// cycle line aborts the transaction.)\n" "\tinitial\t" PREFIX "r_%s_ack = 0;\n" "\talways\t@(posedge %s)\n" "\tif (%s || !%s_cyc)\n", dlp->c_str(), c->m_wire->c_str(), rst->c_str(), dlp->c_str()); fprintf(fp, "\t\t" PREFIX "r_%s_ack <= 0;\n" "\telse\n" "\t\t" PREFIX "r_%s_ack <= { " PREFIX "r_%s_ack[0], (%s_stb) };\n", dlp->c_str(), dlp->c_str(), dlp->c_str(), dlp->c_str()); fprintf(fp, "\tassign\t" PREFIX "%s_ack = " PREFIX "r_%s_ack[1];\n", dlp->c_str(), dlp->c_str()); fprintf(fp, "\n"); // // The data return lines // fprintf(fp, "\t// Since it costs us two clocks to go through this\n" "\t// logic, we'll take one of those clocks here to set\n" "\t// a selection index, and then on the next clock we'll\n" "\t// use this index to select from among the vaious\n" "\t// possible bus return values\n" "\talways @(posedge %s)\n" "\tcasez(%s_addr[%d:%d])\n", c->m_wire->c_str(), dlp->c_str(), maskbits+unused_lsbs-1, unused_lsbs); for(unsigned k=0; ksize(); k++) { fprintf(fp, "\t%d'b", maskbits); for(unsigned b=0; bp_mask & (1<p_base & (1<<(shift+lgdw))) fprintf(fp, "1"); else fprintf(fp, "0"); if ((shift > lgdw)&&(((shift-lgdw)&3)==0) &&(bc_str(), nextlg(m_dlist->size()), k); } fprintf(fp, "\tdefault: " PREFIX "r_%s_bus_select <= 0;\n", dlp->c_str()); fprintf(fp, "\tendcase\n\n"); fprintf(fp, "\talways\t@(posedge %s)\n" "\tcasez(" PREFIX "r_%s_bus_select)\n", c->m_wire->c_str(), dlp->c_str()); for(unsigned k=0; ksize(); k++) { fprintf(fp, "\t%d'd%d", nextlg(m_dlist->size()), k); fprintf(fp, ": " PREFIX "r_%s_data <= %s_idata;\n", dlp->c_str(), (*m_dlist)[k]->bus_prefix()->c_str()); } if ((1u<size())) != m_dlist->size()) { // Only place the default value into the case if there // are empty values there. if (bus_option(KY_OPT_LOWPOWER)) { fprintf(fp, "\tdefault: " PREFIX "r_%s_data <= 0;\n", dlp->c_str()); } else fprintf(fp, "\tdefault: " PREFIX "r_%s_data <= %s_idata;\n", dlp->c_str(), (*m_dlist)[m_dlist->size()-1]->bus_prefix()->c_str()); } fprintf(fp, "\tendcase\n\n"); fprintf(fp, "\tassign\t" PREFIX "%s_idata = " PREFIX "r_%s_data;\n\n", dlp->c_str(), dlp->c_str()); // // Connect the dio bus wires together to send to the various // slave buses the dio bus drives // unsigned sbaw; unsigned dw = m_info->data_width(); unsigned dalines = nextlg(dw/8); mask = 0; sbaw = m_dlist->get_address_width(); for(unsigned j=0; jsize(); j++) { const char *pn = (*m_dlist)[j]->bus_prefix()->c_str(); fprintf(fp, "\tassign\t%s_cyc = %s_cyc;\n", pn, dlp->c_str()); if ((*m_dlist)[j]->p_mask == 0) { fprintf(fp, "\tassign\t%s_stb = 1\'b0; // ERR: (DIO) address mask == 0\n", pn); } else { assert(sbaw > unused_lsbs); assert(sbaw > 0); fprintf(fp, "\tassign\t%s_stb = %s_stb " "&& ((%s_addr[%2d:%2d] & %2d\'h%0*lx) == %2d\'h%0*lx); ", pn, dlp->c_str(), dlp->c_str(), // Relevant address bits sbaw-1, unused_lsbs, // // Mask bits sbaw-unused_lsbs, (sbaw-unused_lsbs+3)/4, (*m_dlist)[j]->p_mask >> unused_lsbs, // sbaw-unused_lsbs, (sbaw-unused_lsbs+3)/4, (*m_dlist)[j]->p_base >> (unused_lsbs+dalines)); write_addr_range(fp, (*m_dlist)[j], dalines); fprintf(fp, "\n"); } fprintf(fp, "\tassign\t%s_we = %s_we;\n" "\tassign\t%s_addr= %s_addr;\n" "\tassign\t%s_data= %s_data;\n" "\tassign\t%s_sel = %s_sel;\n", pn, dlp->c_str(), pn, dlp->c_str(), pn, dlp->c_str(), pn, dlp->c_str()); } } else fprintf(fp, "\t//\n\t// No class DOUBLE peripherals on the \"%s\" bus\n\t//\n\n", n->c_str()); // // // Now for the main set of slaves // // unsigned slave_name_width = 4; // Find the maximum width of any slaves name, for our comment tables // below for(unsigned k=0; km_plist->size(); k++) { PERIPHP p = (*m_info->m_plist)[k]; unsigned sz; sz = p->name()->size(); if (slave_name_width < sz) slave_name_width = sz; } // // First make certain any slaves that cannot produce error wires // can define // for(unsigned k=0; km_plist->size(); k++) { PERIPHP p = (*m_info->m_plist)[k]; const char *pn = (*m_info->m_plist)[k]->bus_prefix()->c_str(); STRINGP err; if (NULL != (err = getstring(p->p_phash, KYERROR_WIRE))) { STRING buserr = STRING(pn) + STRING("_err"); if (buserr.compare(*err) == 0) { fprintf(fp, "\t// info: @ERROR.WIRE for %s " "matches the buses error name, " "%s_err\n", p->name()->c_str(), pn); } else { fprintf(fp, "\t// info: @ERROR.WIRE %s != %s\n", err->c_str(), pn); fprintf(fp, "\t// info: @ERROR.WIRE for %s, = %s, doesn\'t match the buses wire %s_err\n", p->name()->c_str(), err->c_str(), pn); fprintf(fp, "\tassign\t%s_err = %s; // Z\n", pn, err->c_str()); } } else fprintf(fp, "\tassign\t%s_err= 1\'b0;\n", pn); } // // Now create the crossbar interconnect // fprintf(fp, "\t//\n" "\t// Connect the %s bus components together using the wbxbar()\n" "\t//\n" "\t//\n", n->c_str()); unused_lsbs = nextlg(m_info->data_width())-3; fprintf(fp, "\twbxbar #(\n" "\t\t.NM(%ld), .NS(%ld), .AW(%d), .DW(%d),\n", m_info->m_mlist->size(), m_info->m_plist->size(), address_width(), m_info->data_width()); slave_addr(fp, m_info->m_plist, unused_lsbs); fprintf(fp, ",\n"); slave_mask(fp, m_info->m_plist, unused_lsbs); xbar_option(fp, KY_OPT_LOWPOWER, ",\n\t\t.OPT_LOWPOWER(%)"); xbar_option(fp, KY_OPT_LGMAXBURST, ",\n\t\t.LGNMAXBURST(%)"); xbar_option(fp, KY_OPT_TIMEOUT, ",\n\t\t.OPT_TIMEOUT(%)"); xbar_option(fp, KY_OPT_DBLBUFFER, ",\n\t\t.OPT_DBLBUFFER(%)", "1\'b1"); // OPT_STARVATION_TIMEOUT? fprintf(fp, ")\n\t%s_xbar(\n" "\t\t.i_clk(%s), .i_reset(%s),\n", n->c_str(), c->m_wire->c_str(), rst->c_str()); xbarcon_master(fp, "\t\t", ".i_mcyc", "cyc"); xbarcon_master(fp, "\t\t", ".i_mstb", "stb"); xbarcon_master(fp, "\t\t", ".i_mwe", "we"); xbarcon_master(fp, "\t\t", ".i_maddr", "addr"); xbarcon_master(fp, "\t\t", ".i_mdata", "data"); xbarcon_master(fp, "\t\t", ".i_msel", "sel"); xbarcon_master(fp, "\t\t", ".o_mstall","stall"); xbarcon_master(fp, "\t\t", ".o_mack", "ack"); xbarcon_master(fp, "\t\t", ".o_mdata", "idata"); xbarcon_master(fp, "\t\t", ".o_merr", "err"); fprintf(fp, "\t\t// Slave connections\n"); pl = m_info->m_plist; xbarcon_slave(fp, pl, "\t\t", ".o_scyc", "cyc"); xbarcon_slave(fp, pl, "\t\t", ".o_sstb", "stb"); xbarcon_slave(fp, pl, "\t\t", ".o_swe", "we"); xbarcon_slave(fp, pl, "\t\t", ".o_saddr", "addr"); xbarcon_slave(fp, pl, "\t\t", ".o_sdata", "data"); xbarcon_slave(fp, pl, "\t\t", ".o_ssel", "sel"); xbarcon_slave(fp, pl, "\t\t", ".i_sstall","stall"); xbarcon_slave(fp, pl, "\t\t", ".i_sack", "ack"); xbarcon_slave(fp, pl, "\t\t", ".i_sdata", "idata"); xbarcon_slave(fp, pl, "\t\t", ".i_serr", "err", false); fprintf(fp, "\t\t);\n\n"); } // }}} STRINGP WBBUS::master_portlist(BMASTERP) { // {{{ return new STRING( "@$(MASTER.PREFIX)_cyc, " "@$(MASTER.PREFIX)_stb, " "@$(MASTER.PREFIX)_we,\n" "\t\t\t@$(MASTER.PREFIX)_addr[@$(MASTER.BUS.AWID)-1:0],\n" "\t\t\t@$(MASTER.PREFIX)_data, // @$(MASTER.BUS.WIDTH) bits wide\n" "\t\t\t@$(MASTER.PREFIX)_sel, // @$(MASTER.BUS.WIDTH)/8 bits wide\n" "\t\t@$(MASTER.PREFIX)_stall, " "@$(MASTER.PREFIX)_ack, " "@$(MASTER.PREFIX)_idata," "@$(MASTER.PREFIX)_err"); } // }}} STRINGP WBBUS::iansi(BMASTERP) { return new STRING("i_"); } STRINGP WBBUS::oansi(BMASTERP) { return new STRING("o_"); } STRINGP WBBUS::master_ansprefix(BMASTERP) { return new STRING("wb_"); } STRINGP WBBUS::master_ansi_portlist(BMASTERP) { // {{{ return new STRING( ".@$(OANSI)@$(MASTER.ANSPREFIX)cyc(@$(MASTER.PREFIX)_cyc), " ".@$(OANSI)@$(MASTER.ANSPREFIX)stb(@$(MASTER.PREFIX)_stb), " ".@$(OANSI)@$(MASTER.ANSPREFIX)we(@$(MASTER.PREFIX)_we),\n" "\t\t\t.@$(OANSI)@$(MASTER.ANSPREFIX)addr(@$(MASTER.PREFIX)_addr[@$(MASTER.BUS.AWID)-1:0]),\n" "\t\t\t.@$(OANSI)@$(MASTER.ANSPREFIX)data(@$(MASTER.PREFIX)_data), // @$(MASTER.BUS.WIDTH) bits wide\n" "\t\t\t.@$(OANSI)@$(MASTER.ANSPREFIX)sel(@$(MASTER.PREFIX)_sel), // @$(MASTER.BUS.WIDTH)/8 bits wide\n" "\t\t.@$(IANSI)@$(MASTER.ANSPREFIX)stall(@$(MASTER.PREFIX)_stall), " ".@$(IANSI)@$(MASTER.ANSPREFIX)ack(@$(MASTER.PREFIX)_ack), " ".@$(IANSI)@$(MASTER.ANSPREFIX)data(@$(MASTER.PREFIX)_idata), " ".@$(IANSI)@$(MASTER.ANSPREFIX)err(@$(MASTER.PREFIX)_err)"); } // }}} STRINGP WBBUS::slave_ansprefix(PERIPHP p) { return new STRING("wb_"); } STRINGP WBBUS::slave_portlist(PERIPHP p) { // {{{ STRINGP errp = getstring(p->p_phash, KYERROR_WIRE); STRING str = STRING( "@$(SLAVE.PREFIX)_cyc, " "@$(SLAVE.PREFIX)_stb,"); if (!p->read_only() && !p->write_only()) str = str + STRING(" @$(SLAVE.PREFIX)_we,"); str = str + STRING("\n"); if (p->get_slave_address_width() > 0) { char tmp[64]; STRING stmp; sprintf(tmp, "_addr[%d-1:0],\n", p->get_slave_address_width()); stmp = STRING("\t\t\t@$(SLAVE.PREFIX)") + STRING(tmp); str = str + stmp; } if (!p->read_only()) str = str + STRING( "\t\t\t@$(SLAVE.PREFIX)_data, // @$(SLAVE.BUS.WIDTH) bits wide\n" "\t\t\t@$(SLAVE.PREFIX)_sel, // @$(SLAVE.BUS.WIDTH)/8 bits wide\n"); str = str + STRING( "\t\t@$(SLAVE.PREFIX)_stall, @$(SLAVE.PREFIX)_ack"); if (!p->write_only()) str = str + STRING(", @$(SLAVE.PREFIX)_idata"); if (NULL != errp) str = str + STRING(", @$(SLAVE.PREFIX)_err"); return new STRING(str); } // }}} STRINGP WBBUS::slave_ansi_portlist(PERIPHP p) { // {{{ STRINGP errp = getstring(p->p_phash, KYERROR_WIRE); STRING str = STRING( ".@$(IANSI)@$(SLAVE.ANSPREFIX)cyc(@$(SLAVE.PREFIX)_cyc), " ".@$(IANSI)@$(SLAVE.ANSPREFIX)stb(@$(SLAVE.PREFIX)_stb), "); if (!p->read_only() && !p->write_only()) str = str + STRING(".@$(IANSI)@$(SLAVE.ANSPREFIX)we(@$(SLAVE.PREFIX)_we),\n"); if (p->get_slave_address_width() > 0) { char tmp[64]; STRING stmp; sprintf(tmp, "_addr[%d-1:0]),\n", p->get_slave_address_width()); stmp = STRING("\t\t\t.@$(IANSI)@$(SLAVE.ANSPREFIX)addr(@$(SLAVE.PREFIX)") + STRING(tmp); str = str + stmp; } if (!p->read_only()) str = str + STRING( "\t\t\t.@$(IANSI)@$(SLAVE.ANSPREFIX)data(@$(SLAVE.PREFIX)_data), // @$(SLAVE.BUS.WIDTH) bits wide\n" "\t\t\t.@$(IANSI)@$(SLAVE.ANSPREFIX)sel(@$(SLAVE.PREFIX)_sel), // @$(SLAVE.BUS.WIDTH)/8 bits wide\n"); str = str + STRING( "\t\t.@$(OANSI)@$(SLAVE.ANSPREFIX)stall(@$(SLAVE.PREFIX)_stall)," ".@$(OANSI)@$(SLAVE.ANSPREFIX)ack(@$(SLAVE.PREFIX)_ack)"); if (!p->write_only()) str = str + STRING(", .@$(OANSI)@$(SLAVE.ANSPREFIX)data(@$(SLAVE.PREFIX)_idata)"); if (NULL != errp) str = str + STRING(", .@$(OANSI)@$(SLAVE.ANSPREFIX)err(@$(SLAVE.PREFIX)_err)"); return new STRING(str); } // }}} //////////////////////////////////////////////////////////////////////// // // Bus class logic // // The bus class describes the logic above in a way that it can be // chosen, selected, and enacted within a design. Hence if a design // has four wishbone buses and one AXI-lite bus, the bus class logic // will recognize the four WB buses and generate WB bus generators, // and then an AXI-lite bus and bus generator, etc. // //////////////////////////////////////////////////////////////////////// STRINGP WBBUSCLASS::name(void) { return new STRING("wb"); } STRINGP WBBUSCLASS::longname(void) { return new STRING("Wishbone"); } bool WBBUSCLASS::matchtype(STRINGP str) { if (!str) // Wishbone is the default type return true; if (str->compare("wb")==0) return true; if (str->compare("wbp")==0) return true; // printf("ERR: No match for bus type %s\n",str->c_str()); return false; } bool WBBUSCLASS::matchfail(MAPDHASH *bhash) { return false; } GENBUS *WBBUSCLASS::create(BUSINFO *bi) { WBBUS *busclass; busclass = new WBBUS(bi); return busclass; } ================================================ FILE: sw/bus/wb.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/bus/wb.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef WB_H #define WB_H #include "../genbus.h" class WBBUS : public GENBUS { PLIST *m_slist, *m_dlist; unsigned m_num_total, m_num_double, m_num_single; bool m_is_single, m_is_double; void xbarcon_master(FILE *fp, const char *, const char *, const char *, bool comma = true); void xbarcon_slave(FILE *fp, PLIST *pl, const char *, const char *, const char *, bool comma = true); void allocate_subbus(void); BUSINFO *create_sio(void); BUSINFO *create_dio(void); void countsio(void); public: WBBUS(BUSINFO *bi); ~WBBUS() {}; virtual int address_width(void); // virtual void assign_addresses(void); virtual bool word_addressing(void) { return true; }; virtual bool get_base_address(MAPDHASH *phash, unsigned &base); void write_addr_range(FILE *fp, const PERIPHP p, const int dalines); virtual void writeout_defn_v(FILE *fp, const char *pname, const char *pfx, const int aw, const int dw, const char *ewire, const char *btyp = ""); virtual void writeout_bus_slave_defns_v(FILE *fp); virtual void writeout_bus_master_defns_v(FILE *fp); virtual void writeout_bus_select_v(FILE *fp); virtual void writeout_bus_logic_v(FILE *fp); virtual void writeout_no_slave_v(FILE *fp, STRINGP prefix); virtual void writeout_no_master_v(FILE *fp); // // virtual STRINGP iansi(BMASTERP); virtual STRINGP oansi(BMASTERP); virtual STRINGP master_ansprefix(BMASTERP); virtual STRINGP master_portlist(BMASTERP); virtual STRINGP master_ansi_portlist(BMASTERP); virtual STRINGP slave_ansprefix(PERIPHP); virtual STRINGP slave_portlist(PERIPHP); virtual STRINGP slave_ansi_portlist(PERIPHP); virtual void integrity_check(void); }; class WBBUSCLASS : public BUSCLASS { public: virtual STRINGP name(void); // i.e. WB virtual STRINGP longname(void); // i.e. "Wishbone" virtual bool matchtype(STRINGP strp); virtual bool matchfail(MAPDHASH *); // virtual bool matches(BUSINFO *bi); GENBUS *create(BUSINFO *bi); }; #endif ================================================ FILE: sw/businfo.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/businfo.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: The businfo structure is a generic object describing a bus // (in general) and all the properties associated with it. It is // used by the specific bus logic drivers (in bus/*) to know how much // address space, or data width is used by the bus, or what masters and // slaves are connected to the bus. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include "parser.h" #include "mapdhash.h" #include "keys.h" #include "kveval.h" #include "legalnotice.h" #include "bldtestb.h" #include "bitlib.h" #include "plist.h" #include "bldregdefs.h" #include "ifdefs.h" #include "bldsim.h" #include "predicates.h" #include "businfo.h" #include "globals.h" #include "subbus.h" #include "msgs.h" #include "clockinfo.h" BUSLIST *gbl_blist; #define PREFIX // Look up the number of bits in the address bus of the given hash int BUSINFO::address_width(void) { if (!m_addresses_assigned) assign_addresses(); return generator()->address_width(); } bool BUSINFO::word_addressing(void) { assert(m_genbus); return m_genbus->word_addressing(); } int BUSINFO::data_width(void) { int value; if ((m_hash)&&(getvalue(m_hash, KY_WIDTH, value))) { m_data_width = value; } if (m_data_width > 0) return m_data_width; return 32; } STRINGP BUSINFO::name(void) { STRINGP str; str = getstring(m_hash, KY_NAME); if (!m_name) m_name = str; else if (str->compare(*m_name) != 0) { gbl_msg.error("Bus name %s has changed to %s\n", m_name->c_str(), str->c_str()); m_name = str; } return str; } STRINGP BUSINFO::prefix(STRINGP p) { STRINGP hash_prefix; hash_prefix = getstring(m_hash, KYPREFIX); if (!p) return hash_prefix; if (NULL == hash_prefix && NULL != p) { setstring(m_hash, KYPREFIX, p); hash_prefix = p; } else if (p && hash_prefix->compare(*p) != 0) gbl_msg.error("Renaming bus %s with a second prefix", name()); return hash_prefix; } STRINGP BUSINFO::btype(void) { STRINGP str; str = getstring(m_hash, KY_TYPE); if (!m_type) m_type = str; else if (str->compare(*m_type) != 0) { gbl_msg.error("Bus %s type has changed from %s to %s\n", name()->c_str(), m_type->c_str(), str->c_str()); m_type = str; } return str; } STRINGP BUSINFO::reset_wire(void) { STRINGP str; str = getstring(m_hash, KY_RESET); if (NULL != str) return str; if (m_clock) str = getstring(m_clock->m_hash, KY_RESET); return str; } bool BUSINFO::get_base_address(MAPDHASH *phash, unsigned &base) { if (!generator()) { gbl_msg.error("BUS[%s] has no type\n", m_name->c_str()); return false; } else return generator()->get_base_address(phash, base); } void BUSINFO::assign_addresses(void) { if (!generator()) gbl_msg.fatal("Bus %s has no generator type defined\n", m_name->c_str()); gbl_msg.info("BI: Assigning addresses for bus %s\n", m_name->c_str()); generator()->assign_addresses(); if (m_mlist) for(unsigned k=0; ksize(); k++) { // Set the bus prefix for the master STRINGP mname; MAPDHASH *hash = (*m_mlist)[k]->m_hash; mname = (*m_mlist)[k]->name(); gbl_msg.info("BI: Assigning portlists for bus %s, " "master %s\n", m_name->c_str(), (mname) ? mname->c_str() : " (No-name)"); (*m_mlist)[k]->bus_prefix(); setstring(hash, KYMASTER_PORTLIST, generator()->master_portlist((*m_mlist)[k])); setstring(hash, KYMASTER_ANSIPORTLIST, generator()->master_ansi_portlist((*m_mlist)[k])); if (!getstring(hash, KYMASTER_IANSI)) setstring(hash, KYMASTER_IANSI, generator()->iansi((*m_mlist)[k])); if (!getstring(hash, KYMASTER_OANSI)) setstring(hash, KYMASTER_OANSI, generator()->oansi((*m_mlist)[k])); if (!getstring(hash, KYMASTER_ANSPREFIX)) setstring(hash, KYMASTER_ANSPREFIX, generator()->master_ansprefix((*m_mlist)[k])); REHASH; } m_addresses_assigned = true; } void BUSINFO::add(void) { if (!m_plist) { m_plist = new PLIST; m_plist->integrity_check(); } } PERIPH *BUSINFO::add(PERIPHP p) { int pi; PLISTP plist; if (!m_plist) m_plist = new PLIST(); else m_plist->integrity_check(); plist = m_plist; pi = plist->add(p); m_addresses_assigned = false; plist->integrity_check(); if (pi >= 0) { p = (*plist)[pi]; p->p_slave_bus = this; assert(NULL != p->p_phash); return p; } else { gbl_msg.fatal("Could not add %s\n", getstring(p->p_phash, KYPREFIX)->c_str()); return NULL; } } PERIPH *BUSINFO::add(MAPDHASH *phash) { PERIPH *p; int pi; PLISTP plist; if (!m_plist) m_plist = new PLIST(); plist = m_plist; assert(plist); pi = plist->add(phash); if (pi >= 0) { p = (*plist)[pi]; p->p_slave_bus = this; return p; } else { gbl_msg.error("Could not add %s\n", getstring(phash, KYPREFIX)->c_str()); return NULL; } } bool BUSINFO::need_translator(BUSINFO *m) { // If they are the same bus, then no translator is necessary if ((m==NULL)||(this == m)) return false; if (m_name->compare(*m->m_name)==0) return false; // If they are of different clocks, then a translator is required if ((m_clock)&&(m->m_clock)&&(m_clock != m->m_clock)) return true; // If they are of different widths if ((m_data_width)&&(m->m_data_width) &&(m_data_width != m->m_data_width)) return true; // If they are of different bus types if ((m_type)&&(m->m_type) &&(m_type->compare(*m->m_type) != 0)) return true; // // return false; } PERIPHP BUSINFO::operator[](unsigned k) { unsigned idx = k; if (idx < m_plist->size()) return (*m_plist)[idx]; return NULL; } unsigned BUSINFO::size(void) { unsigned sz = m_plist->size(); return sz; } void BUSINFO::init(MAPDHASH *bushash) { m_hash = bushash; m_name = getstring(m_hash, KY_NAME); if (!getvalue(m_hash, KY_WIDTH, m_data_width)) m_data_width = 0; else { setvalue(*m_hash, KY_NSELECT, (m_data_width+7)/8); } if (!getvalue(m_hash, KY_NULLSZ, m_nullsz)) m_nullsz = 0; if (getstring(m_hash, KY_TYPE)) generator(); } void BUSINFO::init(STRINGP bname) { m_hash = new MAPDHASH(); setstring(m_hash, KY_NAME, bname); m_name = getstring(m_hash, KY_NAME); } // void BUSINFO::merge(STRINGP src, MAPDHASH *hash) { // // Merge description of bus from multiple disparate sources // // Set name, prefix, type, clock, nullsz, data width // // } void BUSINFO::merge(STRINGP component, MAPDHASH *bp) { // Component is the name of the component with this bus reference // bp is the pointer to the BUS reference from within this component // int value; MAPT elm; STRINGP strp; for(MAPDHASH::iterator kvpair=bp->begin(); kvpair != bp->end(); kvpair++) { if (0 == KY_WIDTH.compare(kvpair->first)) { if (getvalue(*bp, KY_WIDTH, value)) { if (m_data_width <= 0) { m_data_width = value; // elm.m_typ = MAPT_INT; elm.u.m_v = value; m_hash->insert(KEYVALUE(KY_WIDTH, elm)); gbl_msg.info("Setting bus width for %s bus to %d, in %s\n", m_name->c_str(), value, component->c_str()); // Calculate the number of select lines elm.m_typ = MAPT_INT; elm.u.m_v = (value+7)/8; m_hash->insert(KEYVALUE(KY_NSELECT, elm)); REHASH; kvpair = bp->begin(); } else if (m_data_width != value) { gbl_msg.error("Conflicting bus width definitions for %s: %d != %d in %s\n", m_name->c_str(), m_data_width, value, component->c_str()); } } continue; } if (0== KY_NULLSZ.compare(kvpair->first)) { if ((getvalue(*bp, KY_NULLSZ, value))&&(m_nullsz != value)) { gbl_msg.info("BUSINFO::INIT(%s).NULLSZ " "FOUND: %d\n", component->c_str(), value); m_nullsz = (value > m_nullsz) ? value : m_nullsz; // m_addresses_assigned = false; // elm.m_typ = MAPT_INT; elm.u.m_v = value; m_hash->insert(KEYVALUE(KY_NULLSZ, elm)); REHASH; kvpair = bp->begin(); } continue; } if (0== KY_IDWIDTH.compare(kvpair->first)) { if (0 != getvalue(*bp, KY_IDWIDTH, value)) { MAPDHASH::iterator kvprev; gbl_msg.info("BUSINFO::INIT(%s).IDWIDTH " "FOUND: %d\n", component->c_str(), value); if (m_hash->end() == (kvprev = findkey(*m_hash, KY_IDWIDTH))){ elm.m_typ = MAPT_INT; elm.u.m_v = value; m_hash->insert(KEYVALUE(KY_IDWIDTH, elm)); REHASH; kvpair = bp->begin(); } else if (kvprev->second.m_typ != MAPT_INT){ gbl_msg.info("BUSINFO::INIT(%s).IDWIDTH not an integer??\n", component->c_str()); } else if (kvprev->second.u.m_v != value) { gbl_msg.error("BUSINFO::INIT(%s).IDWIDTH has conflicting values, %d and %d\n", component->c_str(), value, kvprev->second.u.m_v); } } continue; } if ((MAPT_STRING == kvpair->second.m_typ) &&(NULL != kvpair->second.u.m_s)) { strp = kvpair->second.u.m_s; gbl_msg.info("BUSINFO::MERGE(%s) @%s=%s\n", component->c_str(), kvpair->first.c_str(), kvpair->second.u.m_s->c_str()); if (0 == KY_TYPE.compare(kvpair->first)) { if (m_type == NULL) { m_type = strp; elm.m_typ = MAPT_STRING; elm.u.m_s = strp; if (NULL == m_hash) { gbl_msg.error("Undefined bus as a part of %s (no name given?)\n", component->c_str()); } else m_hash->insert(KEYVALUE(KY_TYPE, elm)); REHASH; kvpair = bp->begin(); } else if (m_type->compare(*strp) != 0) { gbl_msg.error("Conflicting bus types " "for %s\n",m_name->c_str()); gbl_msg.info("First bus type: %s\n", m_type->c_str()); gbl_msg.info("New bus type: %s\n", strp->c_str()); } continue; } else if (0 == KY_RESET.compare(kvpair->first)) { STRINGP reset = getstring(m_hash, KY_RESET); if (reset == NULL) { elm.m_typ = MAPT_STRING; elm.u.m_s = strp; m_hash->insert(KEYVALUE(KY_RESET, elm)); REHASH; kvpair = bp->begin(); } else if (reset->compare(*strp) != 0) { gbl_msg.error("Conflicting bus resets " "for %s\n",m_name->c_str()); } continue; } else if ((0 == KY_CLOCK.compare(kvpair->first)) &&(NULL == m_clock)) { gbl_msg.info("BUSINFO::INIT(%s)." "CLOCK(%s)\n", component->c_str(), strp->c_str()); assert(strp); m_clock = getclockinfo(strp); if (m_clock == NULL) m_clock = CLOCKINFO::new_clock(kvpair->second.u.m_s); gbl_msg.info("BUSINFO::INIT(%s)." "CLOCK(%s) FOUND, FREQ = %d\n", component->c_str(), strp->c_str(), m_clock->frequency()); elm.m_typ = MAPT_MAP; elm.u.m_m = m_clock->m_hash; if (NULL == m_hash) { gbl_msg.error("Undefined bus as a part of %s (no name given?)\n", component->c_str()); } else m_hash->insert(KEYVALUE(KY_CLOCK, elm)); kvpair->second.m_typ = MAPT_MAP; kvpair->second.u.m_m = m_clock->m_hash; REHASH; kvpair = bp->begin(); continue; } } /* // We should really allow a clock *definition* here, rather // than just a reference // else if ((kvpair->second.m_typ == MAPT_MAP) &&(NULL != kvpair->second.u.m_m)) { if ((KY_CLOCK.compare(kvpair->first)==0) &&(NULL == m_clock)) ; } */ // Anything else, we copy into our defining hash if ((bp != m_hash)&&(m_hash->end() != findkey(*m_hash, kvpair->first))) { m_hash->insert(*kvpair); // REHASH; } } } STRINGP BUSINFO::slave_portlist(PERIPHP p) { if (!generator()) return NULL; return generator()->slave_portlist(p); } STRINGP BUSINFO::slave_iansi(PERIPHP p) { if (!generator()) return NULL; return generator()->iansi(NULL); } STRINGP BUSINFO::slave_oansi(PERIPHP p) { if (!generator()) return NULL; return generator()->oansi(NULL); } STRINGP BUSINFO::slave_ansprefix(PERIPHP p) { if (!generator()) return NULL; return generator()->slave_ansprefix(p); } STRINGP BUSINFO::slave_ansi_portlist(PERIPHP p) { if (!generator()) return NULL; return generator()->slave_ansi_portlist(p); } STRINGP BUSINFO::master_portlist(BMASTERP b) { if (!generator()) return NULL; return generator()->master_portlist(b); } STRINGP BUSINFO::master_ansi_portlist(BMASTERP b) { if (!generator()) return NULL; return generator()->master_ansi_portlist(b); } void BUSINFO::integrity_check(void) { if (!m_name) { gbl_msg.error("Bus with no name! (No BUS.NAME tag)\n"); return; } if (m_data_width <= 0) { gbl_msg.error("BUS width not defined for %s\n", m_name->c_str()); } if (m_clock == NULL) { gbl_msg.error("BUS %s has no defined clock\n", m_name->c_str()); } } bool need_translator(BUSINFO *s, BUSINFO *m) { if (!s) return false; return s->need_translator(m); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // // Operations on sets of buses (i.e. vectors of BUSINFO) // //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// BUSINFO *BUSLIST::find_bus_of_peripheral(MAPDHASH *phash) { assert(NULL != phash); for(iterator bp=begin(); bp!=end(); bp++) { if ((*bp)->ismember_of(phash)) return (*bp); } return NULL; } BUSINFO *find_bus_of_peripheral(MAPDHASH *phash) { return gbl_blist->find_bus_of_peripheral(phash); } BUSINFO *BUSLIST::find_bus(MAPDHASH *hash) { if (!hash) { if ((*this)[0]) return ((*this)[0]); return NULL; } for(unsigned k=0; km_hash)&&(hash == (*this)[k]->m_hash)) { return (*this)[k]; } } return NULL; } BUSINFO *find_bus(MAPDHASH *hash) { return gbl_blist->find_bus(hash); } BUSINFO *BUSLIST::find_bus(STRINGP name) { // If no name is given, return the default bus if (NULL == name) { if ((*this)[0]) return ((*this)[0]); return NULL; } for(unsigned k=0; kname()) &&((*this)[k]->name()->compare(*name)==0)) { return (*this)[k]; } } return NULL; } BUSINFO *find_bus(STRINGP name) { return gbl_blist->find_bus(name); } unsigned BUSLIST::get_base_address(MAPDHASH *phash) { unsigned base; // Assume everything has only one address, and that the first // address is the one we want for(unsigned i=0; iget_base_address(phash, base)) return base; return 0; } void BUSLIST::addperipheral(MAPDHASH *phash) { STRINGP pname; BUSINFO *bi; // Ignore everything that isn't a bus slave if (NULL == getmap(*phash, KYSLAVE)) return; if (NULL == (pname = getstring(*phash, KYPREFIX))) pname = new STRING("(Unnamed-P)"); gbl_msg.info("Adding peripheral %s to bus %s\n", pname->c_str(), (getstring(phash, KYSLAVE_BUS_NAME) ? getstring(phash, KYSLAVE_BUS_NAME)->c_str() : "(Unnamed)")); // Insist on the existence of a default bus assert((*this)[0]); MAPDHASH::iterator kvpair, kvbus; kvpair = findkey(*phash, KYSLAVE_BUS); if (kvpair == phash->end()) { bi = (*this)[0]; } else if (kvpair->second.m_typ == MAPT_STRING) { // If this peripheral is on a named bus, point us to it. bi = find_bus(kvpair->second.u.m_s); // Insist, though, that the named bus exist already assert(bi); } else if (kvpair->second.m_typ == MAPT_MAP) { bi = find_bus(kvpair->second.u.m_m); if (bi == NULL) { MAPDHASH *blmap = kvpair->second.u.m_m; for(kvbus = blmap->begin(); kvbus != blmap->end(); kvbus++) { if (kvbus->second.m_typ != MAPT_MAP) continue; bi = find_bus(kvbus->second.u.m_m); if (NULL == bi) continue; bi->add(phash); } return; } assert(bi); } // Now that we know what bus this peripheral attaches to, add it in assert(bi); bi->add(phash); assert(bi->m_plist); bi->m_plist->integrity_check(); } void BUSLIST::addperipheral(MAPT &map) { if (map.m_typ == MAPT_MAP) addperipheral(map.u.m_m); } void BUSLIST::addmaster(MAPDHASH *phash) { // STRINGP mname; BUSINFO *bi; // Ignore everything that isn't a bus slave if (NULL == getmap(*phash, KYMASTER)) return; /* if (NULL == (mname = getstring(*phash, KYPREFIX))) mname = new STRING("(Unnamed-M)"); */ // Insist on the existence of a default bus assert((*this)[0]); MAPDHASH::iterator kvpair, kvbus; kvpair = findkey(*phash, KYMASTER_BUS); if (kvpair == phash->end()) { // // We have a MASTER tag with no MASTER.BUS tag // // Make this the default bus // bi = (*this)[0]; } else if (kvpair->second.m_typ == MAPT_STRING) { // // MASTER.BUS= // // If this peripheral is on a named bus, point us to it. bi = find_bus(kvpair->second.u.m_s); // Insist, though, that the named bus exist already assert(bi); gbl_msg.error("MASTER.BUS string shouldn't be here"); } else if (kvpair->second.m_typ == MAPT_MAP) { bi = find_bus(kvpair->second.u.m_m); if (bi == NULL) { MAPDHASH *blmap = kvpair->second.u.m_m; for(kvbus = blmap->begin(); kvbus != blmap->end(); kvbus++) { if (kvbus->second.m_typ != MAPT_MAP) continue; bi = find_bus(kvbus->second.u.m_m); if (NULL == bi) continue; bi->addmaster(phash); } return; } assert(bi); } // Now that we know what bus this peripheral attaches to, add it in assert(bi); bi->addmaster(phash); assert(bi->m_mlist); // // bi->m_mlist->integrity_check(); } void BUSLIST::addmaster(MAPT &map) { if (map.m_typ == MAPT_MAP) addmaster(map.u.m_m); } void BUSLIST::adddefault(MAPDHASH &master, STRINGP defname) { BUSINFO *bi; if (size() == 0) { // If there are no elements (yet) in our BUSLIST, then create // a first one, and call it our default. push_back(bi = new BUSINFO()); bi->m_hash = new MAPDHASH(); setstring(*bi->m_hash, KY_NAME, defname); } else { // if (size() > 0) // // If there are already busses in our bus list, shuffle them // so that the bus named defname is the first. // if (NULL != (bi = find_bus(defname))) { // This bus already exists for(unsigned k=0; kname()) &&((*this)[k]->name()->compare(*defname)==0)) { if (k == 0) return; // If it's not the zero bus, // move it to the zero position BUSINFO *bi = (*this)[0]; (*this)[0] = (*this)[k]; (*this)[k] = bi; return; } } } else if ((*this)[0]->name()) { // The bus doesn't exist, although others do if ((*this)[0]->name()->compare(*defname)!=0) { // Create a new BUSINFO struct for // this new one push_back((*this)[0]); (*this)[0] = bi = new BUSINFO(); bi->m_hash = new MAPDHASH(); setstring(*bi->m_hash, KY_NAME, defname); } // else this is already the default } else { // First spot exists, but has no name bi = (*this)[0]; setstring(*bi->m_hash, KY_NAME, defname); } } } BUSINFO *BUSLIST::newbus_aux(STRINGP component, MAPDHASH *bp) { if (NULL == bp) return NULL; STRINGP str; BUSINFO *bi; str = getstring(*bp, KY_NAME); if (str) { bi = find_bus(str); if (!bi) { MAPDHASH::iterator kvpair; bi = new BUSINFO(); push_back(bi); bi->init(bp); gbl_msg.userinfo("Bus: %s\n", str->c_str()); } else { // We need to merge the BUS-MAP into the existing // one bi->merge(component, bp); // We don't need to initialize a new bus, so just // return } } else if (size() > 0) { // A default bus exists, add to that bi = (*this)[0]; bi->merge(component, bp); } else { bi = new BUSINFO(); push_back(bi); bi->init(bp); } return bi; } BUSINFO *BUSLIST::newbus_aux(STRINGP component, STRINGP bn) { if (NULL == bn) return NULL; BUSINFO *bi; bi = find_bus(bn); if (!bi) { MAPDHASH::iterator kvpair; bi = new BUSINFO(); push_back(bi); bi->init(bn); gbl_msg.userinfo("BUS: %s (from %s)\n", bn->c_str(), (component) ? component->c_str() : "(Unnamed component)"); } return bi; } void BUSLIST::addbus(STRINGP cname, STRINGP bname) { (void)newbus_aux(cname, bname); } void BUSLIST::addbus(STRINGP cname, MAPDHASH *bhash) { STRINGP bname; BUSINFO *bi; bname = getstring(bhash, KY_NAME); if (bname == NULL) // Bus is un-named--won't happen here return; bi = find_bus(bname); if (!bi) bi = newbus_aux(cname, bhash); // This includes the merge else bi->merge(cname, bhash); } void BUSLIST::addbus(STRINGP cname, MAPT &map) { if (map.m_typ == MAPT_MAP) addbus(cname, map.u.m_m); } // // assign_addresses // // Assign addresses to all of our peripherals, given a first address to start // from. The first address helps to insure that the NULL address creates a // proper error (as it should). // void assign_addresses(void) { fprintf(stderr, "MASTER--> ASSIGN ADDRESSES\n"); for(unsigned i=0; isize(); i++) (*gbl_blist)[i]->assign_addresses(); } void BUSINFO::writeout_bus_defns_v(FILE *fp) { if (!generator()) gbl_msg.error("No bus type defined for bus %s\n", name()->c_str()); generator()->writeout_bus_defns_v(fp); } void writeout_bus_defns_v(FILE *fp) { fprintf(fp, "\t////////////////////////////////////////////////////////////////////////\n" "\t//\n" "\t// Declare bus signals\n" "\t// {{{\n" "\t////////////////////////////////////////////////////////////////////////\n\n"); BUSLIST *bl = gbl_blist; for(BUSLIST::iterator bp=bl->begin(); bp != bl->end(); bp++) { fprintf(fp, "\t// Bus %s\n\t// {{{\n", (*bp)->name()->c_str()); (*bp)->writeout_bus_defns_v(fp); fprintf(fp, "\t// }}}\n"); } fprintf(fp, "\t// }}}\n"); } void BUSINFO::writeout_no_slave_v(FILE *fp, STRINGP prefix) { if (!generator()) gbl_msg.error("No slaves assigned to bus %s\n", name()->c_str()); else generator()->writeout_no_slave_v(fp, prefix); } void BUSINFO::writeout_no_master_v(FILE *fp) { if (!generator()) gbl_msg.error("No slaves assigned to bus %s\n", (name()) ? name()->c_str() : "(Unnamed-bus)"); else generator()->writeout_no_master_v(fp); } bool BUSINFO::ismember_of(MAPDHASH *phash) { if (m_plist == NULL) return false; for(unsigned i=0; isize(); i++) if ((*m_plist)[i]->p_phash == phash) return true; return false; } void BUSINFO::writeout_bus_logic_v(FILE *fp) { if (!generator()) gbl_msg.error("No slaves assigned to bus %s\n", name()->c_str()); else generator()->writeout_bus_logic_v(fp); } void writeout_bus_logic_v(FILE *fp) { for(unsigned i=0; isize(); i++) { fprintf(fp, "\t//\n\t// BUS-LOGIC for %s\n\t// {{{\n", (*gbl_blist)[i]->name()->c_str()); (*gbl_blist)[i]->writeout_bus_logic_v(fp); fprintf(fp, "\t// End of bus logic for %s\n" "\t// }}}\n", (*gbl_blist)[i]->name()->c_str()); } } void assign_bus_slave(MAPDHASH &master, MAPDHASH *bus_slave) { MAPDHASH::iterator sbus; BUSINFO *bi; STRINGP pname, strp; MAPDHASH *shash; pname = getstring(*bus_slave, KYPREFIX); if (pname == NULL) pname = new STRING("(Null)"); shash = getmap(*bus_slave, KYSLAVE); if (NULL == shash) return; sbus = findkey(*shash, KYBUS); if (sbus == shash->end()) { // // No SLAVE.BUS tag // } else if (sbus->second.m_typ == MAPT_STRING) { // // SLAVE.BUS = bus_name // BUSINFO *bi; char *cstr, *tok, *nxt; const char *DELIMITERS=", \t\r\n"; strp = sbus->second.u.m_s; cstr = strdup(strp->c_str()); // Allow only one bus name tok = strtok(cstr, DELIMITERS); nxt = strtok(NULL, DELIMITERS); if ((tok)&&(!nxt)) { bi = gbl_blist->find_bus(strp); if (NULL == bi) { // Buses should've been found and enumerated // already gbl_msg.error("BUS %s not found in %s\n", tok, pname->c_str()); } else { // // Replace the bus name with the bus map sbus->second.m_typ = MAPT_MAP; sbus->second.u.m_m = bi->m_hash; } } else gbl_msg.error("TAG %s does not specify a bus name\n", strp->c_str()); free(cstr); } else if (sbus->second.m_typ == MAPT_MAP) { // // SLAVE.BUS.NAME = bus_name // if (NULL == (strp = getstring(*sbus->second.u.m_m, KY_NAME))) { gbl_msg.error("%s SLAVE.BUS " "exists, is a map, but has no name\n", pname->c_str()); } else if (NULL == (bi = find_bus(strp))) { gbl_msg.error("%s SLAVE.BUS.NAME " "exists, is a map, but no there\'s no bus named %s\n", pname->c_str(), strp->c_str()); } else if ((bi->m_hash != sbus->second.u.m_m) &&(strp->compare(*bi->name())==0)) { bi->merge(pname, sbus->second.u.m_m); sbus->second.u.m_m = bi->m_hash; } } else { gbl_msg.error("%s SLAVE.BUS exists, but isn't a string!\n", pname->c_str()); } } void assign_bus_master(MAPDHASH &master, MAPDHASH *bus_master) { MAPDHASH::iterator mbus; BUSINFO *bi; STRINGP pname, strp; MAPDHASH *mhash; pname = getstring(*bus_master, KYPREFIX); if (pname == NULL) pname = new STRING("(Null)"); mhash = getmap(*bus_master, KYMASTER); if (NULL == mhash) return; mbus = findkey(*mhash, KYBUS); if (mbus == mhash->end()) { // // No MASTER.BUS tag // } else if (mbus->second.m_typ == MAPT_STRING) { // // MASTER.BUS = bus_name // char *cstr, *tok, *nxt; const char *DELIMITERS=", \t\r\n"; strp = mbus->second.u.m_s; cstr = strdup(strp->c_str()); // Allow only one bus name tok = strtok(cstr, DELIMITERS); nxt = (tok) ? strtok(NULL, DELIMITERS) : NULL; if ((tok)&&(!nxt)) { STRING tokstr = tok; bi = gbl_blist->find_bus(&tokstr); if (NULL == bi) { gbl_msg.error("BUS %s not found in %s\n", tok, pname->c_str()); } else { // // Replace the bus name with the bus hash mbus->second.m_typ = MAPT_MAP; mbus->second.u.m_m = bi->m_hash; } reeval(master); } free(cstr); } else if (mbus->second.m_typ == MAPT_MAP) { // // MASTER.BUS.NAME = bus_name if (NULL == (strp = getstring(*mbus->second.u.m_m, KY_NAME))) { gbl_msg.error("%s MASTER.BUS " "exists, is a map, but has no name\n", pname->c_str()); } else if (NULL == (bi = find_bus(strp))) { gbl_msg.error("%s MASTER.BUS.NAME " "exists, is a map, but there\'s no bus named %s\n", pname->c_str(), strp->c_str()); } else if ((bi->m_hash != mbus->second.u.m_m) &&(strp->compare(*bi->name())==0)) { bi->merge(pname, mbus->second.u.m_m); mbus->second.u.m_m = bi->m_hash; } } else { gbl_msg.error("%s MASTER.BUS exists, but isn't a string!\n", pname->c_str()); } } GENBUS *BUSINFO::generator(void) { bool found= false; if (NULL == m_genbus) { for(unsigned tst=0; tstmatches(this)) { found = true; m_genbus = busclass_list[tst]->create(this); break; } } if (!found) { gbl_msg.fatal("No bus logic generator found for bus %s " "of type %s\n", name()->c_str(), getstring(m_hash, KY_TYPE) ? getstring(m_hash, KY_TYPE)->c_str() : "(None)"); } } return m_genbus; } void BUSLIST::assign_bus_types(void) { if (num_bus_classes == 0) gbl_msg.warning("No bus classes defined!\n"); for(unsigned k = 0; k < size(); k++) { bool found= false; for(unsigned tst=0; tstm_name->c_str()); if (busclass_list[tst]->matches((*this)[k])) { found = true; (*this)[k]->generator(); // = busclass_list[tst]->create((*this)[k]); break; } // printf("No match to class, %s %s\n", (*this)[k]->m_name->c_str(), busclass_list[tst]->name()->c_str()); } if (!found) { gbl_msg.error("No bus logic generator found for bus %s\n", (*this)[k]->name()->c_str()); } } } void BUSLIST::checkforbusdefns(STRINGP prefix, MAPDHASH *map, const STRING &key) { MAPDHASH::iterator busp; STRINGP bname; BUSINFO *bi; if (map->end() != (busp = findkey(*map, key))) { if (busp->second.m_typ == MAPT_MAP) { addbus(prefix, busp->second.u.m_m); bname = getstring(busp->second.u.m_m, KY_NAME); if (bname == NULL) { gbl_msg.error("Bus tag in %s without a bus name\n", (prefix) ? prefix->c_str() : "(No name)"); return; } bi = find_bus(bname); if (bi == NULL) { gbl_msg.error("Just created bus %s, and can\'t find it now\n", bname->c_str()); } busp->second.u.m_m = bi->m_hash; } else if (busp->second.m_typ == MAPT_STRING) { addbus(prefix, busp->second.u.m_s); busp->second.m_typ = MAPT_MAP; busp->second.u.m_m = find_bus(busp->second.u.m_s)->m_hash; assert(busp->second.u.m_m); } } } bool gbl_ready_for_address_assignment = false; void build_bus_list(MAPDHASH &master) { MAPDHASH::iterator kvpair, kvaccess, kvsearch; BUSLIST *bl = new BUSLIST; STRINGP str; gbl_blist = bl; gbl_msg.info("------------ BUILD-BUS-LIST------------\n"); if (NULL != (str = getstring(master, KYDEFAULT_BUS))) { bl->adddefault(master, str); } // if (refbus(master)) { STRING cname = "toplevel"; MAPDHASH *mp; gbl_msg.info("Adding a refbus (master)\n"); if (NULL != (mp = getmap(*kvpair->second.u.m_m, KYBUS))) bl->addbus(&cname, mp); } // for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { STRINGP prefix; if (kvpair->second.m_typ != MAPT_MAP) continue; prefix = getstring(kvpair->second.u.m_m, KYPREFIX); // // First check for any of the three possible bus maps // bl->checkforbusdefns(prefix, kvpair->second.u.m_m, KYBUS); bl->checkforbusdefns(prefix, kvpair->second.u.m_m, KYSLAVE_BUS); bl->checkforbusdefns(prefix, kvpair->second.u.m_m, KYMASTER_BUS); } // Make certain every bus has an appropriate logic generator for(unsigned k=0; ksize(); k++) (*bl)[k]->generator(); // Let's now go back through our components, and create a SLAVE.BUS // and (possibly) a MASTER.BUS tags for each component. for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (isbusmaster(kvpair->second)) { assign_bus_master(master, kvpair->second.u.m_m); } if (isperipheral(kvpair->second)) { assign_bus_slave(master, kvpair->second.u.m_m); } } reeval(master); // Set any unset clocks to the default for(BUSLIST::iterator bp=bl->begin(); bp != bl->end(); bp++) { if (NULL == (*bp)->m_clock) { MAPDHASH *map; if (NULL != (str = getstring((*bp)->m_hash, KYCLOCK))) { (*bp)->m_clock = getclockinfo(str); MAPDHASH::iterator kvclock; kvclock = findkey(*(*bp)->m_hash, KYCLOCK); assert((*bp)->m_hash->end() != kvclock); kvclock->second.m_typ = MAPT_MAP; kvclock->second.u.m_m = (*bp)->m_clock->m_hash; } else if (NULL != (map = getmap((*bp)->m_hash, KYCLOCK))) { (*bp)->m_clock = getclockinfo(getstring(map, KY_NAME)); MAPDHASH::iterator kvclock; kvclock = findkey(*(*bp)->m_hash, KYCLOCK); assert((*bp)->m_hash->end() != kvclock); kvclock->second.m_typ = MAPT_MAP; kvclock->second.u.m_m = (*bp)->m_clock->m_hash; } else { gbl_msg.fatal("Bus %s has no defined clock\n", (*bp)->name()->c_str()); (*bp)->m_clock = getclockinfo(NULL); assert((*bp)->m_hash); setstring((*bp)->m_hash, KYCLOCK, (*bp)->m_clock->m_name); } } } for(BUSLIST::iterator bp=bl->begin(); bp != bl->end(); bp++) (*bp)->integrity_check(); // // for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (isperipheral(kvpair->second)) bl->addperipheral(kvpair->second); if (isbusmaster(kvpair->second)) bl->addmaster(kvpair->second); } reeval(master); bl->assign_bus_types(); gbl_ready_for_address_assignment = true; for(unsigned i=0; i< bl->size(); i++) { (*bl)[i]->assign_addresses(); reeval(master); } reeval(master); } // #define DUMP_BUS_TREE #ifdef DUMP_BUS_TREE void BUSINFO::dump_bus_tree(int tab=0) { gbl_msg.info("%*sDUMP BUS-TREE: %s\n", tab, "", b_name->c_str()); for(m_plist::iterator pp=m_plist->begin(); pp != m_plist->end(); pp++) { gbl_msg.info("%*s%s\n", tab+1, "", (*pp)->p_name->c_str()); if (issubbus((*pp)->p_phash)) (*pp)->p_master_bus->dump_bus_tree(tab+1); } } void dump_global_buslist(void) { find_bus(0)->dump_bus_tree(0); } #endif ================================================ FILE: sw/businfo.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/businfo.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef BUSINFO_H #define BUSINFO_H #include #include #include #include #include class BUSINFO; class GENBUS; #include "parser.h" #include "mapdhash.h" #include "plist.h" #include "mlist.h" #include "clockinfo.h" #include "keys.h" #include "bitlib.h" #include "genbus.h" class BUSINFO { GENBUS *m_genbus; // Bus logic generator int m_nullsz; STRINGP m_name; public: // List of peripherals on the bus PLISTP m_plist; // List of bus masters MLISTP m_mlist; // STRINGP m_type; CLOCKINFO *m_clock; // , *m_bhash; MAPDHASH *m_hash; int m_data_width, m_address_width; bool m_addresses_assigned; BUSINFO(void) { // MAPDHASH *hash) // m_bhash = hash; m_plist = NULL; m_mlist = NULL; m_name = NULL; m_type = NULL; m_clock = NULL; m_hash = NULL; m_genbus = NULL; m_nullsz = 0; m_data_width = 0; m_addresses_assigned = false; m_address_width = 0; } BUSINFO(STRINGP name) { m_plist = NULL; m_mlist = NULL; m_name = name; m_type = NULL; m_clock = NULL; m_hash = new MAPDHASH(); m_genbus = NULL; m_nullsz = 0; m_data_width = 0; m_addresses_assigned = false; m_address_width = 0; setstring(m_hash, KY_NAME, name); } bool need_translator(BUSINFO *b); bool get_base_address(MAPDHASH *phash, unsigned &base); int word_address_width(void) { if (word_addressing()) return address_width(); else return address_width() - nextlg(data_width()/8); } int byte_address_width(void) { if (word_addressing()) return address_width() + nextlg(data_width()/8); else return address_width(); } bool word_addressing(void); void assign_addresses(void); int address_width(void); int data_width(void); void add(void); PERIPH *add(PERIPHP p); PERIPH *add(MAPDHASH *phash); void addmaster(MAPDHASH *hash) { if (!m_mlist) m_mlist = new MLIST(); BMASTERP bp = new BMASTER(hash); m_mlist->push_back(bp); } void writeout_bus_slave_defns_v(FILE *fp); void writeout_bus_master_defns_v(FILE *fp); void writeout_bus_defns_v(FILE *fp); void writeout_bus_logic_v(FILE *fp); void writeout_no_slave_v(FILE *fp, STRINGP prefix); void writeout_no_master_v(FILE *fp); PERIPHP operator[](unsigned i); unsigned size(void); void init(MAPDHASH *phash); void init(STRINGP bname); void merge(STRINGP component, MAPDHASH *hash); void integrity_check(void); bool ismember_of(MAPDHASH *phash); STRINGP name(void); STRINGP prefix(STRINGP p = NULL); STRINGP btype(void); STRINGP reset_wire(void); STRINGP slave_iansi(PERIPHP); STRINGP slave_oansi(PERIPHP); STRINGP slave_ansprefix(PERIPHP); STRINGP slave_portlist(PERIPHP); STRINGP slave_ansi_portlist(PERIPHP); STRINGP master_portlist(BMASTERP); STRINGP master_ansi_portlist(BMASTERP); GENBUS *generator(void); // Bus logic generator }; class BUSLIST : public std::vector { public: BUSINFO *find_bus(STRINGP name); BUSINFO *find_bus(MAPDHASH *hash); unsigned get_base_address(MAPDHASH *phash); void addperipheral(MAPDHASH *phash); void addperipheral(MAPT &map); void addmaster(MAPDHASH *phash); void addmaster(MAPT &map); void adddefault(MAPDHASH &master, STRINGP defname); BUSINFO *newbus_aux(STRINGP cname, MAPDHASH *bp); BUSINFO *newbus_aux(STRINGP cname, STRINGP bn); void addbus(STRINGP cname, STRINGP busname); void addbus(STRINGP cname, MAPDHASH *phash); void addbus(STRINGP cname, MAPT &map); // void countsio(MAPDHASH *phash); // void countsio(MAPT &map); BUSINFO *find_bus_of_peripheral(MAPDHASH *phash); void assign_bus_types(void); void checkforbusdefns(STRINGP, MAPDHASH *, const STRING &); }; extern void build_bus_list(MAPDHASH &master); extern BUSINFO *find_bus_of_peripheral(MAPDHASH *phash); extern BUSINFO *find_bus(MAPDHASH *hash); extern BUSINFO *find_bus(STRINGP name); extern bool need_translator(BUSINFO *a, BUSINFO *b); extern void writeout_bus_defns_v(FILE *fp); extern void writeout_bus_select_v(FILE *fp); extern void writeout_bus_logic_v(FILE *fp); #endif // BUSINFO_H ================================================ FILE: sw/clockinfo.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/clockinfo.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Captures the information associated with a clock in a fashion // that can cross the entire design. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include "parser.h" #include "mapdhash.h" #include "keys.h" #include "bldtestb.h" #include "legalnotice.h" #include "clockinfo.h" #include "globals.h" #include "msgs.h" const unsigned long CLOCKINFO::UNKNOWN_PS = 2ul; const unsigned long CLOCKINFO::PICOSECONDS_PER_SECOND = 1000000000000ul; CLKLIST cklist; CLOCKINFO::CLOCKINFO(void) { m_hash = new MAPDHASH(); m_name = NULL; m_reset = NULL; m_wire = NULL; m_top = NULL; m_simclass = NULL; m_interval_ps = UNKNOWN_PS; } CLOCKINFO *CLOCKINFO::new_clock(STRINGP name) { CLOCKINFO *ci; if (NULL != (ci = getclockinfo(name))) return ci; unsigned id = cklist.size(); cklist.push_back(CLOCKINFO()); ci = &cklist[id]; ci->setname(new STRING(*name)); return ci; } unsigned long CLOCKINFO::setfrequency(unsigned long frequency_hz) { if (frequency_hz != 0l) { unsigned long ps; setvalue(*m_hash, KY_FREQUENCY, (int)frequency_hz); ps = PICOSECONDS_PER_SECOND / (unsigned long)frequency_hz; m_interval_ps = ps; return m_interval_ps; } else if (m_interval_ps != UNKNOWN_PS) return m_interval_ps; return 0l; } unsigned CLOCKINFO::frequency(void) { double v = 1e12 / m_interval_ps; return (unsigned)v; } void CLOCKINFO::setname(STRINGP name) { STRINGP strp; strp = getstring(*m_hash, KY_NAME); if (NULL == strp) { setstring(*m_hash, KY_NAME, name); m_name = name; } else if (strp->compare(*name) != 0) { fprintf(stderr, "ERR: Clock with multiple names: %s and %s\n", strp->c_str(), name->c_str()); m_name = strp; } else if (!m_name) m_name = name; } STRINGP CLOCKINFO::reset(void) { STRINGP strp; strp = getstring(*m_hash, KY_RESET); return strp; } void CLOCKINFO::setwire(STRINGP wire) { STRINGP strp; strp = getstring(*m_hash, KY_WIRE); if (NULL == strp) { setstring(*m_hash, KY_WIRE, wire); m_wire = wire; } else if (strp->compare(*wire) != 0) { fprintf(stderr, "ERR: Clock with multiple wire ID\'s: %s and %s\n", strp->c_str(), wire->c_str()); m_wire = strp; } else if (!m_wire) { // Case #3: This is a new WIRE tag MAPT subfm; subfm.m_typ = MAPT_STRING; subfm.u.m_s = wire; m_hash->insert(KEYVALUE(KY_WIRE, subfm)); m_wire = wire; } } void CLOCKINFO::settop(STRINGP top) { STRINGP strp; strp = getstring(*m_hash, KY_TOP); if (NULL == strp) { // Case #1: it's not (yet) in our hash setstring(*m_hash, KY_TOP, top); m_top = top; } else if (strp->compare(*top) != 0) { // Case #2: it's in the has, but conflicts fprintf(stderr, "ERR: Clock with multiple top-level wire ID\'s: %s and %s\n", strp->c_str(), top->c_str()); m_top = strp; } else if (!m_top) { // Case #3: This is a new TOP tag MAPT subfm; subfm.m_typ = MAPT_STRING; subfm.u.m_s = top; m_hash->insert(KEYVALUE(KY_TOP, subfm)); m_top = top; } } void CLOCKINFO::setclass(STRINGP simclass) { STRINGP strp; strp = getstring(*m_hash, KY_CLASS); if (NULL == strp) { setstring(*m_hash, KY_CLASS, simclass); m_simclass = simclass; } else if (strp->compare(*simclass) != 0) { fprintf(stderr, "ERR: Clock with multiple simulation classes: %s and %s\n", strp->c_str(), simclass->c_str()); m_simclass = strp; } else if (!m_simclass) { // Case #3: This is a new CLASS tag m_simclass = simclass; MAPT subfm; subfm.m_typ = MAPT_STRING; subfm.u.m_s = simclass; m_hash->insert(KEYVALUE(KY_CLASS, subfm)); m_simclass = simclass; } } void CLOCKINFO::setreset(STRINGP ckreset) { STRINGP strp; strp = getstring(*m_hash, KY_RESET); if (NULL == strp) { setstring(*m_hash, KY_RESET, ckreset); m_reset = ckreset; } else if (strp->compare(*ckreset) != 0) { fprintf(stderr, "ERR: Clock with multiple reset wires: %s and %s\n", strp->c_str(), ckreset->c_str()); m_reset = strp; } else if (!m_reset) { // Case #3: This is a new RESET tag m_reset = ckreset; MAPT subfm; subfm.m_typ = MAPT_STRING; subfm.u.m_s = ckreset; m_hash->insert(KEYVALUE(KY_RESET, subfm)); m_reset = ckreset; } } void add_to_clklist(MAPDHASH *ckmap) { const char DELIMITERS[] = " \t\n,"; int ifreq; STRINGP sname, swire, sfreq, simclass, stop, sreset; char *dname, *dwire, *dfreq, *dsimclass, *dtop, *dreset; char *pname, *pwire, *pfreq, *psimclass, *ptop, *preset; char *tname, *twire, *tfreq, *tsimclass, *ttop, *treset; sname = getstring(*ckmap, KY_NAME); swire = getstring(*ckmap, KY_WIRE); simclass = getstring(*ckmap, KY_CLASS); stop = getstring(*ckmap, KY_TOP); sreset = getstring(*ckmap, KY_RESET); // strtok requires a writable string if (sname) dname = strdup(sname->c_str()); else dname = NULL; if (swire) dwire = strdup(swire->c_str()); else dwire = NULL; if (simclass) dsimclass = strdup(simclass->c_str()); else dsimclass = NULL; if (stop) dtop = strdup(stop->c_str()); else dtop = NULL; if (sreset) dreset = strdup(sreset->c_str()); else dreset = NULL; { MAPDHASH::iterator kvfreq; sfreq = NULL; dfreq = NULL; ifreq = 0; kvfreq = findkey(*ckmap, KY_FREQUENCY); if (kvfreq != ckmap->end()) switch(kvfreq->second.m_typ) { case MAPT_STRING: sfreq = kvfreq->second.u.m_s; dfreq = strdup(sfreq->c_str()); break; case MAPT_INT: case MAPT_AST: case MAPT_MAP: default: if (!getvalue(*ckmap, KY_FREQUENCY, ifreq)) { gbl_msg.error("Could not evaluate the " "frequency of clock %s\n", (sname)?(sname->c_str()) : "(Unnamed-clock)"); } break; } } pname = (dname) ? strtok_r(dname, DELIMITERS, &tname) : NULL; pwire = (dwire) ? strtok_r(dwire, DELIMITERS, &twire) : NULL; pfreq = (dfreq) ? strtok_r(dfreq, DELIMITERS, &tfreq) : NULL; ptop = (dtop ) ? strtok_r(dtop , DELIMITERS, &ttop) : NULL; psimclass = (dsimclass) ? strtok_r(dsimclass, DELIMITERS, &tsimclass) : NULL; preset = (dreset) ? strtok_r(dreset, DELIMITERS, &treset) : NULL; if (!pname) fprintf(stderr, "ERR: CLOCK has no name!\n"); // if ((!pfreq)&&(ifreq == 0)) // fprintf(stderr, "ERR: CLOCK has no frequency\n"); while(pname) { unsigned id = cklist.size(); unsigned long clocks_per_second; STRINGP wname; bool already_defined = false; gbl_msg.info("Examining clock: %s %s %s %s\n", pname, (pwire)?pwire:"(Unspec)", (pfreq)?pfreq:"(Unspec)", (ptop)?ptop:"(Unspec)"); for(unsigned i=0; icompare(pname)==0) { // // Update an existing clocks information // already_defined = true; gbl_msg.info("Clock %s is already defined: %s %ld\n", cklist[i].m_name->c_str(), (cklist[i].m_wire) ? cklist[i].m_wire->c_str() : "(Unspec)", cklist[i].m_interval_ps); // // Clock's wire name, such as i_clk // if ((pwire)&&(cklist[i].m_wire == NULL)) { cklist[i].m_wire = new STRING(pwire); gbl_msg.info("Clock %s\'s wire set to %s\n", pname, pwire); } else if ((pwire)&&(cklist[i].m_wire->compare(pwire) != 0)) { gbl_msg.error("Clock %s has a conflicting wire definition: %s and %s\n", pname, pwire, cklist[i].m_wire->c_str()); } // // Name of the top level incoming port, if // present // if ((ptop)&&(cklist[i].m_top == NULL)) { cklist[i].settop(new STRING(ptop)); gbl_msg.info("Clock\'s %s top-level wire set to %s\n", pname, ptop); } else if ((ptop)&&(cklist[i].m_top->compare(ptop) != 0)) { gbl_msg.error("Clock %s has a conflicting toplevel wire definition: %s and %s\n", pname, ptop, cklist[i].m_top->c_str()); } // // Name of the simulation class, if present // if ((psimclass)&&(cklist[i].m_simclass == NULL)) { cklist[i].setclass(new STRING(psimclass)); gbl_msg.info("Clock %s\'s simulation class set to %s\n", pname, psimclass); } else if ((psimclass)&&(cklist[i].m_simclass->compare(psimclass) != 0)) { gbl_msg.error("Clock %s has a conflicting simulation class definition: %s and %s\n", pname, psimclass, cklist[i].m_simclass->c_str()); } // // Name of the associated reset wire, if any // if (preset) { cklist[i].setreset(new STRING(preset)); gbl_msg.info("Clock %s\'s associated reset wire set to %s\n", pname, preset); } // // Set the clocks frequency // if ((pfreq)&&(cklist[i].interval_ps()==CLOCKINFO::UNKNOWN_PS)) { clocks_per_second = strtoul(pfreq, NULL, 0); gbl_msg.info("Setting %s clock frequency to %ld\n", pname, clocks_per_second); cklist[i].setfrequency( clocks_per_second); } else if ((ifreq)&&(cklist[i].interval_ps() == CLOCKINFO::UNKNOWN_PS)) { gbl_msg.info("Setting %s clock frequency to %u\n", pname, ifreq); cklist[i].setfrequency( (unsigned long) ((unsigned)ifreq)); } break; } } if (!already_defined) { CLOCKINFO *cki; cklist.push_back(CLOCKINFO()); cki = &cklist[id]; cki->setname(new STRING(pname)); if (pwire) wname = new STRING(pwire); else wname = new STRING(STRING("i_")+STRING(pname)); cki->setwire(wname); if (ptop) cki->settop(new STRING(ptop)); if (psimclass) cki->setclass(new STRING(psimclass)); if (preset) { fprintf(stderr, "preset != NULL\n"); cki->setreset(new STRING(preset)); } clocks_per_second = (unsigned)ifreq; if (pfreq) { clocks_per_second = strtoul(pfreq, NULL, 0); cki->setfrequency(clocks_per_second); } else if (ifreq != 0) { // clocks_per_second = (unsigned)ifreq; cki->setfrequency(clocks_per_second); } STRING infostr = STRING("Clock: ") + STRING(pname) + STRING(", is ") + (*wname); if (clocks_per_second != 0) { if ((clocks_per_second % 1000000) == 0) { infostr += STRING(" at ") + std::to_string(clocks_per_second/1000000); infostr += " MHz"; } else if ((clocks_per_second % 1000) == 0) { infostr += STRING(" at ") + std::to_string(clocks_per_second / 1000); infostr += " kHz"; } else { infostr += STRING(" at ") + std::to_string(clocks_per_second); infostr += " Hz"; } } if (NULL != cki->reset()) infostr += ", w/ associated reset " + (*cki->reset()); infostr += "\n"; gbl_msg.userinfo(infostr.c_str()); } if (pname) pname = strtok_r(NULL, DELIMITERS, &tname); if (pwire) pwire = strtok_r(NULL, DELIMITERS, &twire); if (pfreq) pfreq = strtok_r(NULL, DELIMITERS, &tfreq); if (ptop) ptop = strtok_r(NULL, DELIMITERS, &ttop); if (psimclass) psimclass = strtok_r(NULL, DELIMITERS, &tsimclass); if (preset) preset = strtok_r(NULL, DELIMITERS, &treset); ifreq = 0; } free(dname); free(dwire); free(dfreq); free(dtop); free(dsimclass); } CLOCKINFO *getclockinfo(STRING &clock_name) { CLKLIST::iterator ckp; for(ckp = cklist.begin(); ckp != cklist.end(); ckp++) { if (ckp->m_name->compare(clock_name)==0) { CLOCKINFO *ckresult; ckresult = &(*ckp); return ckresult; } } return NULL; } CLOCKINFO *getclockinfo(STRINGP clock_name) { if (!clock_name) { // Get the default clock assert(0); gbl_msg.fatal("No clock name given (might have assumed a default clock of clk)\n"); STRING str("clk"); return getclockinfo(str); } return getclockinfo(*clock_name); } void expand_clock(MAPDHASH &info) { MAPDHASH::iterator kyclock; MAPDHASH *ckmap; CLOCKINFO *cki; STRINGP sname; kyclock = findkey(info, KYCLOCK); if (info.end() == kyclock) return; if (kyclock->second.m_typ != MAPT_MAP) return; ckmap = kyclock->second.u.m_m; sname = getstring(ckmap, KY_NAME); if (!sname) { STRINGP ckwire; MAPDHASH::iterator kyprefix; kyprefix = findkey(info, KYPREFIX); if ((info.end() == kyprefix) ||(kyprefix->second.m_typ != MAPT_STRING)) { gbl_msg.error("ERR: Clock in %s has been given no name", kyprefix->second.u.m_s->c_str()); return; } ckwire = getstring(ckmap, KY_WIRE); if (ckwire) { gbl_msg.error("ERR: Clock with no name, using wire named %s\n", ckwire->c_str()); return; } } assert(sname); // This will fail if multiple clocks are defined on the same line cki = getclockinfo(sname); if (cki) { if (cki->m_hash != kyclock->second.u.m_m) kyclock->second.u.m_m = cki->m_hash; } } void expand_clock(MAPT &elm) { if(elm.m_typ == MAPT_MAP) expand_clock(*elm.u.m_m); } void find_clocks(MAPDHASH &master) { MAPDHASH *ckkey; MAPDHASH::iterator kypair; gbl_msg.info("------------ FIND-CLOCKS!! ------------\n"); // If we already have at least one clock, then we must've been called // before. Do nothing more. if (cklist.size() > 0) return; if (NULL != (ckkey = getmap(master, KYCLOCK))) { add_to_clklist(ckkey); } for(kypair = master.begin(); kypair != master.end(); kypair++) { MAPDHASH *p; if (kypair->second.m_typ != MAPT_MAP) continue; p = kypair->second.u.m_m; if (NULL != (ckkey = getmap(*p, KYCLOCK))) add_to_clklist(ckkey); } CLOCKINFO *cki; STRINGP sclk; sclk = new STRING("clk"); if (NULL == (cki = getclockinfo(new STRING("clk")))) { cklist.push_back(CLOCKINFO()); // Default clock, if not given, is 100MHz cklist[0].set(sclk, new STRING("i_clk"), 100000000ul); } else delete sclk; expand_clock(master); for(kypair = master.begin(); kypair != master.end(); kypair++) expand_clock(kypair->second); fprintf(stderr, "All clocks enumerated\n"); } ================================================ FILE: sw/clockinfo.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/clockinfo.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef CLOCKINFO_H #define CLOCKINFO_H #include "parser.h" #include "mapdhash.h" #include "keys.h" class CLOCKINFO { private: STRINGP m_reset; public: MAPDHASH *m_hash; unsigned long m_interval_ps; STRINGP m_name, m_wire, m_top, m_simclass; static const unsigned long UNKNOWN_PS, PICOSECONDS_PER_SECOND; CLOCKINFO(void); static CLOCKINFO *new_clock(STRINGP name); unsigned long interval_ps(void) { return m_interval_ps; } unsigned long setfrequency(const char *sfreq_hz) { return setfrequency(strtoul(sfreq_hz, NULL, 0)); } unsigned long setfrequency(unsigned long frequency_hz); void setname(STRINGP name); void setwire(STRINGP wire); void settop(STRINGP top); void setclass(STRINGP simclass); void setreset(STRINGP ckreset); void set(STRINGP name, STRINGP wire, unsigned long frequency_hz) { setname(name); setwire(wire); setfrequency(frequency_hz); } void set(STRINGP name, STRINGP wire, char *sfreq) { setname(name); setwire(wire); setfrequency(sfreq); } unsigned frequency(void); STRINGP reset(void); }; typedef std::vector CLKLIST; // A list of all of the clocks found within this design extern CLKLIST cklist; // Search through the master hash looking for all of the clocks within it. extern CLOCKINFO *getclockinfo(STRING &clock_name); extern CLOCKINFO *getclockinfo(STRINGP clock_name); // Search through the master hash looking for all of the clocks within it. extern void find_clocks(MAPDHASH &master); #endif // CLOCKINFO_H ================================================ FILE: sw/expr.l ================================================ /******************************************************************************* ** ** Filename: expr.l ** {{{ ** Project: AutoFPGA, a utility for composing FPGA designs from peripherals ** ** Purpose: The lexical analyzer for any variable evaluations. This ** converts data description input into tokens, to feed the parser. ** In general, the data description input is a single line, although it may ** be split across multiple if the computation to be accomplished is ** complex enough. ** ** ** Creator: Dan Gisselquist, Ph.D. ** Gisselquist Technology, LLC ** ******************************************************************************** ** }}} ** Copyright (C) 2017-2024, Gisselquist Technology, LLC ** {{{ ** This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ** target there if the PDF file isn't present.) If not, see ** for a copy. ** }}} ** License: GPL, v3, as defined and found on www.gnu.org, ** {{{ ** http://www.gnu.org/licenses/gpl.html ** ******************************************************************************** ** }}} **/ %{ #include #include "parser.h" #include "expr.tab.h" extern "C" int yylex(); extern "C" int yywrap() { return 1;} %} %% [@]?[$]?[/.^+]?[_A-Za-z][._a-zA-Z0-9]* { if (yytext[0] == '@') { if (yytext[1]=='$') yylval.u_id = strdup(yytext+2); else yylval.u_id = strdup(yytext+1); } else yylval.u_id = strdup(yytext); return IDENTIFIER; } @[$]?\([/.^+]?[_A-Za-z][._a-zA-Z0-9]*\) { if (yytext[1]=='$') yylval.u_id = strdup(yytext+3); else yylval.u_id = strdup(yytext+2); // Remove the trailing parenthesis yylval.u_id[strlen(yylval.u_id)-1]='\0'; return IDENTIFIER; } 0[xX][0-9A-Fa-f]+ { yylval.u_ival = strtoul(yytext,NULL,16);return INT;} 0[0-7]+ { yylval.u_ival = strtoul(yytext,NULL, 8);return INT;} [1-9][0-9]* { yylval.u_ival = strtoul(yytext,NULL,10);return INT;} "0" { yylval.u_ival = 0;return INT;} "+" { return PLUS; } "-" { return MINUS; } "*" { return TIMES; } "/" { return DIVIDE; } "<<" { return UPSHIFT; } ">>" { return DOWNSHIFT; } "!=" { return LOGICAL_NEQ; } "<=" { return LOGICAL_LTE; } ">=" { return LOGICAL_GTE; } "<" { return LOGICAL_LT; } ">" { return LOGICAL_GT; } "&&" { return BOOLEANAND; } "||" { return BOOLEANOR; } "==" { return BOOLEANEQ; } "!" { return BOOLEANNOT; } "|" { return BITWISEOR; } "&" { return BITWISEAND; } "^" { return BITWISEXOR; } "~" { return BITWISENOT; } "%" { return MODULO; } ":" { return COLON; } "?" { return QUESTION; } [ \t]+ { } [(] { return '('; } [)] { return ')'; } %% ================================================ FILE: sw/expr.ypp ================================================ /******************************************************************************* ** ** Filename: expr.ypp ** {{{ ** Project: AutoFPGA, a utility for composing FPGA designs from peripherals ** ** Purpose: ** ** Creator: Dan Gisselquist, Ph.D. ** Gisselquist Technology, LLC ** ******************************************************************************** ** }}} ** Copyright (C) 2017-2021, Gisselquist Technology, LLC ** {{{ ** This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no ** target there if the PDF file isn't present.) If not, see ** for a copy. ** }}} ** License: GPL, v3, as defined and found on www.gnu.org, ** {{{ ** http://www.gnu.org/licenses/gpl.html ** ** ******************************************************************************** ** }}} */ %{ #include #include #include #include "parser.h" #include "ast.h" #define DEFAULT_OUTPUT_FNAME "z.out" #define YYDEBUG 1 extern "C" int yylex(void); extern "C" int yyparse(void); // extern "C" FILE *yyin; void yyerror(const char *); static AST *toplevel_ast; %} %token PLUS MINUS TIMES DIVIDE MODULO %token UPSHIFT DOWNSHIFT %token BITWISEOR BITWISEAND BITWISEXOR BITWISENOT %token BOOLEANOR BOOLEANAND BOOLEANEQ BOOLEANNOT %token LOGICAL_NEQ LOGICAL_LT LOGICAL_LTE %token LOGICAL_GT LOGICAL_GTE %token COLON QUESTION %token IDENTIFIER INT %union { long u_ival; char *u_id; AST *u_ast; } %type INT %type IDENTIFIER %type expr value %left QUESTION COLON %left BOOLEANOR %left BOOLEANAND %left BOOLEANEQ %left BOOLEANNOT %left UPSHIFT DOWNSHIFT %left LOGICAL_LT LOGICAL_GT LOGICAL_LTE LOGICAL_GTE %left LOGICAL_EQ LOGICAL_NEQ %left BITWISEOR BITWISEXOR %left BITWISEAND %left BITWISENOT %left MODULO %left PLUS MINUS %left TIMES DIVIDE %% /* The grammar follows */ input: %empty | expr { toplevel_ast = $1; } ; expr: value { $$ = $1; } | MINUS value %prec TIMES { $$ = new AST_BRANCH('-',new AST_NUMBER(0), $2); } | expr PLUS expr { $$ = new AST_BRANCH('+',$1,$3); } | expr MINUS expr { $$ = new AST_BRANCH('-',$1,$3); } | expr TIMES expr { $$ = new AST_BRANCH('*',$1,$3); } | expr DIVIDE expr { $$ = new AST_BRANCH('/',$1,$3); } | expr MODULO expr { $$ = new AST_BRANCH('%',$1,$3); } | expr BITWISEOR expr { $$ = new AST_BRANCH('|',$1,$3); } | expr BITWISEAND expr { $$ = new AST_BRANCH('&',$1,$3); } | expr BITWISEXOR expr { $$ = new AST_BRANCH('^',$1,$3); } | expr BITWISENOT expr { $$ = new AST_BRANCH('~',$1,$3); } | expr UPSHIFT expr { $$ = new AST_BRANCH('u',$1,$3); } | expr DOWNSHIFT expr { $$ = new AST_BRANCH('d',$1,$3); } | expr BOOLEANOR expr { $$ = new AST_BRANCH('o',$1,$3); } | expr BOOLEANAND expr { $$ = new AST_BRANCH('a',$1,$3); } | expr LOGICAL_EQ expr { $$ = new AST_BRANCH('e',$1,$3); } | expr LOGICAL_NEQ expr { $$ = new AST_BRANCH('N',$1,$3); } | expr LOGICAL_LT expr { $$ = new AST_BRANCH('L',$1,$3); } | expr LOGICAL_GT expr { $$ = new AST_BRANCH('G',$1,$3); } | expr LOGICAL_LTE expr { $$ = new AST_BRANCH('<',$1,$3); } | expr LOGICAL_GTE expr { $$ = new AST_BRANCH('>',$1,$3); } | expr QUESTION expr COLON expr { $$ = new AST_TRIOP($1,$3,$5); } | '(' expr ')' { $$ = $2; } ; /* | BITWISENOT expr { $$ = new AST_SINGLEOP('~',$2); } */ /* | BOOLEANNOT expr { $$ = new AST_SINGLEOP('!',$2); } */ value: INT { $$ = new AST_NUMBER($1); } | IDENTIFIER { $$ = new AST_IDENTIFIER($1); } ; %% #include #include #include #include #include #include #include // #include "lex.yy.h" static char *topstr; void yyerror(const char *str) { fflush(stdout); fprintf(stderr, "EXPR ERR: %s\n", str); fprintf(stderr, "ERR: While processing \"%s\"\n", topstr); } AST *parse_ast(const STRING &str) { size_t ln = str.size() + 4; char *buf = new char[ln]; topstr = buf; memset(buf, 0, ln); strcpy(buf, str.c_str()); yy_scan_string(buf); yyparse(); return toplevel_ast; } ================================================ FILE: sw/gather.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/gather.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To gather all peripherals together, using a given bus to do so // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "keys.h" #include "kveval.h" #include "legalnotice.h" #include "plist.h" #include "bldregdefs.h" #include "businfo.h" #include "subbus.h" #include "globals.h" #include "msgs.h" #include "predicates.h" typedef std::vector APLIST; void gather_peripherals(APLIST *alist, BUSINFO *bus, PLIST *plist, unsigned base) { if (NULL == plist) { gbl_msg.warning("Sub-bus %s has no peripherals\n", bus->name()->c_str()); return; } for(unsigned k=0; ksize(); k++) { MAPDHASH *ph = (*plist)[k]->p_phash; unsigned addr; // unsigned base = 0; if (!bus->get_base_address(ph, addr)) addr = 0; alist->push_back((*plist)[k]); if (addr+base != 0) { setvalue(*ph, KYREGBASE, addr+base); reeval(gbl_hash); } (*plist)[k]->p_regbase = addr+base; if (isarbiter(*ph)) { BUSINFO *subbus; subbus = (*plist)[k]->p_master_bus; assert(subbus); gather_peripherals(alist, subbus, subbus->m_plist, addr+base); } } } APLIST *gather_peripherals(BUSINFO *bus) { APLIST *alist = new APLIST; gather_peripherals(alist, bus, bus->m_plist, 0); return alist; } APLIST *full_gather(void) { STRINGP strp; BUSINFO *bi; APLIST *alist; strp = getstring(*gbl_hash, KYREGISTER_BUS_NAME); if (NULL == strp) { gbl_msg.warning("No REGISTER.BUS defined, assuming a register bus of \"wbu\".\n"); strp = new STRING("wbu"); } bi = find_bus(strp); if (NULL == bi) { gbl_msg.warning("Register bus %s not found, switching to default\n", strp->c_str()); bi = find_bus((STRINGP)NULL); } if(!bi) { gbl_msg.error("No bus found for register definitions\n"); return NULL; } // Get the list of peripherals alist = gather_peripherals(bi); sort(alist->begin(), alist->end(), compare_regaddr); return alist; } ================================================ FILE: sw/gather.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/gather.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To gather all peripherals together, using a given bus to do so // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef GATHER_H #define GATHER_H #include #include "plist.h" #include "businfo.h" typedef std::vector APLIST; extern void gather_peripherals(APLIST *alist, BUSINFO *bus, PLIST *plist, unsigned base=0); extern APLIST *gather_peripherals(BUSINFO *bus); extern APLIST *full_gather(void); #endif ================================================ FILE: sw/genbus.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/genbus.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Defines a generic bus class, from which other buses may derive. // More importantly, describes a way that different potential // bus classes/implementations may be searched for an appropriate one. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include "genbus.h" #include "bitlib.h" #include "msgs.h" #include "bus/wb.h" #include "bus/axil.h" #include "bus/axi.h" #include "keys.h" #include "mapdhash.h" WBBUSCLASS wbclass; AXILBUSCLASS axilclass; AXIBUSCLASS axiclass; BUSCLASS *busclass_list[NUM_BUS_CLASSES] = { &wbclass, &axilclass, &axiclass }; unsigned num_bus_classes = NUM_BUS_CLASSES; /* void GENBUS::integrity_check(void) { if (!m_info) { gbl_msg.error("Bus logic generator with no bus info structure\n"); return; } if (!m_info->m_plist) gbl_msg.error("Bus logic generator with no peripherals attached\n"); if (!m_info->m_name) gbl_msg.error("Bus has no name!\n"); if (!m_info->m_clock) gbl_msg.error("Bus has no assigned clock!\n"); } */ bool GENBUS::bus_option(const STRING &ky) { MAPDHASH *option; option = getmap(m_info->m_hash, ky); return (option != NULL); } void GENBUS::xbar_option(FILE *fp, const STRING &key, const char *pat, const char *def) { const char *loc = strchr(pat, '%'); STRINGP str; int val, prech; assert(loc != NULL); prech = loc-pat; if (!bus_option(key)) { if (NULL != def) fprintf(fp, "%.*s%s%s", prech, pat, def, loc+1); return; } if (getvalue(*m_info->m_hash, key, val)) { fprintf(fp, "%.*s%d%s", prech, pat, val, loc+1); return; } if (NULL != (str = getstring(*m_info->m_hash, key))) { fprintf(fp, "%.*s%s%s", prech, pat, str->c_str(), loc+1); return; } if (NULL != def) { fprintf(fp, "%.*s%s%s", prech, pat, def, loc+1); return; } } STRINGP GENBUS::name(void) { if (m_info) return m_info->name(); return NULL; } unsigned GENBUS::max_name_width(PLIST *pl) { unsigned slave_name_width = 0; for(unsigned k=0; ksize(); k++) { PERIPHP p = (*pl)[k]; unsigned sz; sz = p->name()->size(); if (slave_name_width < sz) slave_name_width = sz; } return slave_name_width; } void GENBUS::slave_addr(FILE *fp, PLIST *pl, const int addr_lsbs) { // int lgdw = nextlg(m_info->data_width())-3; unsigned slave_name_width = max_name_width(pl); fprintf(fp, "\t\t.SLAVE_ADDR({\n"); fprintf(fp, "\t\t\t// Address width = %d\n" "\t\t\t// Address LSBs = %d\n", address_width(), addr_lsbs); for(unsigned k=pl->size()-1; k>0; k=k-1) { PERIPHP p = (*pl)[k]; fprintf(fp, "\t\t\t{ %d\'h%0*lx },", address_width(), (address_width()+3)/4, ((*pl)[k]->p_base)>>addr_lsbs); fprintf(fp, " // %*s: 0x%0*lx\n", slave_name_width, p->name()->c_str(), (address_width()+addr_lsbs+3)/4, p->p_base); } fprintf(fp, "\t\t\t{ %d\'h%0*lx } // %*s: 0x%0*lx\n", address_width(), (address_width()+3)/4, ((*pl)[0]->p_base)>>addr_lsbs, slave_name_width, (*pl)[0]->name()->c_str(), (address_width()+addr_lsbs+3)/4, (*pl)[0]->p_base); fprintf(fp, "\t\t})"); } void GENBUS::slave_mask(FILE *fp, PLIST *pl, const int addr_lsbs) { int lgdw = 0; unsigned slave_name_width = max_name_width(pl); if (word_addressing()) lgdw = nextlg(m_info->data_width())-3; fprintf(fp, "\t\t.SLAVE_MASK({\n"); fprintf(fp, "\t\t\t// Address width = %d\n" "\t\t\t// Address LSBs = %d\n", address_width(), addr_lsbs); for(unsigned k=pl->size()-1; k>0; k=k-1) { PERIPHP p = (*pl)[k]; fprintf(fp, "\t\t\t{ %d\'h%0*lx }, // %*s\n", address_width(), (address_width()+3)/4, p->p_mask << (addr_lsbs-lgdw), slave_name_width, p->name()->c_str()); } fprintf(fp, "\t\t\t{ %d\'h%0*lx } // %*s\n", address_width(), (address_width()+3)/4, ((*pl)[0]->p_mask << (lgdw - addr_lsbs)), slave_name_width, (*pl)[0]->name()->c_str()); fprintf(fp, "\t\t})"); } bool BUSCLASS::matches(BUSINFO *bi) { MAPDHASH *bhash = bi->m_hash; STRINGP btype; // Check any slaves of this bus to see if we can // handle them btype = getstring(bhash, KY_TYPE); return matchtype(btype); } ================================================ FILE: sw/genbus.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/genbus.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Defines a generic bus interface which, if implemented, should // allow support for any bus type desired. // // Translators: // To facilitate bus translation, every bus type is defined uniquely by // the buses data width, type, and clock. Data types will (eventually) // include: AXI, AXI-lite (or AXIL), WB, and WBC (or WB-classic). // // To avoid unnecessary translation, address width properties will // propagate up, ID width will propagate down. All AXI slaves are required // to support an arbitrary number of AXI ID's. // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef GENBUS_H #define GENBUS_H #include #include #include #include #include #include "parser.h" #include "mapdhash.h" #include "plist.h" #include "clockinfo.h" #include "businfo.h" class GENBUS { public: BUSINFO *m_info; // Generic bus information // MLISTP m_mlist; // List of bus masters // PLISTP m_plist; // List of peripheral/slaves // GENBUS(BUSINFO *bi); // ~GENBUS() {}; virtual int address_width(void) = 0; virtual bool word_addressing(void) = 0; // virtual void assign_addresses(void) = 0; virtual bool get_base_address(MAPDHASH *phash, unsigned &base) = 0; // virtual unsigned size(void) { return (m_info && m_info->m_plist) ? m_info->m_plist->size() : 0; }; // virtual void writeout_slave_defn_v(FILE *fp, const char *name, const char *errwire = NULL, const char *btyp="") = 0; virtual void writeout_bus_slave_defns_v(FILE *fp) = 0; virtual void writeout_bus_master_defns_v(FILE *fp) = 0; virtual void writeout_bus_defns_v(FILE *fp) { writeout_bus_master_defns_v(fp); writeout_bus_slave_defns_v(fp); } virtual void writeout_bus_logic_v(FILE *fp) = 0; virtual void writeout_no_slave_v(FILE *fp, STRINGP prefix) = 0; virtual void writeout_no_master_v(FILE *fp) = 0; virtual STRINGP iansi(BMASTERP m) { return NULL; } virtual STRINGP oansi(BMASTERP m) { return NULL; } virtual STRINGP master_ansprefix(BMASTERP m) { return NULL; } virtual STRINGP master_portlist(BMASTERP m) { return NULL; } virtual STRINGP master_ansi_portlist(BMASTERP m) { return NULL; } virtual STRINGP slave_ansprefix(PERIPHP p) { return NULL; } virtual STRINGP slave_portlist(PERIPHP p) { return NULL; } virtual STRINGP slave_ansi_portlist(PERIPHP p) { return NULL; } STRINGP name(void); unsigned max_name_width(PLIST *pl); void slave_addr(FILE *fp, PLIST *pl, const int addr_lsbs = 0); void slave_mask(FILE *fp, PLIST *pl, const int addr_lsbs = 0); virtual void integrity_check(void) {}; bool bus_option(const STRING &str); void xbar_option(FILE *fp, const STRING&, const char *,const char *d=NULL); }; class BUSCLASS { public: virtual STRINGP name(void) = 0; // i.e. WB virtual STRINGP longname(void) = 0; // i.e. "Wishbone" virtual bool matchtype(STRINGP) = 0; virtual bool matchfail(MAPDHASH *bhash) { return false; }; virtual bool matches(BUSINFO *bi); virtual GENBUS *create(BUSINFO *bi) = 0; }; #define NUM_BUS_CLASSES 3 extern unsigned num_bus_classes; extern BUSCLASS *busclass_list[NUM_BUS_CLASSES]; #endif // GENBUS_H ================================================ FILE: sw/globals.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/globals.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include "globals.h" MAPDHASH *gbl_hash = NULL; const bool DELAY_ACK = true; ================================================ FILE: sw/globals.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/globals.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef GLOBALS_H #define GLOBALS_H #include #include "mapdhash.h" extern MAPDHASH *gbl_hash; #endif // GLOBALS_H ================================================ FILE: sw/ifdefs.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/ifdefs.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Components we have can contain an ACCESS keyword that can then // be used by logic to determine if the component exists or not. // // These ACCESS lines may also depend upon the ACCESS lines of other // components. // // main.v Gets all of our work. The ACCESS lines are used at // the top of this component to turn things on (or off) // // toplevel.v Doesn't get touched. If you include your component // in the autofpga list, it will define external ports // for it, independent of the ACCESS lines. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "keys.h" #include "kveval.h" #include "legalnotice.h" extern bool isperipheral(MAPT &pmap); extern bool isperipheral(MAPDHASH &phash); void build_access_ifdefs_v(MAPDHASH &master, FILE *fp) { const char DELIMITERS[] = ", \t\n"; MAPDHASH::iterator kvpair; STRING already_defined; MAPDHASH dephash; fprintf(fp, "//\n" "//\n" "// Here is a list of defines which may be used, post auto-design\n" "// (not post-build), to turn particular peripherals (and bus masters)\n" "// on and off. In particular, to turn off support for a particular\n" "// design component, just comment out its respective `define below.\n" "//\n" "// These lines are taken from the respective @ACCESS tags for each of our\n" "// components. If a component doesn\'t have an @ACCESS tag, it will not\n" "// be listed here.\n" "//\n"); fprintf(fp, "// First, the independent access fields for any bus masters\n"); // {{{ for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (isperipheral(kvpair->second)) continue; STRINGP dep, accessp; dep = getstring(*kvpair->second.u.m_m, KYDEPENDS); accessp = getstring(*kvpair->second.u.m_m, KYACCESS); if (NULL == accessp) continue; if (NULL != dep) { dephash.insert(*kvpair); } else { char *dup = strdup(accessp->c_str()); char *tok = strtok(dup, DELIMITERS); while(tok != NULL) { if (tok[0] == '!') tok++; fprintf(fp, "`define\t%s\n", tok); already_defined = already_defined + " " + STRING(tok); tok = strtok(NULL, DELIMITERS); } free(dup); } } // }}} fprintf(fp, "// And then for the independent peripherals\n"); // {{{ for(kvpair=master.begin(); kvpair != master.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (!isperipheral(kvpair->second)) continue; STRINGP dep, accessp; dep = getstring(kvpair->second, KYDEPENDS); accessp = getstring(kvpair->second, KYACCESS); if (NULL == accessp) continue; else if (NULL != dep) { dephash.insert(*kvpair); } else { char *dup = strdup(accessp->c_str()); char *tok = strtok(dup, DELIMITERS); while(tok != NULL) { if (tok[0] == '!') tok++; fprintf(fp, "`define\t%s\n", tok); already_defined = already_defined + " " + STRING(tok); tok = strtok(NULL, DELIMITERS); } free(dup); } } // }}} if (dephash.begin() != dephash.end()) { fprintf(fp, "//\n//\n// The list of those things that have @DEPENDS tags\n//\n//\n"); fprintf(fp, "//\n" "// Dependencies\n" "// Any core with both an @ACCESS and a @DEPENDS tag will show up here.\n" "// The @DEPENDS tag will turn into a series of ifdef\'s, with the @ACCESS\n" "// being defined only if all of the ifdef\'s are true" "//\n"); // {{{ bool done; do { done = true; STRING depstr, endstr; for(kvpair=dephash.begin(); kvpair != dephash.end(); kvpair++) { // {{{ if (kvpair->second.m_typ != MAPT_MAP) continue; STRINGP dep, accessp; dep = getstring(kvpair->second, KYDEPENDS); accessp = getstring(kvpair->second, KYACCESS); bool depsmet = true; char *deplist, *dependency; deplist = strdup(dep->c_str()); depstr = ""; endstr = ""; fprintf(fp, "// Deplist for @$(PREFIX)=%s\n", kvpair->first.c_str()); dependency = strtok(deplist, DELIMITERS); while(dependency) { char *rawdep, *baredep; rawdep = dependency; baredep = rawdep; if (rawdep[0] == '!') baredep = rawdep+1; STRING mstr = STRING(" ")+STRING(baredep) +STRING(" "); if (NULL == strstr(already_defined.c_str(), baredep)) { // fprintf(fp, "// -- Dependency not met: %s\n", baredep); depsmet = false; break; } if (rawdep[0] == '!') { depstr += STRING("`ifndef\t") + STRING(baredep) + STRING("\n"); } else { depstr += STRING("`ifdef\t") + STRING(rawdep) + STRING("\n"); } endstr = STRING("`endif\t// ") + STRING(rawdep) + STRING("\n") + endstr; dependency = strtok(NULL, DELIMITERS); } if (depsmet) { char *dup = strdup(accessp->c_str()); char *tok = strtok(dup, DELIMITERS); fprintf(fp, "%s", depstr.c_str()); while(tok != NULL) { if (tok[0] == '!') tok++; if (NULL == strstr(already_defined.c_str(), tok)) { fprintf(fp, "`define\t%s\n", tok); already_defined = already_defined + " " + STRING(tok); // We changed something, so ... done = false; } tok = strtok(NULL, DELIMITERS); } free(dup); fprintf(fp, "%s", endstr.c_str()); dephash.erase(kvpair); kvpair = dephash.begin(); if (kvpair == dephash.end()) break; } // }}} } if (dephash.begin() == dephash.end()) done = true; } while(!done); // }}} } if (dephash.begin() != dephash.end()) { fprintf(fp, "//\n" "// The following macros have unmet dependencies. They are listed\n" "// here for reference, but their dependencies cannot be met.\n"); // {{{ for(kvpair=dephash.begin(); kvpair != dephash.end(); kvpair++) { const char DELIMITERS[] = ", \t\n"; if (kvpair->second.m_typ != MAPT_MAP) continue; STRINGP dep, accessp; dep = getstring(kvpair->second, KYDEPENDS); accessp = getstring(kvpair->second, KYACCESS); char *deplist, *dependency; deplist = strdup(dep->c_str()); STRING depstr, endstr; depstr = ""; endstr = ""; fprintf(fp, "// Unmet Dependency list for @$(PREFIX)=%s\n", kvpair->first.c_str()); dependency = strtok(deplist, DELIMITERS); while(dependency) { const char *baredep = dependency; bool defined = false; if (baredep[0] == '!') baredep++; if (NULL != strstr(already_defined.c_str(), baredep)) defined = true; if (dependency[0] == '!') { depstr += STRING("`ifndef\t") +STRING(baredep); if (!defined) depstr += " // This value is unknown"; depstr += STRING("\n"); } else { depstr += STRING("`ifdef\t") +STRING(baredep); if (!defined) depstr += " // This value is unknown"; depstr += STRING("\n"); } endstr += STRING("`endif\n"); dependency = strtok(NULL, DELIMITERS); } fprintf(fp, "%s", depstr.c_str()); { char *dup = strdup(accessp->c_str()); char *tok = strtok(dup, DELIMITERS); while(tok != NULL) { if (tok[0] == '!') tok++; fprintf(fp, "`define\t%s\n", tok); tok = strtok(NULL, DELIMITERS); } free(dup); } fprintf(fp, "%s\n", endstr.c_str()); } // }}} } fprintf(fp, "//\n// End of dependency list\n//\n//\n"); } ================================================ FILE: sw/ifdefs.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/ifdefs.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Components we have can contain an ACCESS keyword that can then // be used by logic to determine if the component exists or not. // // These ACCESS lines may also depend upon the ACCESS lines of other // components. // // main.v Gets all of our work. The ACCESS lines are used at // the top of this component to turn things on (or off) // // toplevel.v Doesn't get touched. If you include your component // in the autofpga list, it will define external ports // for it, independent of the ACCESS lines. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef IFDEFS_H #define IFDEFS_H #include #include "mapdhash.h" extern void build_access_ifdefs_v(MAPDHASH &master, FILE *fp); #endif ================================================ FILE: sw/keys.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/keys.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Defines the strings AutoFPGA understands. These strings are // typically key names, as described by the ICD. The actual string // names are (nearly) equal to their C++ name. However, by defining them // here, I get some robustness to ICD changes, and some compiler help to // make sure I only use named strings. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include "keys.h" const STRING KYLEGAL= "LEGAL"; const STRING KYCOPYRIGHT= "COPYRIGHT"; // Another name for LEGAL const STRING KYCMDLINE= "CMDLINE"; const STRING KYSUBD= "SUBD"; const STRING KYPATH= "PATH"; // const STRING KYBUS_ADDRESS_WIDTH="BUS_ADDRESS_WIDTH"; const STRING KYRESET_ADDRESS ="RESET_ADDRESS"; // For subclassing const STRING KYPLUSDOT ="+"; const STRING KYINCLUDE ="INCLUDE"; const STRING KYINCLUDEFILE ="INCLUDEFILE"; // Other global keys const STRING KYREGDEFS_CPP_INCLUDE ="REGDEFS.CPP.INCLUDE"; const STRING KYREGDEFS_CPP_INSERT ="REGDEFS.CPP.INSERT"; const STRING KYKEYS_TRIMLIST ="KEYS.TRIMLIST"; const STRING KYKEYS_INTLIST ="KEYS.INTLIST"; const STRING KYPROJECT ="PROJECT"; // const STRING KYSIO= "sio"; const STRING KYDIO= "dio"; const STRING KYSIO_SEL= "sio_sel"; const STRING KYDIO_SEL= "dio_sel"; // const STRING KYPREFIX= "PREFIX"; const STRING KYACCESS= "ACCESS"; const STRING KYDEPENDS= "DEPENDS"; const STRING KYERROR_WIRE= "ERROR.WIRE"; const STRING KYSLAVE= "SLAVE", KYSLAVE_TYPE= "SLAVE.TYPE", KYSLAVE_BUS= "SLAVE.BUS", KYSLAVE_BUS_NAME= "SLAVE.BUS.NAME", KYSLAVE_ORDER= "SLAVE.ORDER", KYSLAVE_AWID= "SLAVE.AWID", KYSLAVE_OPTIONS= "SLAVE.OPTIONS", KYSLAVE_PREFIX= "SLAVE.PREFIX", KYSLAVE_PORTLIST= "SLAVE.PORTLIST", KYSLAVE_ANSIPORTLIST= "SLAVE.ANSIPORTLIST", KYSLAVE_IANSI= "SLAVE.IANSI", KYSLAVE_OANSI= "SLAVE.OANSI", KYSLAVE_ANSPREFIX= "SLAVE.ANSPREFIX"; const STRING KYMASTER= "MASTER", KYMASTER_TYPE= "MASTER.TYPE", KYMASTER_BUS= "MASTER.BUS", KYMASTER_BUS_NAME= "MASTER.BUS.NAME", KYMASTER_PREFIX= "MASTER.PREFIX", KYMASTER_AWID= "MASTER.AWID", KYMASTER_OPTIONS= "MASTER.OPTIONS", KYMASTER_PORTLIST= "MASTER.PORTLIST", KYMASTER_ANSIPORTLIST= "MASTER.ANSIPORTLIST", KYMASTER_IDWIDTH= "MASTER.IDWIDTH", KYMASTER_IANSI= "MASTER.IANSI", KYMASTER_OANSI= "MASTER.OANSI", KYMASTER_ANSPREFIX= "MASTER.ANSPREFIX"; // Types of bus masters // KYBUS, and ... const STRING KYSUBBUS= "SUBBUS", KYARBITER= "ARBITER", KYXCLOCK= "XCLOCK", KYHOST= "HOST", KYCPU= "CPU"; // const STRING KYBASE= "BASE"; const STRING KYREGBASE= "REGBASE"; const STRING KYNADDR= "NADDR"; const STRING KYMASK= "MASK"; // const STRING KYEXPR= "EXPR"; const STRING KYVAL= "VAL"; const STRING KYFORMAT= "FORMAT"; const STRING KYSTR= "STR"; // const STRING KYSCOPE= "SCOPE"; const STRING KYMEMORY= "MEMORY"; const STRING KYSINGLE= "SINGLE"; const STRING KYDOUBLE= "DOUBLE"; const STRING KYOTHER= "OTHER"; // Numbers of things const STRING KYNP= "NP"; const STRING KYNPIC= "NPIC"; const STRING KYNPSINGLE= "NPSINGLE"; const STRING KYNPDOUBLE= "NPDOUBLE"; const STRING KYNPMEMORY= "NPMEMORY"; const STRING KYNSCOPES= "NSCOPES"; // Regs definitions const STRING KYREGS_N= "REGS.N"; const STRING KYREGS_NOTE= "REGS.NOTE"; const STRING KYREGDEFS_H_INCLUDE="REGDEFS.H.INCLUDE"; const STRING KYREGDEFS_H_DEFNS="REGDEFS.H.DEFNS"; const STRING KYREGDEFS_H_INSERT="REGDEFS.H.INSERT"; // Board defintions for C/C++ const STRING KYBDEF_INCLUDE= "BDEF.INCLUDE"; const STRING KYBDEF_DEFN= "BDEF.DEFN"; const STRING KYBDEF_IOTYPE= "BDEF.IOTYPE"; const STRING KYBDEF_OSDEF= "BDEF.OSDEF"; const STRING KYBDEF_OSVAL= "BDEF.OSVAL"; const STRING KYBDEF_INSERT= "BDEF.INSERT"; // Top definitions const STRING KYTOP_PORTLIST= "TOP.PORTLIST"; const STRING KYTOP_IODECL= "TOP.IODECL"; const STRING KYTOP_PARAM= "TOP.PARAM"; const STRING KYTOP_DEFNS= "TOP.DEFNS"; const STRING KYTOP_MAIN= "TOP.MAIN"; const STRING KYTOP_INSERT= "TOP.INSERT"; // Main definitions const STRING KYMAIN_INCLUDE= "MAIN.INCLUDE"; const STRING KYMAIN_PORTLIST="MAIN.PORTLIST"; const STRING KYMAIN_IODECL= "MAIN.IODECL"; const STRING KYMAIN_PARAM= "MAIN.PARAM"; const STRING KYMAIN_DEFNS= "MAIN.DEFNS"; const STRING KYMAIN_INSERT= "MAIN.INSERT"; const STRING KYMAIN_ALT= "MAIN.ALT"; // LD definitions const STRING KYLD_FILE= "LD.FILE"; const STRING KYLD_SCRIPT= "LD.SCRIPT"; const STRING KYLD_ENTRY= "LD.ENTRY"; const STRING KYLD_NAME= "LD.NAME"; const STRING KYLD_PERM= "LD.PERM"; const STRING KYLD_DEFNS= "LD.DEFNS"; const STRING KYSCRIPT= "SCRIPT"; const STRING KYFLASH= "flash"; // XDC/UCF definitions const STRING KYXDC_FILE= "XDC.FILE"; const STRING KYXDC_INSERT= "XDC.INSERT"; const STRING KYPCF_FILE= "PCF.FILE"; const STRING KYPCF_INSERT= "PCF.INSERT"; const STRING KYLPF_FILE= "LPF.FILE"; const STRING KYLPF_INSERT= "LPF.INSERT"; const STRING KYUCF_FILE= "UCF.FILE"; const STRING KYUCF_INSERT= "UCF.INSERT"; // INT definitions const STRING KY_INT= "INT"; const STRING KYINTLIST= "INTLIST"; const STRING KY_WIRE= "WIRE"; const STRING KY_DOTWIRE= ".WIRE"; const STRING KY_ID= "ID"; // Arbitrary output data files const STRING KYOUT_FILE= "OUT.FILE"; const STRING KYOUT_DATA= "OUT.DATA"; // RTL/Makefile definitions const STRING KYRTL_MAKE_GROUP= "RTL.MAKE.GROUP"; const STRING KYRTL_MAKE_SUBD= "RTL.MAKE.SUBD"; const STRING KYVFLIST= "VFLIST"; const STRING KYRTL_MAKE_VDIRS= "RTL.MAKE.VDIRS"; const STRING KYRTL_MAKE_FILES= "RTL.MAKE.FILES"; const STRING KYAUTOVDIRS= "AUTOVDIRS"; // PIC definitions const STRING KYPIC= "PIC"; const STRING KYPIC_BUS= "PIC.BUS"; const STRING KYPIC_MAX= "PIC.MAX"; // Cache information const STRING KYCACHABLE_FILE="CACHABLE.FILE"; // SIM definitions const STRING KYSIM_INCLUDE= "SIM.INCLUDE"; const STRING KYSIM_DEFINES= "SIM.DEFINES"; const STRING KYSIM_DEFNS= "SIM.DEFNS"; const STRING KYSIM_PREINITIAL="SIM.PREINITIAL"; const STRING KYSIM_INIT= "SIM.INIT"; const STRING KYSIM_CLOCK= "SIM.CLOCK"; const STRING KYSIM_TICK= "SIM.TICK"; const STRING KYSIM_SETRESET= "SIM.SETRESET"; const STRING KYSIM_CLRRESET= "SIM.CLRRESET"; const STRING KYSIM_DBGCONDITION= "SIM.DBGCONDITION"; const STRING KYSIM_DEBUG= "SIM.DEBUG"; const STRING KYSIM_LOAD= "SIM.LOAD"; const STRING KYSIM_METHODS= "SIM.METHODS"; // SIM/Makefile definitions // const STRING KYSIM_MAKE_GROUP= "SIM.MAKE.GROUP"; // const STRING KYSIM_MAKE_FILES= "SIM.MAKE.FILES"; // const STRING KYSIM_MAKE_SUBD= "SIM.MAKE.SUBD"; // const STRING KYSIM_MAKE_VDIRS= "SIM.MAKE.VDIRS"; // const STRING KYTHIS="THIS"; const STRING KYTHISDOT="THIS."; // CLOCKS const STRING KYCLOCK="CLOCK"; const STRING KYCLOCK_NAME="CLOCK.NAME"; const STRING KYCLOCK_TOP="CLOCK.TOP"; const STRING KY_NAME="NAME"; const STRING KY_TOP="TOP"; const STRING KY_FREQUENCY="FREQUENCY"; const STRING KY_CLASS="CLASS"; // BUS definitions const STRING KYBUS = "BUS", KYBUS_NAME = "BUS.NAME", KYBUS_PREFIX = "BUS.PREFIX", KYBUS_TYPE = "BUS.TYPE", KYBUS_AWID = "BUS.AWID", KYBUS_IDWIDTH= "BUS.IDWIDTH", KYBUS_CLOCK = "BUS.CLOCK", KYBUS_NULLSZ = "BUS.NULLSZ", KY_TYPE = "TYPE", KY_WIDTH = "WIDTH", KY_IDWIDTH = "IDWIDTH", KY_AWID = "AWID", KY_CLOCK = "CLOCK", KY_RESET = "RESET", KY_NULLSZ = "NULLSZ", KY_NSELECT = "NSELECT", KYDEFAULT_BUS= "DEFAULT.BUS", KYREGISTER_BUS= "REGISTER.BUS", KYREGISTER_BUS_NAME= "REGISTER.BUS.NAME"; const STRING KY_OPT_LOWPOWER = "OPT_LOWPOWER", KY_OPT_LINGER = "OPT_LINGER", KY_OPT_LGMAXBURST = "OPT_LGMAXBURST", KY_OPT_TIMEOUT = "OPT_TIMEOUT", KY_OPT_STARVATION_TIMEOUT = "OPT_STARVATION_TIMEOUT", KY_OPT_DBLBUFFER = "OPT_DBLBUFFER"; // // ================================================ FILE: sw/keys.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/keys.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Defines the names of the strings AutoFPGA understands. These // are the key names understood by AutoFPGA and described by the // ICD. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef ICD_H #define ICD_H #include #include "mapdhash.h" // extern const STRING KYLEGAL; extern const STRING KYCOPYRIGHT; extern const STRING KYCMDLINE; extern const STRING KYSUBD; // Output subdirectory extern const STRING KYPATH; extern const STRING KYSUBD; // extern const STRING KYBUS_ADDRESS_WIDTH; extern const STRING KYSKIPADDR; extern const STRING KYRESET_ADDRESS; // For subclassing extern const STRING KYPLUSDOT; extern const STRING KYINCLUDEFILE; // Other global keys extern const STRING KYREGDEFS_CPP_INCLUDE; extern const STRING KYREGDEFS_CPP_INSERT; extern const STRING KYKEYS_TRIMLIST; extern const STRING KYKEYS_INTLIST; extern const STRING KYPROJECT; // extern const STRING KYSIO; extern const STRING KYDIO; extern const STRING KYSIO_SEL; extern const STRING KYDIO_SEL; // extern const STRING KYPREFIX; extern const STRING KYACCESS; extern const STRING KYDEPENDS; extern const STRING KYERROR_WIRE; extern const STRING KYSLAVE, KYSLAVE_TYPE, KYSLAVE_BUS, KYSLAVE_BUS_NAME, KYSLAVE_ORDER, KYSLAVE_AWID, KYSLAVE_OPTIONS, KYSLAVE_PREFIX, KYSLAVE_PORTLIST, KYSLAVE_ANSIPORTLIST, KYSLAVE_IANSI, KYSLAVE_OANSI, KYSLAVE_ANSPREFIX; extern const STRING KYMASTER, KYMASTER_TYPE, KYMASTER_BUS, KYMASTER_BUS_NAME, KYMASTER_PREFIX, KYMASTER_AWID, KYMASTER_OPTIONS, KYMASTER_PORTLIST, KYMASTER_ANSIPORTLIST, KYMASTER_IDWIDTH, KYMASTER_IANSI, KYMASTER_OANSI, KYMASTER_ANSPREFIX; // Types of bus masters. // KYBUS, (HOST), (VIDEO), (XCLOCK), and ... extern const STRING KYSUBBUS, KYARBITER, KYXCLOCK, KYHOST, KYCPU; // extern const STRING KYBASE; extern const STRING KYREGBASE; extern const STRING KYMASK; extern const STRING KYNADDR; // extern const STRING KYEXPR; extern const STRING KYVAL; extern const STRING KYFORMAT; extern const STRING KYSTR; // extern const STRING KYSCOPE; extern const STRING KYMEMORY; extern const STRING KYSINGLE; extern const STRING KYDOUBLE; extern const STRING KYOTHER; // extern const STRING KYNP; extern const STRING KYNPIC; extern const STRING KYNPSINGLE; extern const STRING KYNPDOUBLE; extern const STRING KYNPMEMORY; extern const STRING KYNSCOPES; // Regs definition(s) extern const STRING KYREGS_N; extern const STRING KYREGS_NOTE; extern const STRING KYREGDEFS_H_INCLUDE; extern const STRING KYREGDEFS_H_DEFNS; extern const STRING KYREGDEFS_H_INSERT; // Board definitions for C/C++ extern const STRING KYBDEF_INCLUDE; extern const STRING KYBDEF_DEFN; extern const STRING KYBDEF_IOTYPE; extern const STRING KYBDEF_OSDEF; extern const STRING KYBDEF_OSVAL; extern const STRING KYBDEF_INSERT; // Top definitions extern const STRING KYTOP_PORTLIST; extern const STRING KYTOP_IODECL; extern const STRING KYTOP_PARAM; extern const STRING KYTOP_DEFNS; extern const STRING KYTOP_MAIN; extern const STRING KYTOP_INSERT; // Main definitions extern const STRING KYMAIN_INCLUDE; extern const STRING KYMAIN_PORTLIST; extern const STRING KYMAIN_IODECL; extern const STRING KYMAIN_PARAM; extern const STRING KYMAIN_DEFNS; extern const STRING KYMAIN_INSERT; extern const STRING KYMAIN_ALT; // Definitions for the .ld file(s) extern const STRING KYLD_FILE; extern const STRING KYLD_SCRIPT; extern const STRING KYLD_ENTRY; extern const STRING KYLD_NAME; extern const STRING KYLD_PERM; extern const STRING KYLD_DEFNS; extern const STRING KYFLASH; extern const STRING KYSCRIPT; // XDC/UCF definitions extern const STRING KYXDC_FILE; extern const STRING KYXDC_INSERT; extern const STRING KYPCF_FILE; extern const STRING KYPCF_INSERT; extern const STRING KYLPF_FILE; extern const STRING KYLPF_INSERT; extern const STRING KYUCF_FILE; extern const STRING KYUCF_INSERT; // Arbitrary output data files extern const STRING KYOUT_FILE; extern const STRING KYOUT_DATA; // rtl/Makefile include file extern const STRING KYRTL_MAKE_GROUP; extern const STRING KYRTL_MAKE_SUBD; extern const STRING KYRTL_MAKE_VDIRS; extern const STRING KYRTL_MAKE_FILES; extern const STRING KYVFLIST; extern const STRING KYAUTOVDIRS; // PIC definitions extern const STRING KYPIC, KYPIC_BUS, KYPIC_MAX; // Cache information extern const STRING KYCACHABLE_FILE; // Interrupt definitions extern const STRING KY_INT, KYINTLIST, KY_WIRE, KY_DOTWIRE, KY_ID; // SIM definitions extern const STRING KYSIM_INCLUDE, KYSIM_DEFINES, KYSIM_DEFNS, KYSIM_PREINITIAL, KYSIM_INIT, KYSIM_TICK, KYSIM_SETRESET, KYSIM_CLRRESET, KYSIM_DBGCONDITION, KYSIM_DEBUG, KYSIM_LOAD, KYSIM_METHODS, KYSIM_CLOCK; // CLOCK definitions extern const STRING KYCLOCK, KYCLOCK_NAME, KYCLOCK_TOP, KY_NAME, KY_TOP, KY_CLASS, KY_FREQUENCY; // BUS definitions extern const STRING KYBUS, KYBUS_NAME, KYBUS_PREFIX, KYBUS_TYPE, KYBUS_WIDTH, KYBUS_IDWIDTH, KYBUS_AWID, KYBUS_CLOCK, KYBUS_NULLSZ, KY_TYPE, KY_WIDTH, KY_IDWIDTH, KY_AWID, KY_CLOCK, KY_RESET, KY_NULLSZ, KY_NSELECT, KYDEFAULT_BUS, KYREGISTER_BUS, KYREGISTER_BUS_NAME; // Bus options extern const STRING KY_OPT_LOWPOWER, KY_OPT_LINGER, KY_OPT_LGMAXBURST, KY_OPT_TIMEOUT, KY_OPT_STARVATION_TIMEOUT, KY_OPT_DBLBUFFER; // extern const STRING KYSTHIS; extern const STRING KYTHISDOT; #endif ================================================ FILE: sw/kveval.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/kveval.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include "mapdhash.h" #include "kveval.h" #include "keys.h" #include "ast.h" #include "msgs.h" typedef std::vector MAPSTACK; bool get_named_kvpair(MAPSTACK &stack, MAPDHASH &here, STRING &key, MAPDHASH::iterator &pair) { MAPDHASH::iterator kvpair, kvsub; if ((key[0]=='.')||(strncmp(key.c_str(), KYTHISDOT.c_str(), KYTHISDOT.size())==0)) { STRING subkey = (key[0]=='.')?key.substr(1) : key.substr(KYTHISDOT.size(), key.size()-KYTHISDOT.size()); pair = findkey(here, subkey); return (pair != here.end()); } else if (key[0] == '+') { STRING subkey = key.substr(2); MAPDHASH::iterator kvnxt; kvpair = findkey(here, KYPLUSDOT); if (kvpair == here.end()) // +. not found return false; if (kvpair->second.m_typ != MAPT_MAP) // It was found, but wasn't a MAP return false; kvsub = kvpair->second.u.m_m->begin(); kvnxt = kvsub; kvnxt++; assert(kvnxt == kvpair->second.u.m_m->end()); assert(kvsub->second.m_typ == MAPT_MAP); pair = findkey(*kvsub->second.u.m_m, subkey); /* if (pair != kvpair->second.u.m_m->end()) fprintf(stderr, " Found a key for %s\n", subkey.c_str()); else fprintf(stderr, " %s not found\n", subkey.c_str()); */ return (pair != kvpair->second.u.m_m->end()); } else if (key[0] == '/') { STRING subkey = key.substr(1); pair = findkey(*stack[0], subkey); return (pair != stack[0]->end()); // Ok, go first, look for things in the following order: // 1. here // 2. superclass (in a loop) // 3. parent (in a loop) // .... // 4. top } else if (here.end() != (pair = findkey(here, key))) { return true; } { int posn = (int)stack.size()-1; for(; posn>= 0; posn--) { pair =findkey(*stack[posn], key); if (pair != stack[posn]->end()) break; } if (posn >= 0) return true; } return false; } bool get_named_value(MAPSTACK &stack, MAPDHASH &here, STRING &key, int &value) { MAPDHASH::iterator kvpair; if (get_named_kvpair(stack, here, key, kvpair)) { if (kvpair->second.m_typ == MAPT_INT) { value = kvpair->second.u.m_v; return true; } else if (kvpair->second.m_typ == MAPT_MAP) { if (getvalue(*kvpair->second.u.m_m, value)) return true; } } return false; } STRINGP get_named_string(MAPSTACK &stack, MAPDHASH &here, STRING &key) { MAPDHASH::iterator kvpair; if (get_named_kvpair(stack, here, key, kvpair)) { if (kvpair->second.m_typ == MAPT_MAP) return getstring(*kvpair->second.u.m_m); if (kvpair->second.m_typ != MAPT_STRING) return NULL; if (NULL != strstr(kvpair->second.u.m_s->c_str(), "@$")) // Don't return a named value if it hasn't (yet) // been filled in within its current context return NULL; return kvpair->second.u.m_s; } return NULL; } void expr_eval(MAPSTACK &stack, MAPDHASH &here, MAPDHASH &sub, MAPT &expr) { AST *ast; if (expr.m_typ == MAPT_STRING) { ast = parse_ast(*expr.u.m_s); ast->define(stack, here); if (ast->isdefined()) { expr.m_typ = MAPT_INT; expr.u.m_v = ast->eval(); delete ast; } else { expr.m_typ = MAPT_AST; expr.u.m_a = ast; } } else if (expr.m_typ == MAPT_AST) { ast = expr.u.m_a; ast->define(stack, here); if (ast->isdefined()) { int v = (int)ast->eval(); expr.m_typ = MAPT_INT; expr.u.m_v = v; delete ast; } } } bool find_any_unevaluated_sub(MAPSTACK &stack, MAPDHASH *here, MAPDHASH &sub) { bool changed = false; MAPDHASH::iterator pfx = sub.end(), subi; MAPDHASH *component; pfx = sub.find(KYPREFIX); if (pfx != sub.end()) component = ⊂ else component = here; for(subi=sub.begin(); subi != sub.end(); subi++) { if (subi->second.m_typ == MAPT_MAP) { if (KYPLUSDOT.compare(subi->first) != 0) { // Don't recurse below any +. keys stack.push_back(subi->second.u.m_m); changed = find_any_unevaluated_sub(stack, component, *subi->second.u.m_m) || (changed); stack.pop_back(); } } else if (subi->first == KYEXPR) { if (subi->second.m_typ == MAPT_STRING) { expr_eval(stack, *component, sub, subi->second); if (subi->second.m_typ != MAPT_STRING) changed = true; } else if (subi->second.m_typ == MAPT_AST) { AST *ast = subi->second.u.m_a; ast->define(stack, *component); if (ast->isdefined()) { subi->second.m_typ = MAPT_INT; subi->second.u.m_v = ast->eval(); delete ast; changed = true; } } } else if (subi->second.m_typ == MAPT_AST) { AST *ast = subi->second.u.m_a; ast->define(stack, *component); if (ast->isdefined()) { int val = ast->eval(); subi->second.m_typ = MAPT_INT; subi->second.u.m_v = val; delete ast; changed = true; } } } return changed; } void find_any_unevaluated(MAPDHASH &info) { MAPDHASH::iterator topi; bool changed = false; MAPSTACK stack; stack.push_back(&info); do { for(topi=info.begin(); topi != info.end(); topi++) { if (topi->second.m_typ != MAPT_MAP) continue; changed = find_any_unevaluated_sub(stack, &info, *topi->second.u.m_m); } } while(changed); } bool subresults_into(MAPSTACK stack, MAPDHASH *here, STRINGP &sval) { bool changed = false, everchanged = false;; if (STRING::npos == (sval->find("@$"))) { return everchanged; } do { unsigned long sloc = -1; changed = false; sloc = 0; while(STRING::npos != (sloc = sval->find("@$", sloc))) { int kylen = 0, value, endpos, kystart, fstart, fend; const char *ptr = sval->c_str() + sloc + 2, *fmt = NULL; kystart = sloc+2; if (*ptr == '[') { fstart = kystart+1; fend = fstart; ptr++; fmt = ptr; for(; (*ptr)&&(*ptr != ']'); ptr++) fend++; assert(*ptr == ']'); assert((*sval)[fend] == ']'); ptr++; kystart = fend+1; fend -= fstart; } if (*ptr == '(') { kystart++; ptr++; if ((ptr[kylen] == '+') ||(ptr[kylen] == '!') ||(ptr[kylen] == '/')) kylen++; for(; (ptr[kylen]); kylen++) { if((!isalpha(ptr[kylen])) &&(!isdigit(ptr[kylen])) &&(ptr[kylen] != '_') &&(ptr[kylen] != '.')) break; } endpos = kylen+1+kystart-sloc; if (ptr[kylen] != ')') { gbl_msg.error("%s <<--\n", sval->c_str()); gbl_msg.error("Closing parentheses for %*s not found\n", kylen, ptr); } } else { if ((ptr[kylen] == '+') ||(ptr[kylen] == '!') ||(ptr[kylen] == '/')) kylen++; for(; ptr[kylen]; kylen++) { if((!isalpha(ptr[kylen])) &&(!isdigit(ptr[kylen])) &&(ptr[kylen] != '_') &&(ptr[kylen] != '.')) break; } endpos = kylen+kystart-sloc; } if (kylen > 0) { STRING key = sval->substr(kystart, kylen), *vstr; if ((fmt)&&(get_named_value(stack, *here, key, value))) { char *tbuf, *fcpy; fcpy = strdup(fmt); fcpy[fend]='\0'; STRING tmp; tbuf = new char[fend+64]; sprintf(tbuf, fcpy, value); tmp = tbuf; sval->replace(sloc, endpos, tmp); delete[] fcpy; delete[] tbuf; } else if (NULL != (vstr = get_named_string( stack, *here, key))) { sval->replace(sloc, endpos, *vstr); changed = true; } else if(get_named_value(stack,*here,key,value)) { char buffer[64]; STRING tmp; sprintf(buffer, "%d", value); tmp = buffer; sval->replace(sloc, endpos, tmp); changed = true; } else sloc++; } else sloc++; } everchanged = everchanged || changed; } while (changed); return everchanged; } STRINGP genstr(STRING fmt, int val) { char *buf = new char[fmt.size()+64]; STRINGP r; if (fmt.size() > 0) { sprintf(buf, fmt.c_str(), val); } else { sprintf(buf, "%d", val); } r = new STRING(buf); delete[] buf; return r; } // Return if anything changes bool resolve_ast_expressions(MAPDHASH &exmap) { MAPDHASH::iterator kvexpr, kvval, kvfmt, kvstr; MAPT elm; STRINGP strp; AST *ast; kvexpr = exmap.find(KYEXPR); kvval = exmap.find(KYVAL); kvfmt = exmap.find(KYFORMAT); kvstr = exmap.find(KYSTR); if (kvstr != exmap.end()) return false; if (kvexpr == exmap.end()) return false; if ((kvval != exmap.end())&&(kvval->second.m_typ == MAPT_INT)) { if((kvfmt != exmap.end())&&(kvfmt->second.m_typ == MAPT_STRING)) strp = genstr(*kvfmt->second.u.m_s,kvval->second.u.m_v); else strp = genstr(STRING(""),kvval->second.u.m_v); MAPT elm; elm.m_typ = MAPT_STRING; elm.u.m_s = strp; exmap.insert(KEYVALUE(KYSTR, elm)); return true; } if ((kvexpr != exmap.end())&&(kvexpr->second.m_typ == MAPT_STRING)) { AST *ast = parse_ast(*kvexpr->second.u.m_s); kvexpr->second.m_typ = MAPT_AST; kvexpr->second.u.m_a = ast; } if ((kvexpr != exmap.end()) &&((kvexpr->second.m_typ == MAPT_AST) ||(kvexpr->second.m_typ == MAPT_INT))) { if (kvexpr->second.m_typ == MAPT_AST) { ast = kvexpr->second.u.m_a; if (!ast->isdefined()) { return false; } kvexpr->second.m_typ = MAPT_INT; kvexpr->second.u.m_v = ast->eval(); delete ast; } elm.m_typ = MAPT_INT; elm.u.m_v = kvexpr->second.u.m_v; exmap.insert(KEYVALUE(KYVAL, elm)); resolve_ast_expressions(exmap); return true; } return false; } bool substitute_any_results_sub(MAPSTACK &stack, MAPDHASH *here, MAPDHASH &sub) { MAPDHASH::iterator pfx = sub.end(), subi, kvelm, kvstr, kvfmt; MAPDHASH *component; bool v = false; pfx = sub.find(KYPREFIX); if (pfx != sub.end()) component = ⊂ else component = here; for(subi=sub.begin(); subi != sub.end(); subi++) { if (subi->second.m_typ == MAPT_MAP) { if ((KYPLUSDOT.compare(subi->first)!=0) &&(subi->first.size()>0)) { stack.push_back(subi->second.u.m_m); substitute_any_results_sub(stack, component, *subi->second.u.m_m); stack.pop_back(); kvelm = subi->second.u.m_m->find(KYEXPR); kvstr = subi->second.u.m_m->find(KYSTR); kvfmt = subi->second.u.m_m->find(KYFORMAT); if ((kvstr == subi->second.u.m_m->end()) &&(kvelm != subi->second.u.m_m->end())) { v = resolve_ast_expressions(*subi->second.u.m_m) || v; } } } else if (subi->second.m_typ == MAPT_STRING) { v = subresults_into(stack, here, subi->second.u.m_s) ||v; } } return v; } bool substitute_any_results(MAPDHASH &info) { MAPSTACK stack; stack.push_back(&info); return substitute_any_results_sub(stack, &info, info); } void reeval(MAPDHASH &info) { do { // First, find expressions that need evalution find_any_unevaluated(info); // Then, substitute their results back in as necessary } while(substitute_any_results(info)); } void reeval(MAPDHASH *info) { assert(info); reeval(*info); } ================================================ FILE: sw/kveval.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/kveval.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To define the interface whereby values within the key-value hash // can be both computed, and substituted/replaced as necessary. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef KVEVAL_H #define KVEVAL_H #include #include "mapdhash.h" #include "globals.h" #define REHASH do { gbl_msg.info("REEVAL %s:%d\n", __FILE__, __LINE__); reeval(gbl_hash); gbl_msg.dump(*gbl_hash); } while(0) typedef std::vector MAPSTACK; bool get_named_kvpair(MAPSTACK &stack, MAPDHASH &here, STRING &key, MAPDHASH::iterator &pair); bool get_named_value(MAPSTACK &stack, MAPDHASH &here, STRING &key, int &value); STRINGP get_named_string(MAPSTACK &stack, MAPDHASH &here, STRING &key); extern bool resolve_ast_expressions(MAPDHASH &info); extern void reeval(MAPDHASH &info); extern void reeval(MAPDHASH *info); #endif ================================================ FILE: sw/legalnotice.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/legalnotice.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: Defines a routine that can be used to copy a legal notice // into a stream. Modifications are made to the comments along // the way, as appropriate for the type of stream. Specific modifications // include: // // Places the name of the file at the top of the file, assuming a // Filename: key (as above) is found within the file. // // Adds the project name from the KYPROJECT key to the Project: line // (as above) the project name with the KYPROJECT // // Places a notice in the file that it was automatically generated. This // notice includes the autofpga command line. // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "mapdhash.h" #include "parser.h" #include "keys.h" #include "kveval.h" #include "msgs.h" extern FILE *open_in(MAPDHASH &info, const STRING &fname); // // Place a legal notice at the top of every file. The legal notice is given // to us as a filename, which we must then open and parse. // // We also do several substitutions here, given by the strings below. This // allows us to mark all of our produced files with their names within them, // as well as marking the project that they are associated with. // void legal_notice(MAPDHASH &info, FILE *fp, STRING &fname, const char *cline = NULL, const char *comment = "//") { char line[512]; FILE *lglfp; STRING str; STRINGP legal_fname = getstring(info, str = KYLEGAL); if (!legal_fname) { fprintf(stderr, "WARNING: NO COPYRIGHT NOTICE\n\nPlease be considerate and license your project under the GPL\n"); fprintf(fp, "%s WARNING: NO COPYRIGHT NOTICE\n\n%s Please be considerate and license this under the GPL\n", comment, comment); return; } lglfp = open_in(info, *legal_fname); if (!lglfp) { gbl_msg.error("Cannot open copyright notice file, %s\n", legal_fname->c_str()); fprintf(fp, "%s WARNING: NO COPYRIGHT NOTICE\n\n" "%s Please be considerate and license this project under the GPL\n", comment, comment); perror("O/S Err:"); return; } while(fgets(line, sizeof(line), lglfp)) { static const char kyfname[] = "// Filename:", kyproject[] = "// Project:", kycmdline[] = "// CmdLine:", kycomment[] = "//", kycline[] = "///////////////////////////////////////////////////////////////////////"; if (strncasecmp(line, kyfname, strlen(kyfname))==0) { fprintf(fp, "%s %s\t%s\n", comment, &kyfname[3], fname.c_str()); } else if (strncasecmp(line, kyproject, strlen(kyproject))==0) { STRINGP strp; if (NULL != (strp = getstring(info, KYPROJECT))) fprintf(fp, "%s %s\t%s\n", comment, &kyproject[3], strp->c_str()); else fputs(line, fp); } else if (strncasecmp(line, kycmdline, strlen(kycmdline))==0){ STRINGP strp = getstring(info, KYCMDLINE); if (strp) fprintf(fp, "%s %s\t%s\n", comment, &kycmdline[3], strp->c_str()); else { fprintf(fp, "%s\t(No command line data found)\n", kycmdline); } }else if((cline)&&(strncmp(line, kycline, strlen(kycline))==0)){ fprintf(fp, "%s\n", cline); } else if (strncmp(line, kycomment, strlen(kycomment))==0) { fprintf(fp, "%s%s", comment, &line[strlen(kycomment)]); } else fputs(line, fp); } } ================================================ FILE: sw/legalnotice.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/legalnotice.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef LEGALNOTICE_H #include #include #include #include "mapdhash.h" #include "parser.h" // Insert a given legal notice into the FILE stream // // 1. We'll adjust the projuct line for the current project // 2. We'll also add a notice that the file so created was computer generated, // and thus should not be edited // 3. This notice will include our command line as well // extern void legal_notice(MAPDHASH &info, FILE *fp, STRING &fname, const char *cline = NULL, const char *comment = "//"); #endif ================================================ FILE: sw/mapdhash.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/mapdhash.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To handle processing our key-value pair data structure. This // is the fundamental data structure used to maintain AutoFPGA's // data store, and so it is used throughout. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include "parser.h" #include "keys.h" #include "ast.h" #include "kveval.h" #include "globals.h" #include "msgs.h" MAPT operator+(MAPT a, MAPT b) { char *sbuf; switch(a.m_typ) { case MAPT_STRING: switch(b.m_typ) { case MAPT_STRING: sbuf = new char[a.u.m_s->length() +b.u.m_s->length()+4]; sprintf(sbuf, "%s %s", a.u.m_s->c_str(), b.u.m_s->c_str()); a.u.m_s = new STRING(sbuf); delete sbuf; break; case MAPT_INT: sbuf = new char[a.u.m_s->length()+32]; sprintf(sbuf, "%s + %d", a.u.m_s->c_str(), b.u.m_v); a.u.m_s = new STRING(sbuf); delete sbuf; break; case MAPT_AST: fprintf(stderr, "WARNING: Dont know how to add STRING to AST\n"); break; default: fprintf(stderr, "WARNING: Dont know how to add STRING to other than INT or STRING\n"); } break; case MAPT_INT: switch(b.m_typ) { case MAPT_STRING: a.m_typ = MAPT_AST; a.u.m_a = new AST_BRANCH( '+', new AST_NUMBER(a.u.m_v), parse_ast(*b.u.m_s)); break; case MAPT_INT: // a.m_typ = MAPT_INT; a.u.m_v += b.u.m_v; break; case MAPT_AST: a.m_typ = MAPT_AST; a.u.m_a = new AST_BRANCH( '+', new AST_NUMBER(a.u.m_v), b.u.m_a); break; default: fprintf(stderr, "WARNING: Dont know how to add INT to a MAP\n"); } break; case MAPT_AST: switch(b.m_typ) { case MAPT_STRING: a.u.m_a = new AST_BRANCH( '+', a.u.m_a, parse_ast(*b.u.m_s)); break; case MAPT_INT: a.m_typ = MAPT_AST; a.u.m_a = new AST_BRANCH('+', a.u.m_a, new AST_NUMBER(b.u.m_v)); break; case MAPT_AST: a.u.m_a = new AST_BRANCH('+', a.u.m_a, b.u.m_a); break; default: fprintf(stderr, "WARNING: Dont know how to add AST to a MAP\n"); } break; default: fprintf(stderr, "1. DONT KNOW HOW TO ADD TWO MAPS TOGETHER (%d and %d)\n", a.m_typ, b.m_typ); if (a.m_typ == MAPT_MAP) mapdump(*a.u.m_m); if (b.m_typ == MAPT_MAP) mapdump(*b.u.m_m); } return a; } MAPT operator+(MAPT a, const STRING b) { char *sbuf; switch(a.m_typ) { case MAPT_STRING: sbuf = new char[a.u.m_s->length() +b.length()+4]; sprintf(sbuf, "%s %s", a.u.m_s->c_str(), b.c_str()); a.u.m_s = new STRING(sbuf); delete sbuf; break; case MAPT_INT: a.m_typ = MAPT_AST; a.u.m_a = new AST_BRANCH( '+', new AST_NUMBER(a.u.m_v), parse_ast(b)); break; case MAPT_AST: a.u.m_a = new AST_BRANCH( '+', a.u.m_a, parse_ast(b)); break; default: fprintf(stderr, "2. DONT KNOW HOW TO ADD A MAP TO A STRING (%d)\n", a.m_typ); mapdump(*a.u.m_m); } return a; } STRING *trim(const STRING &s) { const char *a, *b; STRINGP strp; a = s.c_str(); b = s.c_str() + s.length()-1; for(; (*a)&&(a<=b); a++) if (!isspace(*a)) break; for(; (b>a); b--) if (!isspace(*b)) break; strp = new STRING(s.substr(a-s.c_str(), b-a+1)); return strp; } bool splitkey(const STRING &ky, STRING &mkey, STRING &subky) { size_t pos; if (((pos=ky.find('.')) != STRING::npos) &&(pos != 0) &&(pos < ky.length()-1)) { mkey = ky.substr(0,pos); subky = ky.substr(pos+1,ky.length()-pos+1); assert(subky.length() > 0); return true; } return false; } void addtomap(MAPDHASH &fm, STRING ky, STRING vl) { STRING mkey, subky; STRINGP trimmed; bool astnode = false, pluskey = false; MAPT subfm; MAPDHASH::iterator subloc = fm.end(); trimmed = trim(ky); if ((*trimmed)[0] == '@') { STRINGP tmp = new STRING(trimmed->substr(1)); delete trimmed; trimmed = tmp; } if ((*trimmed)[0] == '$') { astnode = true; STRINGP tmp = new STRING(trimmed->substr(1)); delete trimmed; trimmed = tmp; } if (((*trimmed)[0] == '+')&&((*trimmed)[1]!='.')) { pluskey = true; STRINGP tmp = new STRING(trimmed->substr(1)); delete trimmed; trimmed = tmp; } if (splitkey(*trimmed, mkey, subky)) { MAPDHASH::iterator subloc = fm.find(mkey); delete trimmed; if ((subloc == fm.end())&&(pluskey)) subloc = fm.find(STRING("+")+mkey); else if (subloc == fm.end()) { subloc = fm.find(STRING("+")+mkey); if (subloc != fm.end()) { // REMOVE anything on conlict fm.erase(subloc); subloc = fm.end(); } } if (subloc == fm.end()) { subfm.m_typ = MAPT_MAP; subfm.u.m_m = new MAPDHASH; fm.insert(KEYVALUE(mkey, subfm ) ); } else { subfm = (*subloc).second; } if ((!pluskey)&&(subfm.m_typ != MAPT_MAP)) { return; } else if (subfm.m_typ == MAPT_MAP) { if (pluskey) subky = STRING("+") + subky; if (astnode) subky = STRING("$") + subky; addtomap(*subfm.u.m_m, subky, vl); return; } } else { subloc = fm.find(*trimmed); if ((subloc == fm.end())&&(pluskey)) subloc = fm.find(STRING("+")+(*trimmed)); if(subloc != fm.end()) { subfm = subloc->second; } } if ((astnode)&&(*trimmed != KYEXPR)) { if (subloc == fm.end()) { MAPDHASH *node; MAPT elm; elm.m_typ = MAPT_MAP; elm.u.m_m = node = new MAPDHASH; fm.insert(KEYVALUE(*trimmed, elm)); addtomap(*node, STRING("$")+STRING((pluskey)?"+":"")+KYEXPR, vl); return; } else if (subfm.m_typ == MAPT_MAP) { addtomap(*subfm.u.m_m, STRING("$")+STRING((pluskey)?"+":"")+KYEXPR, vl); return; } } MAPT elm; if (pluskey) { if (subloc == fm.end()) { MAPT elm; if (astnode) { elm.m_typ = MAPT_AST; elm.u.m_a = parse_ast(vl); } else { elm.m_typ = MAPT_STRING; elm.u.m_s = new STRING(vl); } fm.insert(KEYVALUE(STRING("+")+(*trimmed), elm)); } else { subloc->second = subfm + vl; } } else if (astnode) { if ((*trimmed)!=KYEXPR) { MAPDHASH *node; elm.m_typ = MAPT_MAP; elm.u.m_m = node = new MAPDHASH; fm.insert(KEYVALUE(*trimmed, elm)); addtomap(*node, STRING("$")+STRING((pluskey)?"+":"")+KYEXPR, vl); } else { elm.m_typ = MAPT_AST; elm.u.m_a = parse_ast(vl); if (NULL == elm.u.m_a) gbl_msg.fatal("Could not parse %s\n", vl.c_str()); fm.insert(KEYVALUE(*trimmed, elm ) ); if ((elm.u.m_a->isdefined())&&(*trimmed == KYEXPR)) { AST *ast = elm.u.m_a; elm.m_typ = MAPT_INT; elm.u.m_v = (int)ast->eval(); fm.insert(KEYVALUE(KYVAL, elm)); } delete trimmed; return; } } else if (subloc == fm.end()) { elm.m_typ = MAPT_STRING; elm.u.m_s = new STRING(vl); fm.insert(KEYVALUE(*trimmed, elm ) ); } else { subfm.m_typ = MAPT_STRING; subfm.u.m_s = new STRING(vl); } delete trimmed; } void mapdump_aux(FILE *fp, MAPDHASH &fm, int offset) { MAPDHASH::iterator kvpair; if (!fp) return; for(kvpair = fm.begin(); kvpair != fm.end(); kvpair++) { if (offset == 0) fprintf(fp, "\n"); fprintf(fp, "%*s%s: ", offset, "", (*kvpair).first.c_str()); if ((*kvpair).second.m_typ == MAPT_MAP) { fprintf(fp, "\n"); mapdump_aux(fp, *(*kvpair).second.u.m_m, offset+1); } else if ((*kvpair).second.m_typ == MAPT_INT) { fprintf(fp, "%d\n", (*kvpair).second.u.m_v); } else if ((*kvpair).second.m_typ == MAPT_AST) { AST *ast = kvpair->second.u.m_a; fprintf(fp, ""); if (ast->isdefined()) { fprintf(fp, "\tDEFINED and = %08lx\n", ast->eval()); } else fprintf(fp, "\tNot defined\n"); ast->dump(fp, offset+4); } else { // if ((*kvpair).second.m_typ == MAPT_STRING) STRINGP s = (*kvpair).second.u.m_s; size_t pos; if ((pos=s->find("\n")) == STRING::npos) { fprintf(fp, "%s\n", s->c_str()); } else if (pos == s->length()-1) { fprintf(fp, "%s", s->c_str()); } else { fprintf(fp, "\n"); fprintf(fp, "%s\n----------------\n", s->c_str()); } } } } void mapdump(FILE *fp, MAPDHASH &fm) { if (!fp) return; fprintf(fp, "\n================\nFULL HASH DUMP!!\n================\n"); mapdump_aux(fp, fm, 0); } void mapdump(MAPDHASH &fm) { mapdump_aux(stdout, fm, 0); } void mapdump(FILE *fp, MAPT &elm) { if (!fp) return; switch(elm.m_typ) { case MAPT_STRING: fprintf(fp, "DUMP: %s\n", elm.u.m_s->c_str()); fflush(fp); break; case MAPT_INT: fprintf(fp, "DUMP: %d\n", elm.u.m_v); fflush(fp); break; case MAPT_AST: fprintf(fp, "(AST)\n"); fflush(fp); break; case MAPT_MAP: mapdump_aux(fp, *elm.u.m_m, 0); fflush(fp); break; } } // // Merge two maps, a master and a sub // void mergemaps(MAPDHASH &master, MAPDHASH &sub) { MAPDHASH::iterator kvmaster, kvsub; for(kvsub = sub.begin(); kvsub != sub.end(); kvsub++) { bool pluskey; pluskey = (kvsub->first.c_str()[0] == '+'); if (kvsub->second.m_typ == MAPT_MAP) { kvmaster = master.find(kvsub->first); if (kvmaster == master.end()) { // Not found master.insert(KEYVALUE((*kvsub).first, (*kvsub).second ) ); } else if (kvmaster->second.m_typ == MAPT_MAP) { mergemaps(*kvmaster->second.u.m_m, *kvsub->second.u.m_m); } else { fprintf(stderr, "NAME CONFLICT! Files not merged\n"); } } else if (pluskey) { // Does the key already exist in the map? if(kvsub->first.length() > 1) { kvmaster = master.find(kvsub->first.substr(1)); if (kvmaster == master.end()) kvmaster = master.find(kvsub->first); } else kvmaster = master.find(kvsub->first); if (kvmaster == master.end()) // No, this key doesn't exist. Let's insert it master.insert(KEYVALUE(kvsub->first, kvsub->second)); else kvmaster->second = kvmaster->second + kvsub->second; } else master.insert(KEYVALUE(kvsub->first, kvsub->second)); } } /* * trimkey * * Given a key to a string within the current map level, trim all spaces from * that key. Do NOT recurse if the key is not found. */ void trimkey(MAPDHASH &mp, const STRING &sky) { MAPDHASH::iterator kvpair, kvsecond; STRING mkey, subky; if (splitkey(sky, mkey, subky)) { if (mp.end() != (kvpair=mp.find(mkey))) { if (kvpair->second.m_typ == MAPT_MAP) { trimkey(*kvpair->second.u.m_m, subky); } } } else for(kvpair = mp.begin(); kvpair != mp.end(); kvpair++) { if ((*kvpair).second.m_typ == MAPT_STRING) { if ((*kvpair).first == sky) { STRINGP tmps = (*kvpair).second.u.m_s; (*kvpair).second.u.m_s = trim(*tmps); delete tmps; } } } } /* * trimall * * Find all keys of the given name, then find the strings they refer to, then * trim any white space from those strings. */ void trimall(MAPDHASH &mp, const STRING &sky) { MAPDHASH::iterator kvpair, kvsecond; STRING mkey, subky; if (splitkey(sky, mkey, subky)) { if (mp.end() != (kvpair=mp.find(mkey))) { if (kvpair->second.m_typ == MAPT_MAP) { // Cannot recurse further, else the key M.S // would cause keys M.*.S to be trimmed as well. // Hence we now force this to be an absolute // reference trimkey(*kvpair->second.u.m_m, subky); } } } for(kvpair = mp.begin(); kvpair != mp.end(); kvpair++) { if ((*kvpair).second.m_typ == MAPT_MAP) { trimall(*(*kvpair).second.u.m_m, sky); } else if ((*kvpair).second.m_typ == MAPT_STRING) { if ((*kvpair).first == sky) { STRINGP tmps = (*kvpair).second.u.m_s; (*kvpair).second.u.m_s = trim(*tmps); delete tmps; } } } } /* * trimbykeylist * * Look for all map elements with the given keylist, and apply trimall to * all elements within their respective maps */ void trimbykeylist(MAPDHASH &mp, const STRING &kylist) { STRINGP strp; if (NULL != (strp = getstring(mp, kylist))) { static const char delimiters[] = " \t\n,"; STRING scpy = *strp; char *tok = strtok((char *)scpy.c_str(), delimiters); while(NULL != tok) { trimall(mp, STRING(tok)); tok = strtok(NULL, delimiters); } } } void trimbykeylist(MAPT &elm, const STRING &kylist) { if (elm.m_typ == MAPT_MAP) trimbykeylist(*elm.u.m_m, kylist); } /* * cvtintbykeylist * * Very similar to trimbykeylist, save that in this case we use the keylist * to determine what to convert to integers. */ void cvtintbykeylist(MAPDHASH &mp, const STRING &kylist) { STRINGP strp; if (NULL != (strp = getstring(mp, kylist))) { static const char delimiters[] = " \t\n,"; STRING scpy = *strp; char *tok = strtok((char *)scpy.c_str(), delimiters); while(NULL != tok) { cvtint(mp, STRING(tok)); tok = strtok(NULL, delimiters); } } /* MAPDHASH::iterator kvpair; for(kvpair=mp.begin(); kvpair != mp.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; cvtintbykeylist(kvpair->second, kylist); } */ } void cvtintbykeylist(MAPT &elm, const STRING &kylist) { if (elm.m_typ == MAPT_MAP) cvtintbykeylist(*elm.u.m_m, kylist); } /* * cvtint * * Traverse the map looking for all keys named sky, and convert them to * integer values */ void cvtint(MAPDHASH &mp, const STRING &sky) { MAPDHASH::iterator kvpair; STRING mkey, subky; if (splitkey(sky, mkey, subky)) { if (mp.end() != (kvpair=mp.find(mkey))) { if (kvpair->second.m_typ == MAPT_MAP) { cvtint(*kvpair->second.u.m_m, subky); } } else for(kvpair = mp.begin(); kvpair != mp.end(); kvpair++) { if (kvpair->second.m_typ == MAPT_MAP) { cvtint(*kvpair->second.u.m_m, sky); } } } else for(kvpair = mp.begin(); kvpair != mp.end(); kvpair++) { if ((*kvpair).second.m_typ == MAPT_MAP) { cvtint(*(*kvpair).second.u.m_m, sky); } else if ((*kvpair).second.m_typ == MAPT_STRING) { if ((*kvpair).first == sky) { STRINGP tmps = (*kvpair).second.u.m_s; (*kvpair).second.m_typ = MAPT_INT; (*kvpair).second.u.m_v=strtoul(tmps->c_str(), NULL, 0); delete tmps; } } } } MAPDHASH::iterator findkey_aux(MAPDHASH &master, const STRING &ky, const STRING &pre) { STRING mkey, subky; MAPDHASH::iterator result; if (splitkey(ky, mkey, subky)) { MAPDHASH::iterator subloc = master.find(mkey); if (subloc == master.end()) { // Check any super classes for a definition of this key if ((master.end() != (subloc = master.find(KYPLUSDOT))) &&(subloc->second.m_typ == MAPT_MAP)) { result = findkey_aux(*subloc->second.u.m_m, ky, pre); if (result == subloc->second.u.m_m->end()) return master.end(); return result; } return subloc; } else { MAPT subfm; subfm = (*subloc).second; if (subfm.m_typ != MAPT_MAP) { /* fprintf(stderr, "ERR: MAP[%s.%s] isnt a map\n", pre.c_str(), mkey.c_str()); */ // assert(subfm->m_typ == MAPT_MAP) return master.end(); } // printf("Recursing on %s\n", mkey.c_str()); STRING new_pre_key = pre+"."+mkey; result = findkey_aux(*subfm.u.m_m, subky, new_pre_key); if (result == subfm.u.m_m->end()) { // printf("Subkey not found\n"); return master.end(); } return result; } } result = master.find(ky); return result; } MAPDHASH::iterator findkey(MAPDHASH &master, const STRING &ky) { STRING empty(""); return findkey_aux(master, ky, empty); } MAPDHASH *getmap(MAPDHASH &master, const STRING &ky) { MAPDHASH::iterator r; r = findkey(master, ky); if (r == master.end()) return NULL; else if (r->second.m_typ != MAPT_MAP) return NULL; return r->second.u.m_m; } MAPDHASH *getmap(MAPDHASH *mp, const STRING &ky) { if (!mp) return NULL; return getmap(*mp, ky); } STRINGP getstring(MAPDHASH &m) { MAPDHASH::iterator r; resolve_ast_expressions(m); // Can we build this string? r = m.find(KYSTR); if (r != m.end()) { if (r->second.m_typ == MAPT_STRING) return r->second.u.m_s; } return NULL; } STRINGP getstring(MAPDHASH &master, const STRING &ky) { MAPDHASH::iterator r; STRINGP prefix; r = findkey(master, ky); if (r == master.end()) return NULL; else if (r->second.m_typ == MAPT_MAP) { // MAPDHASH *m = r->second.u.m_m; STRINGP strp; // Check for a .STR key within this node strp = getstring(master); if (NULL == strp) { MAPDHASH::iterator kvprefix= findkey(master, KYPREFIX); if ((kvprefix != master.end())&&(kvprefix->second.m_typ == MAPT_STRING)) prefix = kvprefix->second.u.m_s; else prefix = new STRING("(Unknown context)"); gbl_msg.error("STRING expression for KEY \"%s\"" " in %s isnt a string!!\n\t... it's a map," " with sub-elements\n", ky.c_str(), prefix->c_str()); } return strp; } else if (r->second.m_typ != MAPT_STRING) { MAPDHASH::iterator kvprefix= findkey(master, KYPREFIX); if ((kvprefix != master.end())&&(kvprefix->second.m_typ == MAPT_STRING)) prefix = kvprefix->second.u.m_s; else prefix = new STRING("(Unknown context)"); gbl_msg.error("STRING expression for KEY \"%s\" in %s isnt a string!!\n", ky.c_str(), prefix->c_str()); return NULL; } return r->second.u.m_s; } STRINGP getstring(MAPDHASH *m, const STRING &ky) { if (!m) return NULL; return getstring(*m, ky); } STRINGP getstring(MAPT &m, const STRING &ky) { if (m.m_typ != MAPT_MAP) return NULL; return getstring(*m.u.m_m, ky); } void setstring(MAPDHASH &master, const STRING &ky, STRINGP strp) { MAPDHASH::iterator kvpair, kvsub; if (strp == NULL) { assert(0); return; } kvpair = findkey(master, ky); if (kvpair == master.end()) { // The given key was not found in the hash STRING mkey, subky; if (splitkey(ky, mkey, subky)) { MAPT subfm; MAPDHASH::iterator subloc = master.find(mkey); if (subloc == master.end()) { // Create a map to hold our value subfm.m_typ = MAPT_MAP; subfm.u.m_m = new MAPDHASH; master.insert(KEYVALUE(mkey, subfm ) ); } else { // The map exists, let's reference it subfm = (*subloc).second; if (subfm.m_typ != MAPT_MAP) { fprintf(stderr, "ERR: MAP[%s] isnt a map\n", mkey.c_str()); return; } } setstring(*subfm.u.m_m, subky, strp); return; } MAPT elm; elm.m_typ = MAPT_STRING; elm.u.m_s = strp; master.insert(KEYVALUE(ky, elm ) ); } else if (kvpair->second.m_typ == MAPT_MAP) { MAPDHASH *subhash = kvpair->second.u.m_m; kvsub = subhash->find(KYSTR); if (kvsub == subhash->end()) { MAPT elm; elm.m_typ = MAPT_STRING; elm.u.m_s = strp; kvsub->second.u.m_m->insert(KEYVALUE(KYVAL, elm)); } else { kvsub->second.m_typ = MAPT_STRING; kvsub->second.u.m_s = strp; } } else if (kvpair->second.m_typ == MAPT_STRING) { kvpair->second.u.m_s = strp; } } void setstring(MAPDHASH &master, const STRING &ky, const STRING &str) { return setstring(master, ky, new STRING(str)); } void setstring(MAPDHASH *mp, const STRING &ky, STRINGP strp) { assert(mp); return setstring(*mp, ky, strp); } void setstring(MAPDHASH *mp, const STRING &ky, const STRING &str) { assert(mp); return setstring(*mp, ky, new STRING(str)); } void setstring(MAPT &m, const STRING &ky, STRINGP strp) { setstring(*m.u.m_m, ky, strp); } bool getvalue(MAPDHASH &map, int &value) { MAPDHASH::iterator kvpair; kvpair = map.find(KYVAL); if (kvpair != map.end()) { value = kvpair->second.u.m_v; return (kvpair->second.m_typ == MAPT_INT); } kvpair = map.find(KYEXPR); if (kvpair == map.end()) return false; if (kvpair->second.m_typ == MAPT_AST) { AST *ast; ast = kvpair->second.u.m_a; if (ast->isdefined()) { kvpair->second.m_typ = MAPT_INT; kvpair->second.u.m_v = ast->eval(); delete ast; } else return false; } if (kvpair->second.m_typ == MAPT_INT) { /* MAPT elm; elm.m_typ = MAPT_INT; elm.u.m_v = kvpair->second.u.m_v; map.insert(KEYVALUE(KYVAL, elm)); value = elm.u.m_v; */ value=kvpair->second.u.m_v; return true; } return false; } bool getvalue(MAPDHASH &master, const STRING &ky, int &value) { MAPDHASH::iterator r; value = -1; r = findkey(master, ky); if (r == master.end()) { return false; } else if (r->second.m_typ == MAPT_MAP) { return getvalue(*r->second.u.m_m, value); } else if (r->second.m_typ == MAPT_AST) { AST *ast = r->second.u.m_a; if (ast->isdefined()) { r->second.m_typ = MAPT_INT; r->second.u.m_v = ast->eval(); delete ast; } else return false; } else if (r->second.m_typ == MAPT_STRING) { value = strtoul(r->second.u.m_s->c_str(), NULL, 0); return true; } else if (r->second.m_typ != MAPT_INT) { return false; } value = r->second.u.m_v; return true; } bool getvalue(MAPDHASH *mp, const STRING &ky, int &value) { if (!mp) return false; return getvalue(*mp, ky, value); } void setvalue(MAPDHASH &master, const STRING &ky, int value) { MAPDHASH::iterator kvpair, kvsub; kvpair = findkey(master, ky); if (kvpair == master.end()) { STRING mkey, subky; STRINGP trimmed; trimmed = trim(ky); if ((*trimmed)[0] == '@') { STRINGP tmp = new STRING(trimmed->substr(1,trimmed->size())); delete trimmed; trimmed = tmp; } if ((*trimmed)[0] == '$') { STRINGP tmp = new STRING(trimmed->substr(1,trimmed->size())); delete trimmed; trimmed = tmp; } if (splitkey(*trimmed, mkey, subky)) { MAPT subfm; MAPDHASH::iterator subloc = master.find(mkey); delete trimmed; if (subloc == master.end()) { // Create a map to hold our value subfm.m_typ = MAPT_MAP; subfm.u.m_m = new MAPDHASH; master.insert(KEYVALUE(mkey, subfm ) ); } else { // The map exists, let's reference it subfm = (*subloc).second; if (subfm.m_typ != MAPT_MAP) { fprintf(stderr, "MAP[%s] isnt a map\n", mkey.c_str()); return; } } setvalue(*subfm.u.m_m, subky, value); return; } MAPT elm; elm.m_typ = MAPT_INT; elm.u.m_v = value; master.insert(KEYVALUE(*trimmed, elm ) ); delete trimmed; } else if (kvpair->second.m_typ == MAPT_MAP) { MAPDHASH *subhash = kvpair->second.u.m_m; kvsub = subhash->find(KYVAL); if (kvsub == subhash->end()) { MAPT elm; elm.m_typ = MAPT_INT; elm.u.m_v = value; kvsub->second.u.m_m->insert(KEYVALUE(KYVAL, elm)); } else { kvsub->second.m_typ = MAPT_INT; kvsub->second.u.m_v = value; } } } MAPDHASH *copy(MAPDHASH *top) { MAPDHASH *cp = new MAPDHASH(); MAPDHASH::iterator kvpair; for(kvpair = top->begin(); kvpair != top->end(); kvpair++) { MAPT elm; elm.m_typ = kvpair->second.m_typ; if (kvpair->second.m_typ == MAPT_INT) elm.u.m_v = kvpair->second.u.m_v; else if (kvpair->second.m_typ == MAPT_STRING) elm.u.m_s = new STRING(*kvpair->second.u.m_s); else if (kvpair->second.m_typ == MAPT_MAP) elm.u.m_m = copy(kvpair->second.u.m_m); else if (kvpair->second.m_typ == MAPT_AST) elm.u.m_a = copy(kvpair->second.u.m_a); else { gbl_msg.fatal("in COPY(MAP)::UNKNOWN TYPE, %d\n", kvpair->second.m_typ); } cp->insert(KEYVALUE(kvpair->first, elm)); } return cp; } void flatten_maps(MAPDHASH &node, MAPDHASH &sub, STRING &here) { MAPDHASH::iterator kvpair, nodepair; gbl_msg.info("FLATT-MAP\n"); // // Search for subnodes that are not maps within node // for(kvpair = sub.begin(); kvpair!=sub.end(); kvpair++) { nodepair = node.find(kvpair->first); if (nodepair == node.end()) { // // The subnode key, from a plus map, does not exist // in the parent. Copy it into the parent therefore. // gbl_msg.info("Key not found, %s + %s, " "inheriting key\n", here.c_str(), kvpair->first.c_str()); MAPT elm; elm.m_typ = kvpair->second.m_typ; if (kvpair->second.m_typ == MAPT_INT) { // Copy an integer key elm.u.m_v = kvpair->second.u.m_v; } else if (kvpair->second.m_typ == MAPT_STRING) { // Copy a string elm.u.m_s = new STRING(*kvpair->second.u.m_s); } else if (kvpair->second.m_typ == MAPT_MAP) { // Copy a MAP elm.u.m_m = copy(kvpair->second.u.m_m); } else if (kvpair->second.m_typ == MAPT_AST) { // Copy a AST/expression elm.u.m_a = copy(kvpair->second.u.m_a); } else // Otherwise, I have no idea what kind of // element this was. BOMB! gbl_msg.fatal("FLATTEN(MAP)::UNKNOWN TYPE, %d\n", kvpair->second.m_typ); // // Put this newly copied key into the parent map. // node.insert(KEYVALUE(kvpair->first, elm)); } else if ((nodepair->second.m_typ==MAPT_MAP)&&(kvpair->second.m_typ == MAPT_MAP)) { // It's not uncommon to have a +.name.KEY.SUBKEY..etc // tag. In that case, we need to get copy the // maps while preserving their structure STRING nxt = here + "." + nodepair->first; gbl_msg.info("RECURSING TO COPY %s\n", nxt.c_str()); // Recurse on both the node, and the subnode flatten_maps(*nodepair->second.u.m_m, *kvpair->second.u.m_m, nxt); } else { STRING nkey = here + "." + nodepair->first; gbl_msg.info("IGNORING %s (already exists)\n", nkey.c_str()); } } } void flatten_aux(MAPDHASH &master, MAPDHASH &sub, STRING &here) { MAPDHASH::iterator kvpair, kvsub, kvnxt; for(kvpair=sub.begin(); kvpair != sub.end(); kvpair++) { if (kvpair->second.m_typ == MAPT_MAP) { STRING nkey = here + "." + STRING(kvpair->first); flatten_aux(master, *kvpair->second.u.m_m, nkey); if (kvpair->first == KYPLUSDOT) { // Only if the key of this element is + // do we need to recurse and copy keys beneath // the plus into this primary location // kvsub = kvpair->second.u.m_m->begin(); kvnxt = kvsub; kvnxt++; // Every +. key should contain its own map, // and a single map within it. Skip the extra // recursion, and reference the map within only. // First, though, assert this is the case. assert(kvnxt == kvpair->second.u.m_m->end()); if (kvsub->second.m_typ == MAPT_MAP) flatten_maps(sub, *kvsub->second.u.m_m, nkey); else flatten_maps(sub, *kvpair->second.u.m_m, nkey); } } if (kvpair->first.compare(KYPLUSDOT)==0) { STRING ikey = kvpair->first.substr(1); MAPDHASH::iterator kvprior; kvprior = sub.find(ikey); if (kvprior == master.end()) { sub.insert(KEYVALUE(ikey, kvpair->second)); } else if ((kvpair->second.m_typ == kvprior->second.m_typ) &&(kvprior->second.m_typ == MAPT_STRING)) { STRINGP pstr = kvprior->second.u.m_s; if (isspace((*pstr)[(*pstr).size()-1])) (*kvprior->second.u.m_s) = (*kvprior->second.u.m_s) + (*kvpair->second.u.m_s); else (*kvprior->second.u.m_s) = (*kvprior->second.u.m_s) + STRING(" ") + (*kvpair->second.u.m_s); } /* // Can't delete the + sub hash, since we might // wish to reference it sub.erase(kvpair); kvpair = sub.begin(); if (kvpair == sub.end()) break; */ //else if((kvpair->first[0] == '/')&&(kvpair->first[1]=='+')) } else if (kvpair->first[0] == '/') { STRING nkey = kvpair->first.substr(1); if (master.find(nkey) == master.end()) { master.insert(KEYVALUE(nkey, kvpair->second)); } } } } void flatten(MAPDHASH &master) { STRING top= STRING(""); flatten_aux(master, master, top); } ================================================ FILE: sw/mapdhash.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/mapdhash.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To define the data structures used to represent a parsed input // file. Of particular note is the key-value pair unordered map // structure, and the components of that structure. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef MAPDHASH_H #define MAPDHASH_H #include #include #include #include #include #include #define MAPT_INT 0 #define MAPT_STRING 1 #define MAPT_MAP 2 #define MAPT_AST 3 // Contains a "soft-link" to a hash entry, in other words, this is the "name" of another hash entry--one which we will use instead // #define MAPT_SLINK 3 typedef std::string *STRINGP, STRING; typedef std::unordered_map MAPDHASH; typedef struct MAPT_S { int m_typ; union { int m_v; STRINGP m_s; MAPDHASH *m_m; class AST *m_a; // Abstract syntax tree (uneval expr) // MAPDHASH *m_l; // link to elsewhere in the table } u; } MAPT; typedef std::pair KEYVALUE; extern STRING *trim(const STRING &s); extern bool splitkey(const STRING &ky, STRING &mkey, STRING &subky); extern void addtomap(MAPDHASH &fm, const STRING ky, STRING vl); extern void mapdump(MAPDHASH &fm); extern void mapdump(FILE *fp, MAPDHASH &fm); extern void mapdump(FILE *fp, MAPT &elm); extern void mergemaps(MAPDHASH &master, MAPDHASH &sub); extern void flatten(MAPDHASH &master); extern void trimall(MAPDHASH &mp, const STRING &sky); extern void trimbykeylist(MAPDHASH &mp, const STRING &skylist); extern void trimbykeylist(MAPT &m, const STRING &skylist); extern void cvtint(MAPDHASH &mp, const STRING &sky); extern void cvtintbykeylist(MAPDHASH &mp, const STRING &skylist); extern void cvtintbykeylist(MAPT &m, const STRING &skylist); extern MAPDHASH::iterator findkey(MAPDHASH &mp, const STRING &sky); extern MAPDHASH *getmap(MAPDHASH &mp, const STRING &ky); extern MAPDHASH *getmap(MAPDHASH *mp, const STRING &ky); extern STRINGP getstring(MAPDHASH &mp); extern STRINGP getstring(MAPDHASH &mp, const STRING &sky); extern STRINGP getstring(MAPDHASH *mp, const STRING &sky); extern STRINGP getstring(MAPT &m, const STRING &sky); extern void setstring(MAPDHASH &mp, const STRING &sky, STRINGP strp); extern void setstring(MAPDHASH &mp, const STRING &sky, const STRING &strp); extern void setstring(MAPDHASH *mp, const STRING &sky, STRINGP strp); extern void setstring(MAPDHASH *mp, const STRING &sky, const STRING &strp); extern void setstring(MAPT &m, const STRING &sky, STRINGP strp); extern bool getvalue(MAPDHASH &mp, int &value); extern bool getvalue(MAPDHASH &mp, const STRING &sky, int &value); extern bool getvalue(MAPDHASH *mp, const STRING &sky, int &value); extern void setvalue(MAPDHASH &mp, const STRING &sky, int value); #endif // MAPDHASH ================================================ FILE: sw/mlist.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/mlist.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: An MLIST is a list (i.e. std::vector<>) of bus masters. This // file defines the methods associated with such a list. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include "parser.h" #include "mlist.h" #include "mapdhash.h" #include "keys.h" #include "predicates.h" STRINGP BMASTER::name(void) { return getstring(*m_hash, KYPREFIX); } STRINGP BMASTER::bus_prefix(void) { STRINGP pfx; pfx = getstring(*m_hash, KYMASTER_PREFIX); if (NULL == pfx) { STRINGP bus = getstring(*m_hash, KYMASTER_BUS_NAME); if (NULL == bus) return NULL; pfx = new STRING(*bus + STRING("_") + *name()); setstring(*m_hash, KYMASTER_PREFIX, pfx); } return pfx; } bool BMASTER::read_only(void) { STRINGP options; options = getstring(*m_hash, KYMASTER_OPTIONS); if (NULL != options) return read_only_option(options); return false; } bool BMASTER::write_only(void) { STRINGP options; options = getstring(*m_hash, KYMASTER_OPTIONS); if (NULL != options) return write_only_option(options); return false; } ================================================ FILE: sw/mlist.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/mlist.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: An MLIST is a list of bus masters. This file defines the // methods associated with such a list. // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef MLIST_H #define MLIST_H #include #include "parser.h" class BUSINFO; // // The MLIST, made of B(us)MASTER(s) // // A structure to contain information about lists of bus masters // class BMASTER { public: MAPDHASH *m_hash; STRINGP name(void); STRINGP bus_prefix(void); bool read_only(void); bool write_only(void); BMASTER(MAPDHASH *hash) : m_hash(hash) {}; }; typedef BMASTER *BMASTERP; typedef std::vector MLIST; // A pointer to a set of peripherals typedef MLIST *MLISTP; #endif // MLIST_H ================================================ FILE: sw/msgs.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/msgs.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: A class for handling messages to the user // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include "msgs.h" MSGS gbl_msg; void MSGS::open(const char *fname) { close(); m_dump = fopen(fname, "w"); if (NULL == m_dump) { fprintf(stderr, "ERR: Could not open %s\n", fname); exit(EXIT_FAILURE); } } void MSGS::info(const char *fmt, ...) { va_list args; if (m_dump) { va_start(args, fmt); vfprintf(m_dump, fmt, args); va_end(args); } } void MSGS::userinfo(const char *fmt, ...) { va_list args; if (m_dump) { va_start(args, fmt); vfprintf(m_dump, fmt, args); va_end(args); } va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args); } void MSGS::warning(const char *fmt, ...) { const char *prefix = "WARNING: "; va_list args; if (m_dump) { va_start(args, fmt); fprintf(m_dump, "%s", prefix); vfprintf(m_dump, fmt, args); va_end(args); } va_start(args, fmt); fprintf(stderr, "%s", prefix); vfprintf(stderr, fmt, args); va_end(args); } void MSGS::error(const char *fmt, ...) { const char *prefix = "ERR: "; va_list args; if (m_dump) { va_start(args, fmt); fprintf(m_dump, "%s", prefix); vfprintf(m_dump, fmt, args); va_end(args); } va_start(args, fmt); fprintf(stderr, "%s", prefix); vfprintf(stderr, fmt, args); va_end(args); m_err++; } void MSGS::fatal(const char *fmt, ...) { const char *prefix = "FATAL ERR: "; va_list args; if (m_dump) { va_start(args, fmt); fprintf(m_dump, "%s", prefix); vfprintf(m_dump, fmt, args); va_end(args); } va_start(args, fmt); fprintf(stderr, "%s", prefix); vfprintf(stderr, fmt, args); va_end(args); exit(EXIT_FAILURE); } void MSGS::dump(MAPDHASH &map, const char *msg) { if (!m_dump) return; fprintf(m_dump, "%s\n", msg); mapdump(m_dump, map); } ================================================ FILE: sw/msgs.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/msgs.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: A class for handling messages to the user // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef MSGS_H #define MSGS_H #include #include #include #include #include #include #include "mapdhash.h" class MSGS { FILE *m_dump; int m_err; public: MSGS(void) { m_err = 0; } void open(const char *fname); void close(void) { if (m_dump) ::fclose(m_dump); m_dump = NULL; }; void flush(void) { if (m_dump) fflush(m_dump); } // void info(const char *, ...); void userinfo(const char *, ...); void warning(const char *, ...); void error(const char *, ...); // void oserr(const char *, ...); void fatal(const char *, ...); void dump(MAPDHASH &map, const char *msg = NULL); int status(void) { return (m_err)?EXIT_FAILURE : EXIT_SUCCESS; } }; extern MSGS gbl_msg; #endif // MSGS ================================================ FILE: sw/parser.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/parser.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To parse an input file, and create a data structure of key-value // pairs from it. Values of this structure may include other // key-value pair sub-structures. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include "mapdhash.h" #include "parser.h" #include "keys.h" #include "msgs.h" STRING *rawline(FILE *fp) { char linebuf[512]; STRING *r = new STRING; char *rv, *nl; do { rv = fgets(linebuf, sizeof(linebuf), fp); nl = strchr(linebuf, '\n'); if (rv) r->append(linebuf); } while((rv)&&(!nl)); // If we didn't get anything, such as on an end of file, return NULL // that way we can differentiate an EOF or error from an empty line. if ((!rv)&&(r->length()==0)) { delete r; return NULL; } return r; } STRING *getline(FILE *fp) { STRING *r; bool comment_line; do { r = rawline(fp); comment_line = false; if ((r)&&(r->c_str()[0] == '#')) { if (isspace(r->c_str()[1])) comment_line = true; else if (r->c_str()[1] == '#') comment_line = true; } } while(comment_line); return r; } bool iskeyline(STRING &s) { if (s.compare(0,3,STRING("@$("))==0) return false; return ((s[0] == '@')&&(s[1] != '@')); } MAPDHASH *genhash(STRING &prefix) { MAPDHASH *devm; MAPT elm; devm = new MAPDHASH(); elm.m_typ = MAPT_STRING; elm.u.m_s = trim(prefix); devm->insert(KEYVALUE(KYPREFIX,elm)); return devm; } MAPDHASH *gensubhash(MAPDHASH *top, STRING &prefix) { MAPDHASH *devm = NULL; STRINGP tmp = trim(prefix); // This isn't any old key, this is a // prefix key. All keys following will // be placed in the hierarchy beneath // this key. MAPDHASH::iterator kvpair; kvpair = top->find(*tmp); if (tmp->length() <= 0) { gbl_msg.fatal("EMPTY KEY\n"); } else if (kvpair == top->end()) { STRING kyp = STRING(*tmp); MAPT elm; devm = genhash(kyp); elm.m_typ = MAPT_MAP; elm.u.m_m = devm; top->insert(KEYVALUE(kyp,elm)); } else if (kvpair->second.m_typ == MAPT_MAP) { devm = kvpair->second.u.m_m; } else { gbl_msg.fatal("NAME-CONFLICT!! (witin the same file, too!)\n"); } delete tmp; return devm; } MAPDHASH *parsefile(FILE *fp, const STRING &search); void process_keyvalue_pair(MAPDHASH *parent, const STRING &search, STRING &key, STRING &value) { if (key == KYINCLUDEFILE) { MAPDHASH *submap, *plusmap; MAPDHASH::iterator subp; // Read and insert the given file here submap= parsefile(value.c_str(), search); // If the file was found, as with the data within it, then ... if (submap != NULL) { // Read this file, creating a hash subp = parent->find(KYPLUSDOT); // Declare everything within the file to be of the // sub-key "+" (KYPLUSDOT) // if (subp == parent->end()) { MAPT elm; elm.m_typ = MAPT_MAP; plusmap = new MAPDHASH; elm.u.m_m = plusmap; parent->insert(KEYVALUE(KYPLUSDOT, elm)); } else if (subp->second.m_typ != MAPT_MAP) { gbl_msg.error("KEY(+) EXISTS, AND ISN\'T A MAP\n"); } else { plusmap = subp->second.u.m_m; } if (plusmap) mergemaps(*plusmap, *submap); } // Otherwise ... (*TRY*) to ignore the error } else // If its a normal key, just add it to the map addtomap(*parent, key, value); } MAPDHASH *parsefile(FILE *fp, const STRING &search) { STRING key, value, *ln, prefix; MAPDHASH *fm = new MAPDHASH, *devm = NULL; size_t pos; key = ""; value = ""; while(NULL != (ln = getline(fp))) { if (iskeyline(*ln)) { // We may have a completed key-value pair that needs // to be stored. if (key.length() > 0) { // A key exists. Let's store it. // If it's a PREFIX key, create a sub hash of // the FILE's hash if (key == KYPREFIX) { MAPDHASH *sub; sub = gensubhash(fm, value); if (sub) devm = sub; } MAPDHASH *parent; if (devm) parent = devm; else parent = fm; // Process the old key process_keyvalue_pair(parent, search, key, value); } // if ((pos = ln->find("=")) &&(pos != STRING::npos)) { // Separate the key from its value key = ln->substr(1, pos-1); // If we have a @KEY += line, then place the // plus in front of the key. @+KEY is an // invalid key, so ... this should work. if (key.c_str()[(key.size())-1] == '+') { // Our key takes the + off the right, // and adds it to the left key = STRING("+")+key.substr(0,key.size()-1); } // Trim any whitespace from the key STRINGP trimd; trimd = trim(key); key = STRING(*trimd); delete trimd; // Trim any whitespace from the value on this // line trimd = trim(ln->substr(pos+1)); value = STRING(*trimd); delete trimd; } else { // If we have a key with no "=" sign, // assume the whole line is the key. // Trim it up. key = ln->substr(1, ln->length()-1); STRINGP trimd; trimd = trim(key); key = STRING(*trimd); delete trimd; gbl_msg.warning("Key line with no =, key was %s\n", key.c_str()); value = ""; } } else if (ln->c_str()[0]) { value = value + (*ln); } delete ln; } if (key.length()>0) { if (key == KYPREFIX) { MAPDHASH *sub; sub = gensubhash(fm, value); if (sub) devm = sub; } MAPDHASH *parent; if (devm) parent = devm; else parent = fm; process_keyvalue_pair(parent, search, key, value); } return fm; } FILE *open_data_file(const char *fname) { struct stat sb; if ((access(fname, R_OK)!=0)||(stat(fname, &sb) != 0)) { return NULL; } else { if (sb.st_mode & S_IFREG) return fopen(fname, "r"); } return NULL; } FILE *search_and_open(const char *fname, const STRING &search) { FILE *fp = open_data_file(fname); if ((fp == NULL)&&(fname[0] != '/')&&(fname[0] != '.')) { STRING copy = search; char *sub = (char *)copy.c_str(); char *dir = strtok(sub, ", \t\n:"); while(dir != NULL) { char *full = new char[strlen(fname)+2+strlen(dir)]; strcpy(full, dir); strcat(full, "/"); strcat(full, fname); if (NULL != (fp=open_data_file(full))) { gbl_msg.info("Opened: %s\n", full); delete[] full; return fp; } delete[] full; dir = strtok(NULL, ", \t\n:"); } gbl_msg.error("Could not open %s\nSearched through %s\n", fname, search.c_str()); return NULL; } gbl_msg.info("Directly opened: %s\n", fname); return fp; } MAPDHASH *parsefile(const char *fname, const STRING &search) { MAPDHASH *map; FILE *fp = search_and_open(fname, search); if (fp == NULL) { gbl_msg.error("PARSE-ERR: Could not open %s\n" "\t Searched through: %s\n", fname, search.c_str()); return NULL; } else { map = parsefile(fp, search); fclose(fp); return map; } } MAPDHASH *parsefile(const STRING &fname, const STRING &search) { return parsefile((const char *)fname.c_str(), search); } ================================================ FILE: sw/parser.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/parser.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: To define the processes used to parse a raw input file. This // does not include the code necessary to evaluate any strings // within that input file, only the code to turn the input file into // KEY-VALUE pairs. used by a parsed input file. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef PARSER_H #define PARSER_H #include #include #include #include #include "mapdhash.h" extern STRING *rawline(FILE *fp); extern STRING *getline(FILE *fp); extern MAPDHASH *parsefile(FILE *fp, const STRING &search=""); extern MAPDHASH *parsefile(const char *fname, const STRING &search=""); extern MAPDHASH *parsefile(const STRING &fname, const STRING &search=""); #endif ================================================ FILE: sw/plist.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/plist.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: A PLIST is a list of peripherals (i.e. bus slaves, or components // with a SLAVE.BUS tag). This file defines the methods associated // with such a list. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "keys.h" #include "kveval.h" #include "plist.h" #include "bitlib.h" #include "businfo.h" #include "predicates.h" #include "subbus.h" #include "globals.h" #include "msgs.h" bool PERIPH::issingle(void) { STRINGP str; if (!p_phash) return false; if (NULL == (str = getstring(*p_phash, KYSLAVE_TYPE))) return false; if (str->compare(KYSINGLE)!=0) return false; return true; } bool PERIPH::isdouble(void) { STRINGP str; if (!p_phash) return false; if (NULL == (str = getstring(*p_phash, KYSLAVE_TYPE))) return false; if (str->compare(KYDOUBLE)!=0) return false; if (NULL != (str = getstring(*p_phash, KYERROR_WIRE))) return false; return true; } bool PERIPH::isbus(void) { STRINGP str; if (!p_phash) return false; if (NULL == (str = getstring(*p_phash, KYSLAVE_TYPE))) return false; if (str->compare(KYBUS)!=0) return false; return true; } bool PERIPH::ismemory(void) { STRINGP str; if (!p_phash) return false; if (NULL == (str = getstring(*p_phash, KYSLAVE_TYPE))) return false; if (str->compare(KYMEMORY)!=0) return false; return true; } unsigned PERIPH::get_slave_address_width(void) { unsigned awid, lgdw = 0; awid = nextlg(naddr()); if (p_slave_bus != NULL && !p_slave_bus->word_addressing()) lgdw = nextlg(p_slave_bus->data_width()/8); awid += lgdw; if (p_awid != (unsigned)awid) { p_awid = awid; setvalue(*p_phash, KYSLAVE_AWID, awid); } return p_awid; } unsigned PERIPH::naddr(void) { int value; assert(p_phash); if (getvalue(*p_phash, KYNADDR, value)) { bool rebuild = false; int lgdw = 0; if (p_slave_bus != NULL && !p_slave_bus->word_addressing()) lgdw = nextlg(p_slave_bus->data_width()/8); if ((int)p_naddr != value) { gbl_msg.warning("%s's number of addresses changed from %ld to %d\n", p_name->c_str(), p_naddr, value); p_naddr = 0; } if (0 == p_naddr) { // Set p_naddr from value int lgaddr = nextlg(value); p_naddr = value; lgaddr += lgaddr + lgdw; rebuild = true; p_awid = lgaddr; } if (rebuild) { setstring(p_phash, KYSLAVE_PORTLIST, p_slave_bus->slave_portlist(this)); setstring(p_phash, KYSLAVE_ANSIPORTLIST, p_slave_bus->slave_ansi_portlist(this)); } if (!getstring(p_phash, KYSLAVE_IANSI)) { setstring(p_phash, KYSLAVE_IANSI, p_slave_bus->slave_iansi(this)); rebuild = true; } if (!getstring(p_phash, KYSLAVE_OANSI)) { setstring(p_phash, KYSLAVE_OANSI, p_slave_bus->slave_oansi(this)); rebuild = true; } if (!getstring(p_phash, KYSLAVE_ANSPREFIX)) { setstring(p_phash, KYSLAVE_ANSPREFIX, p_slave_bus->slave_ansprefix(this)); rebuild = true; } if (rebuild) reeval(p_phash); } return p_naddr; } void PERIPH::integrity_check(void) { assert(NULL != p_name); assert(NULL != p_phash); assert(NULL != p_slave_bus); } STRINGP PERIPH::bus_prefix(void) { STRINGP pfx; pfx = getstring(p_phash, KYSLAVE_PREFIX); if (NULL == pfx) { STRINGP bus = p_slave_bus->name(); if (NULL == bus) return NULL; // Assume a prefix if it isnt given pfx = new STRING(STRING(*bus)+STRING("_")+STRING(*p_name)); setstring(p_phash, KYSLAVE_PREFIX, pfx); } return pfx; } bool PERIPH::read_only(void) { STRINGP options; options = getstring(*p_phash, KYSLAVE_OPTIONS); if (NULL != options) return read_only_option(options); return false; } bool PERIPH::write_only(void) { STRINGP options; options = getstring(*p_phash, KYSLAVE_OPTIONS); if (NULL != options) return write_only_option(options); return false; } //////////////////////////////////////////////////////////////////////////////// // // Logic on sets of peripherals // //////////////////////////////////////////////////////////////////////////////// void PLIST::integrity_check(void) { assert(NULL != this); for(unsigned k=0; kintegrity_check(); } } // // compare_naddr // // This is part of the peripheral sorting mechanism, whereby peripherals are // sorted by the numbers of addresses they use. Peripherals using fewer // addresses are placed first, with peripherals using more addresses placed // later. // bool compare_naddr(PERIPHP a, PERIPHP b) { if (!a) return (b)?false:true; else if (!b) return true; // Unordered items come before ordered items. bool have_order = false; int aorder, border; if (a->p_phash == NULL) { gbl_msg.fatal("Peripheral %s has a null hash!\n", a->p_name->c_str()); } if (b->p_phash == NULL) { gbl_msg.fatal("ERR: Peripheral %s has a null hash!\n", b->p_name->c_str()); } have_order = getvalue(*a->p_phash, KYSLAVE_ORDER, aorder); if (have_order) { have_order = getvalue(*b->p_phash, KYSLAVE_ORDER, border); if (have_order) return (aorder < border); return false; } else if (getvalue(*b->p_phash, KYSLAVE_ORDER, border)) return true; unsigned anaddr, bnaddr; anaddr = a->get_slave_address_width(); bnaddr = b->get_slave_address_width(); if (anaddr != bnaddr) return (anaddr < bnaddr); // Otherwise ... the two address types are equal. if ((a->p_name)&&(b->p_name)) return (a->p_name->compare(*b->p_name) < 0) ? true:false; else if (!a->p_name) return true; else return true; } bool compare_address(PERIPHP a, PERIPHP b) { if (!a) return (b)?false:true; else if (!b) return true; return (a->p_base < b->p_base); } bool compare_regaddr(PERIPHP a, PERIPHP b) { return (a->p_regbase < b->p_regbase); } int PLIST::add(PERIPHP p) { // To get here, the component must already have a valid hash assert(p->p_phash); push_back(p); return size()-1; } // // Add a peripheral to a given list of peripherals int PLIST::add(MAPDHASH *phash) { PERIPHP p; STRINGP pname; int naddr; pname = getstring(*phash, KYPREFIX); if (!pname) { gbl_msg.warning("Skipping unnamed peripheral\n"); return -1; } if (!getvalue(*phash, KYNADDR, naddr)) { naddr = 0; } if (issubbus(*phash)) { BUSINFO *bi; MAPDHASH::iterator kvmbus; kvmbus = findkey(*phash, KYMASTER_BUS); if (kvmbus != phash->end()) { bi = NULL; if (kvmbus->second.m_typ == MAPT_STRING) bi = find_bus(kvmbus->second.u.m_s); else if (kvmbus->second.m_typ == MAPT_MAP) bi = find_bus(kvmbus->second.u.m_m); assert(bi); } p = new SUBBUS(phash, bi->name(), bi); } else { p = new PERIPH; p->p_master_bus = NULL; } p->p_base = 0; p->p_naddr = naddr; p->p_phash = phash; p->p_name = pname; { BUSINFO *bi; MAPDHASH::iterator kvsbus; kvsbus = findkey(*phash, KYSLAVE_BUS); assert(kvsbus != phash->end()); assert(kvsbus->second.m_typ == MAPT_MAP); bi = find_bus(kvsbus->second.u.m_m); assert(bi); p->p_slave_bus = bi; } if (0 != naddr) { // Calculate and set p->p_awid p->get_slave_address_width(); } else p->p_awid = 0; (void)p->bus_prefix(); push_back(p); return size()-1; } bool PLIST::get_base_address(MAPDHASH *phash, unsigned &base) { for(iterator p=begin(); p!=end(); p++) { if ((*p)->p_phash == phash) { base = (*p)->p_base; return true; } else if ((*p)->p_master_bus) { if ((*p)->p_master_bus->get_base_address(phash, base)){ base += (*p)->p_base; return true; } } } return false; } unsigned PLIST::min_addr_size_bytes(const unsigned np, const unsigned mina_bytes, const unsigned nullsz_bytes) { unsigned start = nullsz_bytes, pa, base_bytes; for(unsigned i=0; iget_slave_address_width(); if (pa <= 0) continue; if (pa < mina_bytes) pa = mina_bytes; base_bytes = (start + ((1<> daddr; mna = min_addr_size_bytes(np, mna, nullszb); mna += daddr; return mna; } extern bool gbl_ready_for_address_assignment; void PLIST::assign_addresses(unsigned dwidth, unsigned nullsz, unsigned bus_min_address_width) { unsigned daddr_abits = nextlg(dwidth/8); assert(gbl_ready_for_address_assignment); // Use daddr_abits to convert our addresses between bus addresses and // byte addresses. The address width involved is in bus words, // whereeas the base address needs to be in octets. NullSz is also // in octets. if (size() < 1) { if (nullsz > 0) m_address_width = nextlg(nullsz); else m_address_width = 0; return; } else if ((size() < 2)&&(nullsz == 0)) { PERIPHP p = (*this)[0]; MAPDHASH *ph = p->p_phash; GENBUS *g = p->p_slave_bus->generator(); p->p_base = 0; p->p_mask = 0; setvalue(*p->p_phash, KYBASE, p->p_base); setvalue(*p->p_phash, KYMASK, p->p_mask); m_address_width = p->get_slave_address_width(); if (m_address_width <= 0) { gbl_msg.error("Slave %s has zero NADDR (now address assigned)\n", p->p_name->c_str()); } if (g) { setstring(*ph, KYSLAVE_PORTLIST, g->slave_portlist(p)); setstring(*ph, KYSLAVE_ANSIPORTLIST, g->slave_ansi_portlist(p)); if (!getstring(*ph, KYSLAVE_IANSI)) setstring(*ph, KYSLAVE_IANSI, g->iansi(NULL)); if (!getstring(*ph, KYSLAVE_OANSI)) setstring(*ph, KYSLAVE_OANSI, g->oansi(NULL)); if (!getstring(*ph, KYSLAVE_ANSPREFIX)) setstring(*ph, KYSLAVE_ANSPREFIX, g->slave_ansprefix(p)); reeval(*ph); } } else { bool m_full_decode = false; assert((*this)[0]->p_slave_bus); if (!(*this)[0]->p_slave_bus->word_addressing()) daddr_abits = 0; // We'll need a minimum of nextlg(p->size()) bits to address // p->size() separate peripherals. While we'd like to minimize // the number of bits we use to do this, adding one extra bit // in to the minimum number of bits required gives us a little // bit of flexibility while also attempting to keep our bus // width to a minimum. unsigned long start_address = nullsz; unsigned long min_awd, min_asz; // Sort our peripherals by the number of address lines they // will be using. At the end of this, we'll know that we'll // need a minimum of (*p)[p->size()-1]->p_awid+1 address lines. sort(begin(), end(), compare_naddr); // // We've got two Goals: // // #1 Keep the bus address width to a minimum // #2 Keep the LUTs required to a minimum // // Hence, let's try adjusting the minimum address difference // between peripherals to find the minimum #2, subject to // having found the minimum of #1 // Let's start by calculating the number of bits we will need // if we don't do anything smart min_awd = (*this)[size()-1]->get_slave_address_width() + daddr_abits; min_asz = min_addr_size_octets(size(), min_awd, nullsz, daddr_abits); if (min_asz < bus_min_address_width) min_asz = bus_min_address_width; // Our goal will be to do better than this for(iterator p=begin(); p!=end(); p++) { // Make certain all of our slaves have at least // one address location assigned to them, generate // an error if not if ((*p)->naddr() <= 0) { gbl_msg.error("Slave %s has zero " "NADDR (now address assigned)\n", (*p)->p_name->c_str()); } } // // Minimize the address width // unsigned min_relevant = 32-daddr_abits; for(unsigned mina = daddr_abits+1; mina < 32-daddr_abits; mina++) { // unsigned total_address_width, relevant_address_bits; // total_address_width = min_addr_size_octets(size(), mina, nullsz, daddr_abits); relevant_address_bits = total_address_width - mina; if (total_address_width > min_asz) { // Never increase our # of address lines } else if (relevant_address_bits < min_relevant) { min_asz = total_address_width; min_relevant = relevant_address_bits; min_awd = mina; } } // // Now we're ready to do the actual address assignment // // We'll do the calculation in calculation in octets, where // the conversion from the one to the next is daddr_abits--the // number of address bits required to advance one bus word. // We'll start assigning addresses after skipping some number // of addresses assigned to the null address. This is user // selectable, and may be zero. start_address = nullsz; for(unsigned i=0; iget_slave_address_width()+daddr_abits; pa = pfull; if (pa <= 0) { // p_base is in octets (*this)[i]->p_base = start_address; (*this)[i]->p_mask = 0; } else { // // If our address increment is smaller than the // minimum increment we calculated above, then // bump it up to that minimum increment if (pa < min_awd) pa = min_awd; // p_base is the base address of this // peripheral, expressed in octets (*this)[i]->p_base =start_address+((1ul<p_base &= (-1l<p_base + (1ul<p_mask = (-1)<<(pmsk-daddr_abits); assert((*this)[i]->p_mask != 0); } } assert(start_address != 0); unsigned master_mask = nextlg(start_address); master_mask = (1u << (master_mask-daddr_abits))-1; // One more pass, now that we know the last address for(unsigned i=0; ip_mask &= master_mask; gbl_msg.info(" %20s -> %08lx & 0x%08lx\n", (*this)[i]->p_name->c_str(), (*this)[i]->p_base, (*this)[i]->p_mask << daddr_abits); if ((*this)[i]->p_phash) { PERIPHP p = (*this)[i]; MAPDHASH *ph = p->p_phash; GENBUS *g = p->p_slave_bus->generator(); setvalue(*ph, KYBASE, p->p_base); setvalue(*ph, KYMASK, p->p_mask << daddr_abits); if (g) { setstring(*ph, KYSLAVE_PORTLIST, g->slave_portlist(p)); setstring(*ph, KYSLAVE_ANSIPORTLIST, g->slave_ansi_portlist(p)); if (!getstring(*ph, KYSLAVE_IANSI)) setstring(*ph, KYSLAVE_IANSI, g->iansi(NULL)); if (!getstring(*ph, KYSLAVE_OANSI)) setstring(*ph, KYSLAVE_OANSI, g->oansi(NULL)); if (!getstring(*ph, KYSLAVE_ANSPREFIX)) setstring(*ph, KYSLAVE_ANSPREFIX, g->slave_ansprefix(p)); reeval(*ph); } } } m_address_width = nextlg(start_address)-daddr_abits; } reeval(gbl_hash); } ================================================ FILE: sw/plist.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/plist.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: A PLIST is a list (C++ vector) of bus slaves, herein called // peripherals. This file defines the methods associated with // such a list. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef PLIST_H #define PLIST_H #include #include "parser.h" class BUSINFO; // // The PLIST, made of PERIPH(erals) // // A structure to contain information about lists of peripherals // class PERIPH { public: unsigned long p_base, p_regbase; // In octets unsigned long p_naddr; // In words, given in file // // p_awid = number of address lines for this slave // In word addressing, this is log_2(p_naddr) // Otherwise, its defined as log_2(p_naddr * bus->data_width()/8) // This is on the *slave* bus. For subbus's, it may not be the same // as the width on the *master* bus. unsigned p_awid; // unsigned long p_mask; // Words. Bit is true if relevant for address selection // unsigned p_sbaw; STRINGP p_name; MAPDHASH *p_phash; BUSINFO *p_slave_bus; // We are a slave of this bus BUSINFO *p_master_bus; // We might master this bus beneath us STRINGP name(void) { return p_name; }; virtual bool issingle(void); virtual bool isdouble(void); virtual bool isbus(void); virtual bool ismemory(void); virtual bool read_only(void); virtual bool write_only(void); virtual unsigned get_slave_address_width(void); unsigned awid(void) { return get_slave_address_width(); } unsigned naddr(void); virtual void integrity_check(void); STRINGP bus_prefix(void); }; typedef PERIPH *PERIPHP; class PLIST : public std::vector { unsigned m_address_width; public: PLIST(void) {} STRINGP m_stype; void set_stype(STRING &stype); // // Add a peripheral to a given list of peripherals int add(MAPDHASH *phash); int add(PERIPHP p); void assign_addresses(unsigned dwidth, unsigned nullsz = 0, unsigned bus_min_address_width = 0); bool get_base_address(MAPDHASH *phash, unsigned &base); unsigned min_addr_size_bytes(unsigned, unsigned, unsigned nullsz=0); unsigned min_addr_size_octets(unsigned, unsigned, unsigned nullsz=0, unsigned daddr=2); unsigned get_address_width(void) { return m_address_width; } void integrity_check(void); /* void remove(std::vector::iterator ptr) { std::vector::remove(ptr); } */ }; // A pointer to a set of peripherals typedef PLIST *PLISTP; // // Count the number of peripherals that are children of this top level hash, // and count them by type as well. // extern int count_peripherals(MAPDHASH &info); // // compare_naddr // // This is part of the peripheral sorting mechanism, whereby peripherals are // sorted by the numbers of addresses they use. Peripherals using fewer // addresses are placed first, with peripherals using more addresses placed // later. // extern bool compare_naddr(PERIPHP a, PERIPHP b); // // compare_address // // This is another means of sorting peripherals, this time by their address // within their bus. // extern bool compare_address(PERIPHP a, PERIPHP b); // // compare_regaddr // // When examining registers that are accessed across busses, it becomes // important to be able to sort peripherals from the point of view of a master // that might be able to reach them. This is the purpose of the REGBASE // address. This compare sorts with respect to that address // extern bool compare_regaddr(PERIPHP a, PERIPHP b); /* * build_plist * * Collect our peripherals into one of four lists. This allows us to have * ordered access through the peripherals later. */ extern void build_plist(MAPDHASH &info); #endif // PLIST_H ================================================ FILE: sw/predicates.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/predicates.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: A predicate is a function that returns true or false. This // file describes the implementation of a series of functions that // can be used to determine of what type a given design component is. // Is it a bus master? A bus slave? A programmable interrupt controller? // etc. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "keys.h" #include "kveval.h" #include "legalnotice.h" #include "bldtestb.h" #include "bitlib.h" #include "plist.h" #include "bldregdefs.h" #include "ifdefs.h" #include "bldsim.h" #include "predicates.h" // // Is the given location within our hash a master? Look it up. // // To be a bus master, it must have a @MTYPE field. // bool isbusmaster(MAPDHASH &phash) { STRINGP styp; styp = getstring(phash, KYMASTER_TYPE); if (NULL == styp) return false; if (KYSCRIPT.compare(*styp) == 0) return false; return true; } // // Does the given location describe access to a bus lying beneath it? // // To be true, isbusmaster() must be true, and the MASTER.BUS.TYPE field // must be one of: SUBBUS, XCLOCK, ARBITER, etc. // bool issubbus(MAPDHASH &phash) { if (!isperipheral(phash)) return false; if (!isbusmaster(phash)) return false; STRINGP mtype = getstring(phash, KYMASTER_TYPE); if (!mtype) return false; if (mtype->compare(KYBUS)==0) return true; if (mtype->compare(KYSUBBUS)==0) return true; if (mtype->compare(KYXCLOCK)==0) return true; if (mtype->compare(KYARBITER)==0) return true; return false; } bool isarbiter(MAPDHASH &phash) { return issubbus(phash); } // // Same thing, but when given a location within the tree, rather than a hash // value. bool isbusmaster(MAPT &pmap) { if (pmap.m_typ != MAPT_MAP) return false; return isbusmaster(*pmap.u.m_m); } // // Is the given hash a definition of a peripheral // // To be a peripheral, it must have a @PTYPE field. // bool isperipheral(MAPDHASH &phash) { return (NULL != getstring(phash, KYSLAVE_TYPE)); // return (phash.end() != phash.find(KYSLAVE_TYPE)); } bool isperipheral(MAPT &pmap) { if (pmap.m_typ != MAPT_MAP) return false; return isperipheral(*pmap.u.m_m); } // // Does the given hash define a programmable interrupt controller? // // If so, it must have a @PIC.MAX field identifying the maximum number of // interrupts that can be assigned to it. bool ispic(MAPDHASH &phash) { return (phash.end() != findkey(phash, KYPIC_MAX)); } bool ispic(MAPT &pmap) { if (pmap.m_typ != MAPT_MAP) return false; return ispic(*pmap.u.m_m); } // Does this reference a memory peripheral? bool ismemory(MAPDHASH &phash) { STRINGP strp; strp = getstring(phash, KYSLAVE_TYPE); if (!strp) return false; if (KYMEMORY.compare(*strp) != 0) return false; return true; } bool ismemory(MAPT &pmap) { if (pmap.m_typ != MAPT_MAP) return false; return ismemory(*pmap.u.m_m); } // // Does this component have a bus definition within it, or does it reference // a bus? bool refbus(MAPDHASH &phash) { if (NULL != getstring(phash, KYBUS)) return true; // else if (NULL != getmap(phash, KYBUS)) return true; return false; } bool refbus(MAPT &pmap) { if (pmap.m_typ != MAPT_MAP) return false; return refbus(*pmap.u.m_m); } // // Does this component have a clock definition within it, or does it reference // a clock? // bool refclock(MAPDHASH &phash) { STRINGP strp; strp = getstring(phash, KYCLOCK); if (!strp) return false; return true; } bool refclock(MAPT &pmap) { if (pmap.m_typ != MAPT_MAP) return false; return refbus(*pmap.u.m_m); } // Does the top level map contain a CPU as one of the peripherals? bool has_cpu(MAPDHASH &phash) { MAPDHASH::iterator kvpair; STRINGP strp; for(kvpair=phash.begin(); kvpair != phash.end(); kvpair++) { if (kvpair->second.m_typ != MAPT_MAP) continue; if (!isbusmaster(kvpair->second)) continue; strp = getstring(kvpair->second.u.m_m, KYMASTER_TYPE); if (NULL == strp) continue; if (strp->compare(KYCPU)==0) return true; } return false; } bool read_only_option(STRINGP op) { char *cstr, *tok; const char DELIMITERS[] = ", \t\r\n"; bool read_only = false; cstr = strdup(op->c_str()); tok = strtok(cstr, DELIMITERS); while(NULL != tok) { if (strcasecmp(tok, "RO")==0) { read_only = true; break; } tok = strtok(NULL, DELIMITERS); } free(cstr); return read_only; } bool write_only_option(STRINGP op) { char *cstr, *tok; const char DELIMITERS[] = ", \t\r\n"; bool write_only = false; cstr = strdup(op->c_str()); tok = strtok(cstr, DELIMITERS); while(NULL != tok) { if (strcasecmp(tok, "WO")==0) write_only = true; tok = strtok(NULL, DELIMITERS); } free(cstr); return write_only; } ================================================ FILE: sw/predicates.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/predicates.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef PREDICATES_H #define PREDICATES_H #include #include #include #include #include "parser.h" // // Is the given location within our hash a master? Look it up. // // To be a bus master, it must have a @MASTER.TYPE field. // bool isbusmaster(MAPDHASH &phash); // // Does the given location describe access to a bus lying beneath it? // // To be true, isbusmaster() must be true, and the MASTER.BUS.TYPE field // must be one of: SUBBUS, XCLOCK, ARBITER, etc. // bool issubbus(MAPDHASH &phash); bool isarbiter(MAPDHASH &phash); // // Same thing, but when given a location within the tree, rather than a hash // value. bool isbusmaster(MAPT &pmap); // // Is the given hash a definition of a peripheral // // To be a peripheral, it must have a @SLAVE.TYPE field. // bool isperipheral(MAPDHASH &phash); bool isperipheral(MAPT &pmap); // // Does the given hash define a programmable interrupt controller? // // If so, it must have a @PIC.MAX field identifying the maximum number of // interrupts that can be assigned to it. bool ispic(MAPDHASH &phash); bool ispic(MAPT &pmap); // Does this reference a memory peripheral? bool ismemory(MAPDHASH &phash); bool ismemory(MAPT &pmap); // Does component reference a bus? bool refbus(MAPDHASH &phash); bool refbus(MAPT &pmap); // Does component reference a clock? bool refclock(MAPDHASH &phash); bool refclock(MAPT &pmap); // Does the toplevel map contain a CPU? bool has_cpu(MAPDHASH &phash); // Does the option set describe a read-only peripheral bool read_only_option(STRINGP op); // bool read_only_option(MAPDHASH &phash); // Does the option set describe a write-only peripheral bool write_only_option(STRINGP op); // bool write_only_option(MAPDHASH &phash); #endif // PREDICATES_H ================================================ FILE: sw/subbus.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/subbus.cpp // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: A subbus component is a special type of bus slave that is also // a bus master on another bus at the same time. The sub bus // that the peripheral is a master of then determines the address range of // the peripheral on the bus that it is a slave of. // // Classic examples of subbus's would be bridges. DMA components are not // subbus's, but rather masters and slaves in their own right. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #include "plist.h" #include "businfo.h" #include "subbus.h" #include "bitlib.h" #include "globals.h" #include "msgs.h" SUBBUS::SUBBUS(MAPDHASH *info, STRINGP subname, BUSINFO *subbus) { p_base = 0; p_naddr= 0; p_awid = 0; p_mask = 0; p_sbaw = 0; p_name = subname; p_phash = info; p_master_bus = subbus; } bool SUBBUS::isbus(void) { return true; } unsigned SUBBUS::get_slave_address_width(void) { unsigned awid; assert(p_master_bus); if (p_master_bus == p_slave_bus) gbl_msg.fatal("ERR: Component %s cannot be both slave to bus %s and master of it as a subbus\n", (p_name->c_str()) ? p_name->c_str() : "(Unknown?!?!)", (p_master_bus->name()->c_str()) ? p_master_bus->name()->c_str() : "(Un-named)", (p_slave_bus->name()->c_str()) ? p_slave_bus->name()->c_str() : "(Un-named)"); assert(p_master_bus != p_slave_bus); // Calculate the address width for bytes awid = p_master_bus->address_width(); if (p_master_bus->word_addressing()) awid += nextlg(p_master_bus->data_width()/8); p_naddr = (1u<<(awid-nextlg(p_slave_bus->data_width()/8))); // Adjust this to be address width for words --- if required if (p_slave_bus->word_addressing()) awid -= nextlg(p_slave_bus->data_width()/8); if (p_awid != awid) { p_awid = awid; setvalue(*p_phash, KYSLAVE_AWID, awid); } return p_awid; } /* bool SUBBUS::get_base_address(MAPDHASH *phash, unsigned &base) { assert(p_master_bus); assert(p_master_bus != p_slave_bus); if (p_slave_bus->get_base_address(phash, base)) { // If the bus we are mastering has an offset, add that to our // base address base += p_base; return true; } return false; } */ void SUBBUS::assign_addresses(void) { assert(p_master_bus); assert(p_master_bus != p_slave_bus); // Assign addresses to the bus that we master from here p_master_bus->assign_addresses(); } bool SUBBUS::need_translator(void) { assert(p_slave_bus); assert(p_master_bus); return p_slave_bus->need_translator(p_master_bus); } ================================================ FILE: sw/subbus.h ================================================ //////////////////////////////////////////////////////////////////////////////// // // Filename: sw/subbus.h // // Project: AutoFPGA, a utility for composing FPGA designs from peripherals // {{{ // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2017-2024, Gisselquist Technology, LLC // {{{ // This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // for a copy. // }}} // License: GPL, v3, as defined and found on www.gnu.org, // {{{ // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // }}} #ifndef SUBBUS_H #define SUBBUS_H #include "plist.h" #include "businfo.h" class SUBBUS : public PERIPH { public: SUBBUS(MAPDHASH *info, STRINGP subname, BUSINFO *subbus); virtual bool isbus(void); virtual unsigned get_slave_address_width(void); void add(PERIPHP p) { p_master_bus->add(p); } void add(MAPDHASH *phash) { p_master_bus->add(phash); } bool get_base_address(MAPDHASH *phash, unsigned &base); void assign_addresses(void); bool need_translator(void); }; #endif