From 30f78a366a2cdaa488ee1afa6a8def6df085474e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Fri, 29 Mar 2024 16:23:03 +0300 Subject: [PATCH 01/26] Transpiler: Add initial. --- bitvm-transpiler/.gitignore | 3 + bitvm-transpiler/Cargo.toml | 10 + bitvm-transpiler/LICENSE | 617 ++++++++++++++++++++++++ bitvm-transpiler/README.md | 33 ++ bitvm-transpiler/src/bitvm.rs | 47 ++ bitvm-transpiler/src/cli.rs | 62 +++ bitvm-transpiler/src/elf_parser.rs | 103 ++++ bitvm-transpiler/src/main.rs | 50 ++ bitvm-transpiler/src/riscv/decoder.rs | 362 ++++++++++++++ bitvm-transpiler/src/riscv/generator.rs | 584 ++++++++++++++++++++++ bitvm-transpiler/src/riscv/mod.rs | 251 ++++++++++ 11 files changed, 2122 insertions(+) create mode 100644 bitvm-transpiler/.gitignore create mode 100644 bitvm-transpiler/Cargo.toml create mode 100644 bitvm-transpiler/LICENSE create mode 100644 bitvm-transpiler/README.md create mode 100644 bitvm-transpiler/src/bitvm.rs create mode 100644 bitvm-transpiler/src/cli.rs create mode 100644 bitvm-transpiler/src/elf_parser.rs create mode 100644 bitvm-transpiler/src/main.rs create mode 100644 bitvm-transpiler/src/riscv/decoder.rs create mode 100644 bitvm-transpiler/src/riscv/generator.rs create mode 100644 bitvm-transpiler/src/riscv/mod.rs diff --git a/bitvm-transpiler/.gitignore b/bitvm-transpiler/.gitignore new file mode 100644 index 0000000..059a814 --- /dev/null +++ b/bitvm-transpiler/.gitignore @@ -0,0 +1,3 @@ +/target +**target/ +.vscode diff --git a/bitvm-transpiler/Cargo.toml b/bitvm-transpiler/Cargo.toml new file mode 100644 index 0000000..ecea7db --- /dev/null +++ b/bitvm-transpiler/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "bitvm-transpiler" +description = "Binary to BitVM assembly transpiler" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap = { version = "4.5.3", features = ["derive"] } +elf = "0.7.4" +file-format = "0.24.0" diff --git a/bitvm-transpiler/LICENSE b/bitvm-transpiler/LICENSE new file mode 100644 index 0000000..a4bd34c --- /dev/null +++ b/bitvm-transpiler/LICENSE @@ -0,0 +1,617 @@ +# 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. diff --git a/bitvm-transpiler/README.md b/bitvm-transpiler/README.md new file mode 100644 index 0000000..3a640f2 --- /dev/null +++ b/bitvm-transpiler/README.md @@ -0,0 +1,33 @@ +# BitVM Transpiler + +This is a **WIP** transpiler for converting other assembly languages to BitVM +assembly. This transpiler accepts different input file formats and ISA's. + +## Running the Transpiler + +```bash +cargo run --release $INPUTFILE +``` + +## Accepted Input File Formats + +This transpiler can read and parse instructions only in executable and linkable +format (ELF). + +## Supported Instruction Set Architectures and Extensions + +Currently, BitVM tries to emulate rv32i instruction set. But this transpiler can +support more instruction sets or extension sets as input. Supported ISA's +resides in `src/*_parser`. + +* rv32i + m extension + +## References + +* Carsten Munk's rv32i to BitVM transpiler - https://github.com/zippiehq/rv32i-to-bitvm/. + +## License + +This project is licensed under the GNU General Public License v3.0 - see the +[LICENSE](LICENSE) file for details. By using, distributing, or contributing to +this software, you agree to the terms and conditions of the GPLv3. diff --git a/bitvm-transpiler/src/bitvm.rs b/bitvm-transpiler/src/bitvm.rs new file mode 100644 index 0000000..d9869c2 --- /dev/null +++ b/bitvm-transpiler/src/bitvm.rs @@ -0,0 +1,47 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// 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 . + +//! BitVM machine description. Parsers must target these descriptions. Most of +//! the stuff here are copied from the official BitVM implementation. + +pub const ASM_ADD: u8 = 1; +pub const ASM_SUB: u8 = 2; +pub const ASM_MUL: u8 = 3; +pub const ASM_AND: u8 = 4; +pub const ASM_OR: u8 = 5; +pub const ASM_XOR: u8 = 6; +pub const ASM_ADDI: u8 = 7; +pub const ASM_SUBI: u8 = 8; +pub const ASM_ANDI: u8 = 9; +pub const ASM_ORI: u8 = 10; +pub const ASM_XORI: u8 = 11; +pub const ASM_JMP: u8 = 12; +pub const ASM_BEQ: u8 = 13; +pub const ASM_BNE: u8 = 14; +pub const ASM_RSHIFT1: u8 = 15; +pub const ASM_SLTU: u8 = 16; +pub const ASM_SLT: u8 = 17; +pub const ASM_SYSCALL: u8 = 18; +pub const ASM_LOAD: u8 = 19; +pub const ASM_STORE: u8 = 20; + +#[derive(Copy, Clone)] +pub struct Instruction { + pub asm_type: u8, + pub address_a: u32, + pub address_b: u32, + pub address_c: u32, +} diff --git a/bitvm-transpiler/src/cli.rs b/bitvm-transpiler/src/cli.rs new file mode 100644 index 0000000..e02c8a5 --- /dev/null +++ b/bitvm-transpiler/src/cli.rs @@ -0,0 +1,62 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! This module parses CLI arguments and options. + +use clap::Parser; +use file_format::FileFormat; +use std::path::PathBuf; + +/// Command line arguments and flags. Clap will handle these. +#[derive(Parser, Debug)] +#[command(version, about)] +struct Args { + /// Input file to be converted to BitVM assembly. + input: Option, +} + +/// Main function to parse all command line inputs. +pub fn parse_cli() -> PathBuf { + let cli = Args::parse(); + let mut input_file = PathBuf::new(); + + match cli.input.as_deref() { + Some(file) => input_file = file.to_owned(), + None => fatal_error("Input file not given."), + } + + check_file_format(&input_file); + + input_file +} + +/// Checks if file format is supported. Exits program in case of any +/// incompatibility. +fn check_file_format(input_file: &PathBuf) { + let fmt = FileFormat::from_file(input_file); + + match fmt { + Ok(FileFormat::ExecutableAndLinkableFormat) => (), + Err(e) => fatal_error(e.to_string().as_str()), + _ => fatal_error("Input file format not supported."), + } +} + +/// Prints a simple error message and exits program with an error code in case +/// of any error while parsing CLI arguments. +fn fatal_error(error: &str) { + panic!("Fatal error while parsing CLI arguments: {}", error); +} diff --git a/bitvm-transpiler/src/elf_parser.rs b/bitvm-transpiler/src/elf_parser.rs new file mode 100644 index 0000000..87cf8e0 --- /dev/null +++ b/bitvm-transpiler/src/elf_parser.rs @@ -0,0 +1,103 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// 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 . + +//! # Executable and Linkable Format Parser +//! +//! This module reads an ELF input binary file's contents and saves important +//! bits to memory. +//! +//! We only need actual program code in an ELF file. Needed sections include: +//! * .text +//! * .data +//! +//! Note: This parser heavily depends on a 3rd party elf library. + +use elf::endian::AnyEndian; +use elf::file::Class; +use elf::section::SectionHeader; +use elf::ElfStream; +use std::path::PathBuf; + +/// Parsed binary file content, which is ready for transpiling. +#[derive(Clone)] +pub struct InputBinary { + pub isa: Isa, + pub code_page: Vec, + pub code_addr: u64, + pub data_page: Vec, + pub data_addr: u64, +} + +impl InputBinary { + pub fn new() -> Self { + Self { + isa: Isa::None, + code_page: vec![], + code_addr: 0, + data_page: vec![], + data_addr: 0, + } + } +} + +/// Supported ISA's. +#[derive(Clone, Copy)] +pub enum Isa { + None, + Riscv32, + Riscv64, +} + +/// Reads file and section headers. Returns ELF target machine information and +/// actual code. +pub fn read_elf_file(input_file: PathBuf) -> InputBinary { + let mut binary = InputBinary::new(); + let path = std::path::PathBuf::from(input_file); + let io = std::fs::File::open(path).expect("Could not open ELF file."); + let mut file = + ElfStream::::open_stream(io).expect("Could not open ELF file as a stream."); + + let text_section = get_a_section(&mut file, ".text"); + binary.code_page = text_section.0.to_vec(); + binary.code_addr = text_section.1; + + let data_section = get_a_section(&mut file, ".data"); + binary.data_page = data_section.0.to_vec(); + binary.data_addr = data_section.1; + + binary.isa = match file.ehdr.e_machine { + 0xF3 => match file.ehdr.class { + Class::ELF32 => Isa::Riscv32, + Class::ELF64 => Isa::Riscv64, + }, + _ => panic!("Unsupported ISA!"), + }; + + binary +} + +/// Gets a raw section data and it's offset. +fn get_a_section<'a, T>(file: &'a mut ElfStream, section: &str) -> (&'a [u8], u64) +where + T: std::io::Read + std::io::Seek, +{ + let shdr: SectionHeader = *file + .section_header_by_name(section) + .expect("section table should be parseable") + .expect(format!("file should have a {} section", section).as_str()); + + (file.section_data(&shdr).unwrap().0, shdr.sh_offset) +} diff --git a/bitvm-transpiler/src/main.rs b/bitvm-transpiler/src/main.rs new file mode 100644 index 0000000..4002903 --- /dev/null +++ b/bitvm-transpiler/src/main.rs @@ -0,0 +1,50 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// 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 . + +//! # BitVM Transpiler +//! +//! This program can accept certain assembly source and binary files as inputs +//! and outputs BitVM executable files. +//! +//! ## Program Flow +//! +//! 1. Parse CLI flags and options +//! 2. Read input binary file and get instructions +//! 3. Run ISA specific decoder +//! 4. Run ISA specific BitVM assembler +//! 5. Write BitVM assembly to a file + +mod bitvm; +mod cli; +mod elf_parser; +mod riscv; + +fn main() { + let input_file = cli::parse_cli(); + + let binary = elf_parser::read_elf_file(input_file); + let isa = binary.isa; + + let decoded_binary = match isa { + elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => riscv::decode(binary), + elf_parser::Isa::None => panic!("ISA not supported!"), + }; + + match isa { + elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => riscv::generate_code(decoded_binary), + elf_parser::Isa::None => panic!("ISA not supported!"), + }; +} diff --git a/bitvm-transpiler/src/riscv/decoder.rs b/bitvm-transpiler/src/riscv/decoder.rs new file mode 100644 index 0000000..7cfe108 --- /dev/null +++ b/bitvm-transpiler/src/riscv/decoder.rs @@ -0,0 +1,362 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// 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 . + +//! Bit format agnostic RISC-V ISA decoder. + +use super::{Instruction, RiscvInstructions}; +use crate::elf_parser; + +/// Decodes binary to an `Instruction` array. +pub fn decode(binary: elf_parser::InputBinary) -> Vec { + let mut instructions = Vec::new(); + let code_page = binary.code_page; + + for i in (0..(code_page.len() / 4)).step_by(4) { + let raw: u32 = ((code_page[i + 3] as u32) << 24) + + ((code_page[i + 2] as u32) << 16) + + ((code_page[i + 1] as u32) << 8) + + ((code_page[i + 0] as u32) << 0); + instructions.push(decode_raw_instruction(raw).unwrap()); + } + + instructions +} + +/// Decodes a raw instruction to an `Instruction` struct. +fn decode_raw_instruction(raw_instruction: u32) -> Result { + let mut instr = RiscvInstructions::NONE; + let opcode = raw_instruction & 0x7f; + let rd = (raw_instruction >> 7) & 0x1f; + let rs1 = (raw_instruction >> 15) & 0x1f; + let rs2 = (raw_instruction >> 20) & 0x1f; + let funct3 = (raw_instruction >> 12) & 0x7; + let funct7 = (raw_instruction >> 25) & 0x7f; + let mut imm: u32 = 0; + + match opcode { + 0x03 => { + imm = raw_instruction >> 20; + match funct3 { + 0x0 => instr = RiscvInstructions::LB, + 0x1 => instr = RiscvInstructions::LH, + 0x2 => instr = RiscvInstructions::LW, + 0x3 => instr = RiscvInstructions::LD, + 0x4 => instr = RiscvInstructions::LBU, + 0x5 => instr = RiscvInstructions::LHU, + 0x6 => instr = RiscvInstructions::LWU, + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + } + } + 0x0f => match funct3 { + 0x0 => instr = RiscvInstructions::FENCE, + 0x1 => instr = RiscvInstructions::FENCEI, + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + }, + 0x13 => { + imm = (raw_instruction & 0xfff00000) >> 20; + let shamt = imm & 0x3f; + match funct3 { + 0x0 => instr = RiscvInstructions::ADDI, + 0x1 => { + instr = RiscvInstructions::SLLI; + imm = shamt; + } + 0x2 => instr = RiscvInstructions::SLTI, + 0x3 => instr = RiscvInstructions::SLTIU, + 0x4 => instr = RiscvInstructions::XORI, + 0x5 => match funct7 >> 1 { + 0x00 => { + instr = RiscvInstructions::SRLI; + imm = shamt; + } + 0x10 => { + instr = RiscvInstructions::SRAI; + imm = shamt; + } + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + }, + 0x6 => instr = RiscvInstructions::ORI, + 0x7 => instr = RiscvInstructions::ANDI, + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + } + } + 0x17 => { + imm = raw_instruction & 0xfffff000; + instr = RiscvInstructions::AUIPC; + } + 0x1b => { + imm = raw_instruction >> 20; + let shamt = imm & 0x1f; + match funct3 { + 0x0 => instr = RiscvInstructions::ADDIW, + 0x1 => { + imm = shamt; + instr = RiscvInstructions::SLLIW; + } + 0x5 => match funct7 { + 0x00 => { + imm = shamt; + instr = RiscvInstructions::SRLIW; + } + 0x20 => { + imm = shamt; + instr = RiscvInstructions::SRAIW; + } + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + }, + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + } + } + 0x23 => { + imm = ((raw_instruction & 0xfe000000) >> 20) | ((raw_instruction >> 7) & 0x1f); + match funct3 { + 0x0 => instr = RiscvInstructions::SB, + 0x1 => instr = RiscvInstructions::SH, + 0x2 => instr = RiscvInstructions::SW, + 0x3 => instr = RiscvInstructions::SD, + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + } + } + 0x2f => { + let funct5 = (funct7 & 0x7c) >> 2; + if funct3 == 0x2 && funct5 == 0x00 { + instr = RiscvInstructions::AMOADDW; + } else if funct3 == 0x2 && funct5 == 0x01 { + instr = RiscvInstructions::AMOSWAPW; + } else if funct3 == 0x2 && funct5 == 0x04 { + instr = RiscvInstructions::AMOXORW; + } else if funct3 == 0x2 && funct5 == 0x08 { + instr = RiscvInstructions::AMOORW; + } else if funct3 == 0x2 && funct5 == 0x0c { + instr = RiscvInstructions::AMOANDW; + } else if funct3 == 0x2 && funct5 == 0x10 { + instr = RiscvInstructions::AMOMINW; + } else if funct3 == 0x2 && funct5 == 0x14 { + instr = RiscvInstructions::AMOMAXW; + } else if funct3 == 0x2 && funct5 == 0x18 { + instr = RiscvInstructions::AMOMINUW; + } else if funct3 == 0x2 && funct5 == 0x1c { + instr = RiscvInstructions::AMOMAXUW; + } else if funct3 == 0x3 && funct5 == 0x00 { + instr = RiscvInstructions::AMOADDW; + } else if funct3 == 0x3 && funct5 == 0x01 { + instr = RiscvInstructions::AMOSWAPD; + } else if funct3 == 0x3 && funct5 == 0x04 { + instr = RiscvInstructions::AMOXORD; + } else if funct3 == 0x3 && funct5 == 0x08 { + instr = RiscvInstructions::AMOORD; + } else if funct3 == 0x3 && funct5 == 0x0c { + instr = RiscvInstructions::AMOANDD; + } else if funct3 == 0x3 && funct5 == 0x10 { + instr = RiscvInstructions::AMOMIND; + } else if funct3 == 0x3 && funct5 == 0x14 { + instr = RiscvInstructions::AMOMAXD; + } else if funct3 == 0x3 && funct5 == 0x18 { + instr = RiscvInstructions::AMOMINUD; + } else if funct3 == 0x3 && funct5 == 0x1c { + instr = RiscvInstructions::AMOMAXUD; + } else if funct3 == 0x2 && funct5 == 0x02 { + instr = RiscvInstructions::LRW; + } else if funct3 == 0x3 && funct5 == 0x02 { + instr = RiscvInstructions::LRD; + } else if funct3 == 0x2 && funct5 == 0x03 { + instr = RiscvInstructions::SCW; + } else if funct3 == 0x3 && funct5 == 0x03 { + instr = RiscvInstructions::SCD; + } + } + 0x33 => { + if funct3 == 0x0 && funct7 == 0x00 { + instr = RiscvInstructions::ADD; + } else if funct3 == 0x0 && funct7 == 0x01 { + instr = RiscvInstructions::MUL; + } else if funct3 == 0x0 && funct7 == 0x20 { + instr = RiscvInstructions::SUB; + } else if funct3 == 0x1 && funct7 == 0x00 { + instr = RiscvInstructions::SLL; + } else if funct3 == 0x1 && funct7 == 0x01 { + instr = RiscvInstructions::MULH; + } else if funct3 == 0x2 && funct7 == 0x01 { + instr = RiscvInstructions::MULHSU; + } else if funct3 == 0x2 && funct7 == 0x00 { + instr = RiscvInstructions::SLT; + } else if funct3 == 0x3 && funct7 == 0x00 { + instr = RiscvInstructions::SLTU; + } else if funct3 == 0x3 && funct7 == 0x01 { + instr = RiscvInstructions::MULHU; + } else if funct3 == 0x4 && funct7 == 0x00 { + instr = RiscvInstructions::XOR; + } else if funct3 == 0x4 && funct7 == 0x01 { + instr = RiscvInstructions::DIV; + } else if funct3 == 0x5 && funct7 == 0x00 { + instr = RiscvInstructions::SRL; + } else if funct3 == 0x5 && funct7 == 0x01 { + instr = RiscvInstructions::DIVU; + } else if funct3 == 0x5 && funct7 == 0x20 { + instr = RiscvInstructions::SRA; + } else if funct3 == 0x6 && funct7 == 0x01 { + instr = RiscvInstructions::REM; + } else if funct3 == 0x6 && funct7 == 0x00 { + instr = RiscvInstructions::OR; + } else if funct3 == 0x7 && funct7 == 0x00 { + instr = RiscvInstructions::AND; + } else if funct3 == 0x7 && funct7 == 0x01 { + instr = RiscvInstructions::REMU; + } + } + 0x37 => { + imm = (raw_instruction & 0xfffff000) >> 0; + instr = RiscvInstructions::LUI; + } + 0x3b => { + if funct3 == 0x0 && funct7 == 0x00 { + instr = RiscvInstructions::ADDW; + } else if funct3 == 0x0 && funct7 == 0x01 { + instr = RiscvInstructions::MULW; + } else if funct3 == 0x0 && funct7 == 0x20 { + instr = RiscvInstructions::SUBW; + } else if funct3 == 0x1 && funct7 == 0x00 { + instr = RiscvInstructions::SLLW; + } else if funct3 == 0x4 && funct7 == 0x01 { + instr = RiscvInstructions::DIVW; + } else if funct3 == 0x5 && funct7 == 0x00 { + instr = RiscvInstructions::SRLW; + } else if funct3 == 0x5 && funct7 == 0x01 { + instr = RiscvInstructions::DIVUW; + } else if funct3 == 0x5 && funct7 == 0x20 { + instr = RiscvInstructions::SRAW; + } else if funct3 == 0x6 && funct7 == 0x01 { + instr = RiscvInstructions::REMW; + } else if funct3 == 0x7 && funct7 == 0x01 { + instr = RiscvInstructions::REMUW; + } + } + 0x63 => { + imm = ((raw_instruction & 0x80000000) >> 19) + | ((raw_instruction & 0x80) << 4) + | ((raw_instruction >> 20) & 0x7e0) + | ((raw_instruction >> 7) & 0x1e); + match funct3 { + 0x0 => instr = RiscvInstructions::BEQ, + 0x1 => instr = RiscvInstructions::BNE, + 0x4 => instr = RiscvInstructions::BLT, + 0x5 => instr = RiscvInstructions::BGE, + 0x6 => instr = RiscvInstructions::BLTU, + 0x7 => instr = RiscvInstructions::BGEU, + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + } + } + 0x67 => { + instr = RiscvInstructions::JALR; + imm = (raw_instruction & 0xfff00000) >> 20; + } + 0x6f => { + instr = RiscvInstructions::JAL; + imm = ((raw_instruction & 0x80000000) >> 11) + | (raw_instruction & 0xff000) + | ((raw_instruction >> 9) & 0x800) + | ((raw_instruction >> 20) & 0x7fe); + } + 0x73 => { + imm = (raw_instruction & 0xfff00000) >> 20; + match funct3 { + 0x0 => { + if rs2 == 0x0 && funct7 == 0x0 { + instr = RiscvInstructions::ECALL; + } else if rs2 == 0x1 && funct7 == 0x0 { + instr = RiscvInstructions::EBREAK; + } + } + 0x1 => instr = RiscvInstructions::CSRRW, + 0x2 => instr = RiscvInstructions::CSRRS, + 0x3 => instr = RiscvInstructions::CSRRC, + 0x5 => instr = RiscvInstructions::CSRRWI, + 0x6 => instr = RiscvInstructions::CSRRSI, + 0x7 => instr = RiscvInstructions::CSRRCI, + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + } + } + _ => { + return Err(format!( + "Line {}: Illegal values for opcode {}", + line!(), + opcode + )) + } + } + + Ok(Instruction { + instr, + rs1, + rs2, + rd, + imm, + }) +} diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs new file mode 100644 index 0000000..74a7d01 --- /dev/null +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -0,0 +1,584 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// 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 . + +//! BitVM code generator for RISC-V targets + +use crate::bitvm; +use crate::riscv::{Instruction, RiscvInstructions::*}; + +/// Generates BitVM assembly using decoded RISC-V assembly. +pub fn generate_code(instructions: Vec) -> Vec { + let mut bitvm_instructions = Vec::new(); + + for i in instructions { + let instr = match i.instr { + ADD => add(i), + ADDI => addi(i), + _ => panic!("Illegal instruction: {:#?}", i.instr), + }; + + for j in instr { + bitvm_instructions.push(j); + } + } + + bitvm_instructions +} + +fn reg2mem(reg: u32) -> u32 { + reg * 4 +} +fn tmp() -> u32 { + 33 * 4 +} +fn tmp2() -> u32 { + 34 * 4 +} +fn tmp3() -> u32 { + 35 * 4 +} + +fn add(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: reg2mem(instruction.rd), + }] +} + +fn addi(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: reg2mem(instruction.rd), + }] +} + +fn sub(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: reg2mem(instruction.rd), + }] +} + +fn xor(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_XOR, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: reg2mem(instruction.rd), + }] +} + +fn xori(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_XORI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: reg2mem(instruction.rd), + }] +} + +fn and(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_AND, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: reg2mem(instruction.rd), + }] +} + +fn andi(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: reg2mem(instruction.rd), + }] +} + +fn or(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: reg2mem(instruction.rd), + }] +} + +fn ori(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ORI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: reg2mem(instruction.rd), + }] +} + +fn jal(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 4, + address_c: reg2mem(instruction.rd), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + ] +} + +fn lbu(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: reg2mem(instruction.rd), + }, + bitvm::Instruction { + // just to be sure someone didn't sneak in a uint32 value instead of a bit + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rd), + address_b: 0xFF, + address_c: reg2mem(instruction.rd), + }, + ] +} + +fn lh(instruction: Instruction) -> Vec { + let mut ret = vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: reg2mem(instruction.rd), + }, + bitvm::Instruction { + // just to be sure someone didn't sneak in a uint32 value instead of a bit + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rd), + address_b: 0xFF, + address_c: reg2mem(instruction.rd), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: tmp(), + address_b: 1, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: tmp2(), + }, + bitvm::Instruction { + // just to be sure someone didn't sneak in a uint32 value instead of a byte + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0xFF, + address_c: tmp2(), + }, + ]; + + for _ in 0..8 { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: tmp2(), + address_b: tmp2(), + address_c: tmp2(), + }); + } + + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(instruction.rd), + address_b: tmp2(), + address_c: reg2mem(instruction.rd), + }); + + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rd), + address_b: 0x8000, + address_c: tmp(), + }); + + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: tmp(), + address_b: tmp(), + address_c: tmp(), + }); + + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: 0, + address_b: tmp(), + address_c: tmp(), + }); + + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(instruction.rd), + address_b: tmp(), + address_c: reg2mem(instruction.rd), + }); + + ret +} + +fn lb(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: reg2mem(instruction.rd), + }, + bitvm::Instruction { + // Load can return up to 32-bit + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rd), + address_b: 0xFF, + address_c: reg2mem(instruction.rd), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rd), + address_b: 0x80, + address_c: tmp(), + }, + bitvm::Instruction { + // lshift + asm_type: bitvm::ASM_ADD, + address_a: tmp(), + address_b: tmp(), + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: 0, + address_b: tmp(), + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(instruction.rd), + address_b: tmp(), + address_c: reg2mem(instruction.rd), + }, + ] +} + +fn lhu(instruction: Instruction) -> Vec { + let mut ret = vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: reg2mem(instruction.rd), + }, + bitvm::Instruction { + // just to be sure someone didn't sneak in a uint32 value instead of a bit + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rd), + address_b: 0xFF, + address_c: reg2mem(instruction.rd), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: tmp(), + address_b: 1, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: tmp2(), + }, + bitvm::Instruction { + // just to be sure someone didn't sneak in a uint32 value instead of a byte + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0xFF, + address_c: tmp2(), + }, + ]; + + for _ in 0..8 { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: tmp2(), + address_b: tmp2(), + address_c: tmp2(), + }); + } + + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(instruction.rd), + address_b: tmp2(), + address_c: reg2mem(instruction.rd), + }); + + ret +} + +fn lw(instruction: Instruction) -> Vec { + let mut ret = vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm + 3, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: reg2mem(instruction.rd), + }, + bitvm::Instruction { + // just to be sure someone didn't sneak in a uint32 value instead of a bit + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rd), + address_b: 0xFF, + address_c: reg2mem(instruction.rd), + }, + ]; + + for _ in 0..8 { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_SUBI, + address_a: tmp(), + address_b: 1, + address_c: tmp(), + }); + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: tmp2(), + }); + ret.push(bitvm::Instruction { + // just to be sure someone didn't sneak in a uint32 value instead of a bit + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0xFF, + address_c: tmp2(), + }); + for __ in 0..8 { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: tmp2(), + address_b: tmp2(), + address_c: tmp2(), + }); + } + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(instruction.rd), + address_b: tmp2(), + address_c: reg2mem(instruction.rd), + }); + } + + ret +} + +fn sb(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(instruction.rs2), + address_b: 0, + address_c: tmp2(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0xFF, + address_c: tmp2(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_STORE, + address_a: tmp2(), + address_b: tmp(), + address_c: 0, + }, + ] +} + +fn sh(instruction: Instruction) -> Vec { + let mut ret = vec![ + bitvm::Instruction { // tmp is now rs1 + offset which is the memroy point where we want to store rs2[0:15] + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { // Move rs2 to tmp2, now we want to store tmp2 to the memory location in tmp. + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(instruction.rs2), + address_b: 0, + address_c: tmp2(), + }, + bitvm::Instruction { + // we get the last 8 bit and store it in tmp2 + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0xFF, + address_c: tmp2(), + }, + bitvm::Instruction {// Finally wrote the last byte, now we have to write rs2[9:15] + asm_type: bitvm::ASM_STORE, + address_a: tmp2(), + address_b: tmp(), + address_c: 0, + }, + bitvm::Instruction { // We move 1 byte to write the second half. + asm_type: bitvm::ASM_ADDI, + address_a: tmp(), + address_b: 1, + address_c: tmp(), + }, + bitvm::Instruction { + // rs2 is the value we want to write, moved it to tmp2 + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(instruction.rs2), + address_b: 0, + address_c: tmp2(), + }, + ]; + + for _ in 0..8 { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: tmp2(), + address_b: tmp2(), + address_c: tmp2(), + }); + } + + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0xFF, + address_c: tmp2(), + }); + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_STORE, + address_a: tmp2(), + address_b: tmp(), + address_c: 0, + }); + + ret +} + +fn sw(instruction: Instruction) -> Vec { + let mut ret = vec![ + bitvm::Instruction { + // Calculate base address and store it in tmp() for memory access + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { + // Temporarily store rs2 value for manipulation + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(instruction.rs2), + address_b: 0, + address_c: tmp2(), + }, + ]; + + for i in 0..4 { + // Isolate the current byte from tmp2() and store it + ret.push(bitvm::Instruction { + // Use a new tmp register if necessary + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0xFF, + address_c: tmp3(), + }); + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: tmp2(), + }); + // Prepare for the next byte unless it's the last byte + if i < 3 { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: tmp2(), + address_b: tmp2(), + address_c: tmp2(), + }); + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(instruction.rd), + address_b: tmp2(), + address_c: reg2mem(instruction.rd), + }); + } + } + + ret +} diff --git a/bitvm-transpiler/src/riscv/mod.rs b/bitvm-transpiler/src/riscv/mod.rs new file mode 100644 index 0000000..d47f5c7 --- /dev/null +++ b/bitvm-transpiler/src/riscv/mod.rs @@ -0,0 +1,251 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// 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 . + +//! # RISC-V Assembly Decoder and BitVM Code Generator +//! +//! This crate includes a RISC-V binary decoder and a BitVM code generator for +//! RISC-V ISA. +//! +//! ## About 32-bit and 64-bit Support +//! +//! RISC-V 32-bit ISA is not a subset of 64-bit ISA. Therefore we need different +//! code generators for both targets. But we can use the same decoder for both +//! targets. + +mod decoder; +mod generator; + +pub use decoder::decode; +pub use generator::generate_code; + +/// A decoded RISC-V instruction, ready for the use of RISC-V BitVM assembler. +#[derive(Debug)] +pub struct Instruction { + pub instr: RiscvInstructions, + pub rs1: u32, + pub rs2: u32, + pub rd: u32, + pub imm: u32, +} + +/// Instruction list for RISC-V targets. +#[allow(dead_code)] +#[derive(Debug)] +pub enum RiscvInstructions { + NONE, + // RV32I/RV64I + LUI, + AUIPC, + JAL, + JALR, + BEQ, + BNE, + BLT, + BGE, + BLTU, + BGEU, + LB, + LH, + LW, + LBU, + LHU, + SB, + SH, + SW, + ADDI, + SLTI, + SLTIU, + XORI, + ORI, + ANDI, + SLLI, + SRLI, + SRAI, + ADD, + SUB, + SLL, + SLT, + SLTU, + XOR, + SRL, + SRA, + OR, + AND, + FENCE, + ECALL, + EBREAK, + // RV64I + LWU, + LD, + SD, + ADDIW, + SLLIW, + SRLIW, + SRAIW, + ADDW, + SUBW, + SLLW, + SRLW, + SRAW, + // RV32/RV64 Zifencei + FENCEI, + // RV32/RV64 Zicsr + CSRRW, + CSRRS, + CSRRC, + CSRRWI, + CSRRSI, + CSRRCI, + // RV32M/RV64M + MUL, + MULH, + MULHSU, + MULHU, + DIV, + DIVU, + REM, + REMU, + // RV64M + MULW, + DIVW, + DIVUW, + REMW, + REMUW, + // RV32A/RV64A + LRW, + SCW, + AMOSWAPW, + AMOADDW, + AMOXORW, + AMOANDW, + AMOORW, + AMOMINW, + AMOMAXW, + AMOMINUW, + AMOMAXUW, + // RV64A + LRD, + SCD, + AMOSWAPD, + AMOADDD, + AMOXORD, + AMOANDD, + AMOORD, + AMOMIND, + AMOMAXD, + AMOMINUD, + AMOMAXUD, + // RV32F/RV64F + FLW, + FSW, + FMADDS, + FMSUBS, + FNMSUBS, + FNMADDS, + FADDS, + FSUBS, + FMULS, + FDIVS, + FSQRTS, + FSGNJS, + FSGNJNS, + FSGNJXS, + FMINS, + FMAXS, + FCVTWS, + FCVTWUS, + FMVXW, + FEQS, + FLTS, + FLES, + FCLASSS, + FCVTSW, + FCVTSWU, + FMVWX, + // RV64F + FCVTLS, + FCVTLUS, + FCVTSL, + FCVTSLU, + // RV32D/RV64D + FLD, + FSD, + FMADDD, + FMSUBD, + FNMSUBD, + FNMADDD, + FADDD, + FSUBD, + FMULD, + FDIVD, + FSQRTD, + FSGNJD, + FSGNJND, + FSGNJXD, + FMIND, + FMAXD, + FCVTSD, + FCVTDS, + FEQD, + FLTD, + FLED, + FCLASSD, + FCVTWD, + FCVTWUD, + FCVTDW, + FCVTDWU, + // RV64D + FCVTLD, + FCVTLUD, + FMVXD, + FCVTDL, + FCVTDLU, + FMVDX, + // RV32Q/RV64Q + FLQ, + FSQ, + FMADDQ, + FMSUBQ, + FNMSUBQ, + FNMADDQ, + FADDQ, + FSUBQ, + FMULQ, + FDIVQ, + FSQRTQ, + FSGNJQ, + FSGNJNQ, + FSGNJXQ, + FMINQ, + FMAXQ, + FCVTSQ, + FCVTQS, + FCVTDQ, + FCVTQD, + FEQQ, + FLTQ, + FLEQ, + FCLASSQ, + FCVTWQ, + FCVTWUQ, + FCVTQW, + FCVTQWU, + // RV64Q + FCVTLQ, + FCVTLUQ, + FCVTQL, + FCVTQLU, +} From 8293e65d202fc48ee2bf9fba1510e683f159dbc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Fri, 29 Mar 2024 20:15:52 +0300 Subject: [PATCH 02/26] Riscv_code_generator: Add bunch of instructions. --- bitvm-transpiler/src/riscv/generator.rs | 436 ++++++++++++++++++++++-- 1 file changed, 411 insertions(+), 25 deletions(-) diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 74a7d01..cb446d9 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -27,6 +27,41 @@ pub fn generate_code(instructions: Vec) -> Vec let instr = match i.instr { ADD => add(i), ADDI => addi(i), + SUB => sub(i), + XOR => xor(i), + XORI => xori(i), + AND => and(i), + ANDI => andi(i), + OR => or(i), + ORI => ori(i), + JAL => jal(i), + LBU => lbu(i), + LH => lh(i), + LB => lb(i), + LHU => lhu(i), + LW => lw(i), + SB => sb(i), + SH => sh(i), + SW => sw(i), + JALR => jalr(i), + AUIPC => auipc(i), + LUI => lui(i), + BEQ => beq(i), + BNE => bne(i), + SLLI => slli(i), + SRLI => srli(i), + SRAI => srai(i), + SLT => slt(i), + SLTU => sltu(i), + SLTIU => sltiu(i), + SLTI => slti(i), + BLT => blt(i), + BLTU => bltu(i), + BGE => bge(i), + BGEU => bgeu(i), + ECALL => ecall(i), + EBREAK => ebreak(i), + SRA => sra(i), _ => panic!("Illegal instruction: {:#?}", i.instr), }; @@ -465,39 +500,43 @@ fn sb(instruction: Instruction) -> Vec { fn sh(instruction: Instruction) -> Vec { let mut ret = vec![ - bitvm::Instruction { // tmp is now rs1 + offset which is the memroy point where we want to store rs2[0:15] + bitvm::Instruction { + // tmp is now rs1 + offset which is the memroy point where we want to store rs2[0:15] asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), }, - bitvm::Instruction { // Move rs2 to tmp2, now we want to store tmp2 to the memory location in tmp. + bitvm::Instruction { + // Move rs2 to tmp2, now we want to store tmp2 to the memory location in tmp. asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rs2), address_b: 0, address_c: tmp2(), }, bitvm::Instruction { - // we get the last 8 bit and store it in tmp2 + // we get the last 8 bit and store it in tmp2 asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0xFF, address_c: tmp2(), }, - bitvm::Instruction {// Finally wrote the last byte, now we have to write rs2[9:15] + bitvm::Instruction { + // Finally wrote the last byte, now we have to write rs2[9:15] asm_type: bitvm::ASM_STORE, address_a: tmp2(), address_b: tmp(), address_c: 0, }, - bitvm::Instruction { // We move 1 byte to write the second half. + bitvm::Instruction { + // We move 1 byte to write the second half. asm_type: bitvm::ASM_ADDI, address_a: tmp(), address_b: 1, address_c: tmp(), }, bitvm::Instruction { - // rs2 is the value we want to write, moved it to tmp2 + // rs2 is the value we want to write, moved it to tmp2 asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rs2), address_b: 0, @@ -516,15 +555,15 @@ fn sh(instruction: Instruction) -> Vec { ret.push(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, - address_a: tmp2(), - address_b: 0xFF, - address_c: tmp2(), + address_a: tmp2(), + address_b: 0xFF, + address_c: tmp2(), }); ret.push(bitvm::Instruction { asm_type: bitvm::ASM_STORE, - address_a: tmp2(), - address_b: tmp(), - address_c: 0, + address_a: tmp2(), + address_b: tmp(), + address_c: 0, }); ret @@ -533,14 +572,14 @@ fn sh(instruction: Instruction) -> Vec { fn sw(instruction: Instruction) -> Vec { let mut ret = vec![ bitvm::Instruction { - // Calculate base address and store it in tmp() for memory access + // Calculate base address and store it in tmp() for memory access asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), }, bitvm::Instruction { - // Temporarily store rs2 value for manipulation + // Temporarily store rs2 value for manipulation asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rs2), address_b: 0, @@ -549,36 +588,383 @@ fn sw(instruction: Instruction) -> Vec { ]; for i in 0..4 { - // Isolate the current byte from tmp2() and store it + // Isolate the current byte from tmp2() and store it ret.push(bitvm::Instruction { - // Use a new tmp register if necessary + // Use a new tmp register if necessary asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0xFF, address_c: tmp3(), }); ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(instruction.rs2), + address_b: 0, + address_c: tmp2(), + }); + // Prepare for the next byte unless it's the last byte + if i < 3 { + for _ in 0.. { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_RSHIFT1, + address_a: tmp2(), + address_b: tmp2(), + address_c: tmp2(), + }); + } + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: tmp(), + address_b: 1, + address_c: tmp(), + }); + } + } + + ret +} + +fn jalr(instruction: Instruction) -> Vec { + let mut ret = vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: tmp(), + address_b: 0xFFFFFFFE, + address_c: tmp(), + }, + bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), - address_c: tmp2(), + address_c: tmp(), + }, + ]; + + if instruction.rd != 0 { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 4, + address_c: reg2mem(instruction.rd), }); - // Prepare for the next byte unless it's the last byte - if i < 3 { + } + + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_JMP, + address_a: tmp(), + address_b: 0, + address_c: 0, + }); + + ret +} + +fn auipc(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + // imm is already << 12'ed + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: instruction.imm & 0xFFFFFFFF, + address_c: reg2mem(instruction.rd), + }] +} + +fn lui(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: (0b0110111 & 0xfffff000) >> 0, // 0110111: lui opcode + address_c: reg2mem(instruction.rd), + }] +} + +fn beq(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: 0, + }] +} + +fn bne(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_BNE, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: 0, + }] +} + +fn slli(instruction: Instruction) -> Vec { + let mut ret = vec![bitvm::Instruction { + asm_type: bitvm::ASM_BNE, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: 0, + }]; + + for _ in 0..(instruction.imm / 8) { + for __ in 0..8 { ret.push(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: tmp2(), address_b: tmp2(), address_c: tmp2(), }); - ret.push(bitvm::Instruction { - asm_type: bitvm::ASM_OR, - address_a: reg2mem(instruction.rd), - address_b: tmp2(), - address_c: reg2mem(instruction.rd), - }); } } + for _ in 0..(instruction.imm % 8) { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(instruction.rd), + address_b: reg2mem(instruction.rd), + address_c: reg2mem(instruction.rd), + }); + } + ret } + +fn srli(instruction: Instruction) -> Vec { + let mut ret = vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: 0, + address_c: reg2mem(instruction.rd), + }]; + + for _ in 0..(instruction.imm / 8) { + for __ in 0..8 { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_RSHIFT1, + address_a: reg2mem(instruction.rd), + address_b: 0, + address_c: reg2mem(instruction.rd), + }); + } + } + + for _ in 0..(instruction.imm % 8) { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_RSHIFT1, + address_a: reg2mem(instruction.rd), + address_b: 0, + address_c: reg2mem(instruction.rd), + }); + } + + ret +} + +fn srai(instruction: Instruction) -> Vec { + let mut ret = vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: 0, + address_c: reg2mem(instruction.rd), + }]; + + for _ in 0..(instruction.imm) { + for __ in 0..8 { + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rd), + address_b: 0x80000000, + address_c: tmp3(), + }); + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_RSHIFT1, + address_a: reg2mem(instruction.rd), + address_b: 0, + address_c: reg2mem(instruction.rd), + }); + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(instruction.rd), + address_b: tmp3(), + address_c: reg2mem(instruction.rd), + }); + } + } + + ret +} + +fn slt(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_SLT, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: reg2mem(instruction.rd), + }] +} + +fn sltu(instruction: Instruction) -> Vec { + vec![bitvm::Instruction { + asm_type: bitvm::ASM_SLTU, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: reg2mem(instruction.rd), + }] +} + +fn sltiu(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_SLTU, + address_a: reg2mem(instruction.rs1), + address_b: tmp(), + address_c: reg2mem(instruction.rd), + }, + ] +} + +fn slti(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: instruction.imm, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_SLT, + address_a: reg2mem(instruction.rs1), + address_b: tmp(), + address_c: reg2mem(instruction.rd), + }, + ] +} + +fn blt(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_SLT, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BNE, + address_a: tmp(), + address_b: reg2mem(0), + address_c: 0, + }, + ] +} + +fn bltu(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_SLTU, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BNE, + address_a: tmp(), + address_b: reg2mem(0), + address_c: 0, + }, + ] +} + +fn bge(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_SLTU, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: tmp(), + address_b: reg2mem(0), + address_c: 0, + }, + ] +} + +fn bgeu(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_SLTU, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: tmp(), + address_b: reg2mem(0), + address_c: 0, + }, + ] +} + +fn ecall(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 1, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(10), + address_b: reg2mem(0), + address_c: 0, + }, + ] +} + +fn ebreak(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 2, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + ] +} + +fn sra(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 2, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + ] +} From 6b97104ed309518dfa957196d5128a8eaa665011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Mon, 1 Apr 2024 10:35:36 +0300 Subject: [PATCH 03/26] Riscv_code_generator: Add rest of the instructions. --- bitvm-transpiler/src/bitvm.rs | 4 +- bitvm-transpiler/src/riscv/generator.rs | 207 +++++++++++++++++++++++- 2 files changed, 206 insertions(+), 5 deletions(-) diff --git a/bitvm-transpiler/src/bitvm.rs b/bitvm-transpiler/src/bitvm.rs index d9869c2..10c34b3 100644 --- a/bitvm-transpiler/src/bitvm.rs +++ b/bitvm-transpiler/src/bitvm.rs @@ -19,7 +19,7 @@ pub const ASM_ADD: u8 = 1; pub const ASM_SUB: u8 = 2; -pub const ASM_MUL: u8 = 3; +pub const _ASM_MUL: u8 = 3; pub const ASM_AND: u8 = 4; pub const ASM_OR: u8 = 5; pub const ASM_XOR: u8 = 6; @@ -34,7 +34,7 @@ pub const ASM_BNE: u8 = 14; pub const ASM_RSHIFT1: u8 = 15; pub const ASM_SLTU: u8 = 16; pub const ASM_SLT: u8 = 17; -pub const ASM_SYSCALL: u8 = 18; +pub const _ASM_SYSCALL: u8 = 18; pub const ASM_LOAD: u8 = 19; pub const ASM_STORE: u8 = 20; diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index cb446d9..aecad70 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -62,6 +62,8 @@ pub fn generate_code(instructions: Vec) -> Vec ECALL => ecall(i), EBREAK => ebreak(i), SRA => sra(i), + SRL => srl(i), + SLL => sll(i), _ => panic!("Illegal instruction: {:#?}", i.instr), }; @@ -918,7 +920,7 @@ fn bgeu(instruction: Instruction) -> Vec { ] } -fn ecall(instruction: Instruction) -> Vec { +fn ecall(_instruction: Instruction) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -935,7 +937,7 @@ fn ecall(instruction: Instruction) -> Vec { ] } -fn ebreak(instruction: Instruction) -> Vec { +fn ebreak(_instruction: Instruction) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -954,17 +956,216 @@ fn ebreak(instruction: Instruction) -> Vec { fn sra(instruction: Instruction) -> Vec { vec![ + bitvm::Instruction { + // result + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: 0, + address_c: tmp(), + }, + bitvm::Instruction { + // shift amount + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs2), + address_b: 0, + address_c: tmp2(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0x1F, + address_c: tmp2(), + }, bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), - address_b: 2, + address_b: reg2mem(0), + address_c: 0, + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: tmp2(), + address_c: 0, + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: tmp(), + address_b: 0x80000000, + address_c: tmp3(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_RSHIFT1, + address_a: tmp(), + address_b: 0, address_c: tmp(), }, + bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: tmp(), + address_b: tmp3(), + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_SUBI, + address_a: tmp2(), + address_b: 1, + address_c: tmp2(), + }, bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + bitvm::Instruction { + // result + asm_type: bitvm::ASM_ADDI, + address_a: tmp(), + address_b: 0, + address_c: reg2mem(instruction.rd), + }, + ] +} + +fn srl(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + // result + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: 0, + address_c: tmp(), + }, + bitvm::Instruction { + // shift amount + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs2), + address_b: 0, + address_c: tmp2(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0x1F, + address_c: tmp2(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: tmp2(), + address_c: 0, + }, + bitvm::Instruction { + asm_type: bitvm::ASM_RSHIFT1, + address_a: tmp(), + address_b: 0, + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_SUBI, + address_a: tmp2(), + address_b: 1, + address_c: tmp2(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + bitvm::Instruction { + // result + asm_type: bitvm::ASM_ADDI, + address_a: tmp(), + address_b: 0, + address_c: reg2mem(instruction.rd), + }, + ] +} + +fn sll(instruction: Instruction) -> Vec { + vec![ + bitvm::Instruction { + // result + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs1), + address_b: 0, + address_c: tmp(), + }, + bitvm::Instruction { + // shift amount + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(instruction.rs2), + address_b: 0, + address_c: tmp2(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0x1F, + address_c: tmp2(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: tmp2(), + address_c: 0, + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: tmp(), + address_b: tmp(), + address_c: tmp(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_SUBI, + address_a: tmp2(), + address_b: 1, + address_c: tmp2(), + }, + bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: 0, + }, + bitvm::Instruction { + // result + asm_type: bitvm::ASM_ADDI, + address_a: tmp(), + address_b: 0, + address_c: reg2mem(instruction.rd), + }, ] } From a4defd3c60abae8c45a5d4197cda5bde1cc4c4d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Mon, 1 Apr 2024 13:01:51 +0300 Subject: [PATCH 04/26] riscv_code_generator: Add initial tests. --- bitvm-transpiler/src/bitvm.rs | 2 +- bitvm-transpiler/src/riscv/generator.rs | 84 +++++++++++++++++++++++++ bitvm-transpiler/src/riscv/mod.rs | 4 +- 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/bitvm-transpiler/src/bitvm.rs b/bitvm-transpiler/src/bitvm.rs index 10c34b3..968c153 100644 --- a/bitvm-transpiler/src/bitvm.rs +++ b/bitvm-transpiler/src/bitvm.rs @@ -38,7 +38,7 @@ pub const _ASM_SYSCALL: u8 = 18; pub const ASM_LOAD: u8 = 19; pub const ASM_STORE: u8 = 20; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, PartialEq)] pub struct Instruction { pub asm_type: u8, pub address_a: u32, diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index aecad70..9bf9201 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -1169,3 +1169,87 @@ fn sll(instruction: Instruction) -> Vec { }, ] } + +#[cfg(test)] +mod tests { + #![cfg_attr(debug_assertions, allow(dead_code, unused_imports))] + use super::*; + use crate::bitvm; + use crate::riscv::{Instruction, RiscvInstructions::*}; + + // For most of the instructions, this is a good default. + const INPUT: Instruction = Instruction { + instr: ADD, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }; + + /// Update input instruction's values. + fn update_instruction(instr: &mut Instruction, rs1: u32, rs2: u32, rd: u32, imm: u32) { + instr.rs1 = rs1; + instr.rs2 = rs2; + instr.rd = rd; + instr.imm = imm; + } + + /// Convert input instruction values to zero. + fn make_it_zero(instr: &mut Instruction) { + update_instruction(instr, 0, 0, 0, 0); + } + + #[test] + fn test_add() { + let mut input = INPUT; + input.instr = ADD; + + assert_eq!( + add(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }] + ); + + make_it_zero(&mut input); + assert_eq!( + add(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + }] + ); + } + + #[test] + fn test_addi() { + let mut input = INPUT; + input.instr = ADDI; + + assert_eq!( + addi(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + }] + ); + + make_it_zero(&mut input); + assert_eq!( + addi(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 0, + address_c: reg2mem(0) + }] + ); + } +} diff --git a/bitvm-transpiler/src/riscv/mod.rs b/bitvm-transpiler/src/riscv/mod.rs index d47f5c7..2d5fdbe 100644 --- a/bitvm-transpiler/src/riscv/mod.rs +++ b/bitvm-transpiler/src/riscv/mod.rs @@ -32,7 +32,7 @@ pub use decoder::decode; pub use generator::generate_code; /// A decoded RISC-V instruction, ready for the use of RISC-V BitVM assembler. -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct Instruction { pub instr: RiscvInstructions, pub rs1: u32, @@ -43,7 +43,7 @@ pub struct Instruction { /// Instruction list for RISC-V targets. #[allow(dead_code)] -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub enum RiscvInstructions { NONE, // RV32I/RV64I From 06cc6b63130962e1c39dd71af074699953bf338a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Mon, 1 Apr 2024 14:47:47 +0300 Subject: [PATCH 05/26] riscv_code_generator: Add tests for generate_code(). --- bitvm-transpiler/src/riscv/generator.rs | 125 +++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 9bf9201..47c4f69 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -1174,8 +1174,8 @@ fn sll(instruction: Instruction) -> Vec { mod tests { #![cfg_attr(debug_assertions, allow(dead_code, unused_imports))] use super::*; - use crate::bitvm; use crate::riscv::{Instruction, RiscvInstructions::*}; + use crate::{bitvm, riscv}; // For most of the instructions, this is a good default. const INPUT: Instruction = Instruction { @@ -1199,6 +1199,129 @@ mod tests { update_instruction(instr, 0, 0, 0, 0); } + #[test] + fn test_generate_code() { + let input_instr = INPUT; + + // Single add instruction. + let input = vec![input_instr]; + assert_eq!( + generate_code(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }] + ); + + let input = vec![input_instr, input_instr]; + assert_eq!( + generate_code(input), + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + } + ] + ); + + let input = vec![ + input_instr, + Instruction { + instr: ADDI, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }, + ]; + assert_eq!( + generate_code(input), + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + } + ] + ); + + let input = vec![ + input_instr, + Instruction { + instr: ADDI, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }, + Instruction { + instr: SUB, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }, + ]; + assert_eq!( + generate_code(input), + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + }, + bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + } + ] + ); + + // Test whether big number of instructions are a problem or not. + // WARNING: This will take a long time to finish and use so much memory. + let mut input: Vec = Vec::new(); + let mut expected: Vec = Vec::new(); + let count = 5_000_000; + for _ in 0..count { + input.push(input_instr); + } + for _ in 0..count { + expected.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3), + }); + } + assert_eq!(generate_code(input), expected); + } + #[test] fn test_add() { let mut input = INPUT; From ec809d684ae165262c60f18a3df5917b177fdf47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Mon, 1 Apr 2024 15:01:37 +0300 Subject: [PATCH 06/26] riscv_code_generator: Fix infinite loop for SW instruction. --- bitvm-transpiler/src/riscv/generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 47c4f69..7995433 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -606,7 +606,7 @@ fn sw(instruction: Instruction) -> Vec { }); // Prepare for the next byte unless it's the last byte if i < 3 { - for _ in 0.. { + for _ in 0..8 { ret.push(bitvm::Instruction { asm_type: bitvm::ASM_RSHIFT1, address_a: tmp2(), From 43f38b7efb14e3174ad5922ed0e5912dcf8b42d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Mon, 1 Apr 2024 16:12:45 +0300 Subject: [PATCH 07/26] output: Add JSON file creator. --- bitvm-transpiler/Cargo.toml | 2 ++ bitvm-transpiler/src/bitvm.rs | 4 +++- bitvm-transpiler/src/main.rs | 5 ++++- bitvm-transpiler/src/output.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 bitvm-transpiler/src/output.rs diff --git a/bitvm-transpiler/Cargo.toml b/bitvm-transpiler/Cargo.toml index ecea7db..990c688 100644 --- a/bitvm-transpiler/Cargo.toml +++ b/bitvm-transpiler/Cargo.toml @@ -8,3 +8,5 @@ edition = "2021" clap = { version = "4.5.3", features = ["derive"] } elf = "0.7.4" file-format = "0.24.0" +serde = { version = "1.0.197", features = ["derive"] } +serde_json = "1.0.115" diff --git a/bitvm-transpiler/src/bitvm.rs b/bitvm-transpiler/src/bitvm.rs index 968c153..90c239a 100644 --- a/bitvm-transpiler/src/bitvm.rs +++ b/bitvm-transpiler/src/bitvm.rs @@ -17,6 +17,8 @@ //! BitVM machine description. Parsers must target these descriptions. Most of //! the stuff here are copied from the official BitVM implementation. +use serde::{Deserialize, Serialize}; + pub const ASM_ADD: u8 = 1; pub const ASM_SUB: u8 = 2; pub const _ASM_MUL: u8 = 3; @@ -38,7 +40,7 @@ pub const _ASM_SYSCALL: u8 = 18; pub const ASM_LOAD: u8 = 19; pub const ASM_STORE: u8 = 20; -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Instruction { pub asm_type: u8, pub address_a: u32, diff --git a/bitvm-transpiler/src/main.rs b/bitvm-transpiler/src/main.rs index 4002903..4c760b0 100644 --- a/bitvm-transpiler/src/main.rs +++ b/bitvm-transpiler/src/main.rs @@ -30,6 +30,7 @@ mod bitvm; mod cli; mod elf_parser; +mod output; mod riscv; fn main() { @@ -43,8 +44,10 @@ fn main() { elf_parser::Isa::None => panic!("ISA not supported!"), }; - match isa { + let bitvm_instructions = match isa { elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => riscv::generate_code(decoded_binary), elf_parser::Isa::None => panic!("ISA not supported!"), }; + + output::generate_json("bitvm", bitvm_instructions) } diff --git a/bitvm-transpiler/src/output.rs b/bitvm-transpiler/src/output.rs new file mode 100644 index 0000000..02f56c2 --- /dev/null +++ b/bitvm-transpiler/src/output.rs @@ -0,0 +1,28 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// 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 . + +//! Output file creation for transpiled instructions. + +use crate::bitvm::Instruction; +use std::fs::File; +use std::io::prelude::*; + +pub fn generate_json(file_name: &str, input: Vec) { + let serialized = serde_json::to_string_pretty(&input).unwrap(); + + let mut file = File::create(format!("{}.json", file_name)).unwrap(); + file.write_all(serialized.as_bytes()).unwrap(); +} From db7dc75bd0c053dc50622c5ad4f75fe04ae58183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Mon, 1 Apr 2024 17:15:28 +0300 Subject: [PATCH 08/26] riscv_code_generator: Reorganize tests and add new integer tests. --- bitvm-transpiler/src/riscv/generator.rs | 555 ++++++++++++++++-------- 1 file changed, 363 insertions(+), 192 deletions(-) diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 7995433..45cf508 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -19,6 +19,19 @@ use crate::bitvm; use crate::riscv::{Instruction, RiscvInstructions::*}; +fn reg2mem(reg: u32) -> u32 { + reg * 4 +} +fn tmp() -> u32 { + 33 * 4 +} +fn tmp2() -> u32 { + 34 * 4 +} +fn tmp3() -> u32 { + 35 * 4 +} + /// Generates BitVM assembly using decoded RISC-V assembly. pub fn generate_code(instructions: Vec) -> Vec { let mut bitvm_instructions = Vec::new(); @@ -74,18 +87,127 @@ pub fn generate_code(instructions: Vec) -> Vec bitvm_instructions } - -fn reg2mem(reg: u32) -> u32 { - reg * 4 -} -fn tmp() -> u32 { - 33 * 4 -} -fn tmp2() -> u32 { - 34 * 4 -} -fn tmp3() -> u32 { - 35 * 4 +#[test] +fn test_generate_code() { + let input_instr = tests::INPUT; + + // Single add instruction. + let input = vec![input_instr]; + assert_eq!( + generate_code(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }] + ); + + let input = vec![input_instr, input_instr]; + assert_eq!( + generate_code(input), + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + } + ] + ); + + let input = vec![ + input_instr, + Instruction { + instr: ADDI, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }, + ]; + assert_eq!( + generate_code(input), + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + } + ] + ); + + let input = vec![ + input_instr, + Instruction { + instr: ADDI, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }, + Instruction { + instr: SUB, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }, + ]; + assert_eq!( + generate_code(input), + vec![ + bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }, + bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + }, + bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + } + ] + ); + + // Test whether big number of instructions are a problem or not. + // WARNING: This will take a long time to finish and use so much memory. + let mut input: Vec = Vec::new(); + let mut expected: Vec = Vec::new(); + let count = 5_000_000; + for _ in 0..count { + input.push(input_instr); + } + for _ in 0..count { + expected.push(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3), + }); + } + assert_eq!(generate_code(input), expected); } fn add(instruction: Instruction) -> Vec { @@ -96,6 +218,31 @@ fn add(instruction: Instruction) -> Vec { address_c: reg2mem(instruction.rd), }] } +#[test] +fn test_add() { + let mut input = tests::INPUT; + + assert_eq!( + add(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + add(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + }] + ); +} fn addi(instruction: Instruction) -> Vec { vec![bitvm::Instruction { @@ -105,6 +252,31 @@ fn addi(instruction: Instruction) -> Vec { address_c: reg2mem(instruction.rd), }] } +#[test] +fn test_addi() { + let mut input = tests::INPUT; + + assert_eq!( + addi(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + }] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + addi(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 0, + address_c: reg2mem(0) + }] + ); +} fn sub(instruction: Instruction) -> Vec { vec![bitvm::Instruction { @@ -114,6 +286,32 @@ fn sub(instruction: Instruction) -> Vec { address_c: reg2mem(instruction.rd), }] } +#[test] +fn test_sub() { + let mut input = tests::INPUT; + + assert_eq!( + sub(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + sub(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + }] + ); +} + fn xor(instruction: Instruction) -> Vec { vec![bitvm::Instruction { @@ -123,6 +321,31 @@ fn xor(instruction: Instruction) -> Vec { address_c: reg2mem(instruction.rd), }] } +#[test] +fn test_xor() { + let mut input = tests::INPUT; + + assert_eq!( + xor(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_XOR, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + xor(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_XOR, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + }] + ); +} fn xori(instruction: Instruction) -> Vec { vec![bitvm::Instruction { @@ -132,6 +355,31 @@ fn xori(instruction: Instruction) -> Vec { address_c: reg2mem(instruction.rd), }] } +#[test] +fn test_xori() { + let mut input = tests::INPUT; + + assert_eq!( + xori(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_XORI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + }] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + xori(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_XORI, + address_a: reg2mem(0), + address_b: 0, + address_c: reg2mem(0) + }] + ); +} fn and(instruction: Instruction) -> Vec { vec![bitvm::Instruction { @@ -141,6 +389,31 @@ fn and(instruction: Instruction) -> Vec { address_c: reg2mem(instruction.rd), }] } +#[test] +fn test_and() { + let mut input = tests::INPUT; + + assert_eq!( + and(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_AND, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + and(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_AND, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + }] + ); +} fn andi(instruction: Instruction) -> Vec { vec![bitvm::Instruction { @@ -150,6 +423,31 @@ fn andi(instruction: Instruction) -> Vec { address_c: reg2mem(instruction.rd), }] } +#[test] +fn test_andi() { + let mut input = tests::INPUT; + + assert_eq!( + andi(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + }] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + andi(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(0), + address_b: 0, + address_c: reg2mem(0) + }] + ); +} fn or(instruction: Instruction) -> Vec { vec![bitvm::Instruction { @@ -159,6 +457,31 @@ fn or(instruction: Instruction) -> Vec { address_c: reg2mem(instruction.rd), }] } +#[test] +fn test_or() { + let mut input = tests::INPUT; + + assert_eq!( + or(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + or(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + }] + ); +} fn ori(instruction: Instruction) -> Vec { vec![bitvm::Instruction { @@ -168,6 +491,31 @@ fn ori(instruction: Instruction) -> Vec { address_c: reg2mem(instruction.rd), }] } +#[test] +fn test_ori() { + let mut input = tests::INPUT; + + assert_eq!( + ori(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ORI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + }] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + ori(input), + vec![bitvm::Instruction { + asm_type: bitvm::ASM_ORI, + address_a: reg2mem(0), + address_b: 0, + address_c: reg2mem(0) + }] + ); +} fn jal(instruction: Instruction) -> Vec { vec![ @@ -1178,7 +1526,7 @@ mod tests { use crate::{bitvm, riscv}; // For most of the instructions, this is a good default. - const INPUT: Instruction = Instruction { + pub const INPUT: Instruction = Instruction { instr: ADD, rs1: 1, rs2: 2, @@ -1187,7 +1535,7 @@ mod tests { }; /// Update input instruction's values. - fn update_instruction(instr: &mut Instruction, rs1: u32, rs2: u32, rd: u32, imm: u32) { + pub fn update_instruction(instr: &mut Instruction, rs1: u32, rs2: u32, rd: u32, imm: u32) { instr.rs1 = rs1; instr.rs2 = rs2; instr.rd = rd; @@ -1195,184 +1543,7 @@ mod tests { } /// Convert input instruction values to zero. - fn make_it_zero(instr: &mut Instruction) { + pub fn make_it_zero(instr: &mut Instruction) { update_instruction(instr, 0, 0, 0, 0); } - - #[test] - fn test_generate_code() { - let input_instr = INPUT; - - // Single add instruction. - let input = vec![input_instr]; - assert_eq!( - generate_code(input), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }] - ); - - let input = vec![input_instr, input_instr]; - assert_eq!( - generate_code(input), - vec![ - bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }, - bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - } - ] - ); - - let input = vec![ - input_instr, - Instruction { - instr: ADDI, - rs1: 1, - rs2: 2, - rd: 3, - imm: 4, - }, - ]; - assert_eq!( - generate_code(input), - vec![ - bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }, - bitvm::Instruction { - asm_type: bitvm::ASM_ADDI, - address_a: reg2mem(1), - address_b: 4, - address_c: reg2mem(3) - } - ] - ); - - let input = vec![ - input_instr, - Instruction { - instr: ADDI, - rs1: 1, - rs2: 2, - rd: 3, - imm: 4, - }, - Instruction { - instr: SUB, - rs1: 1, - rs2: 2, - rd: 3, - imm: 4, - }, - ]; - assert_eq!( - generate_code(input), - vec![ - bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }, - bitvm::Instruction { - asm_type: bitvm::ASM_ADDI, - address_a: reg2mem(1), - address_b: 4, - address_c: reg2mem(3) - }, - bitvm::Instruction { - asm_type: bitvm::ASM_SUB, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - } - ] - ); - - // Test whether big number of instructions are a problem or not. - // WARNING: This will take a long time to finish and use so much memory. - let mut input: Vec = Vec::new(); - let mut expected: Vec = Vec::new(); - let count = 5_000_000; - for _ in 0..count { - input.push(input_instr); - } - for _ in 0..count { - expected.push(bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3), - }); - } - assert_eq!(generate_code(input), expected); - } - - #[test] - fn test_add() { - let mut input = INPUT; - input.instr = ADD; - - assert_eq!( - add(input), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }] - ); - - make_it_zero(&mut input); - assert_eq!( - add(input), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(0), - address_b: reg2mem(0), - address_c: reg2mem(0) - }] - ); - } - - #[test] - fn test_addi() { - let mut input = INPUT; - input.instr = ADDI; - - assert_eq!( - addi(input), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADDI, - address_a: reg2mem(1), - address_b: 4, - address_c: reg2mem(3) - }] - ); - - make_it_zero(&mut input); - assert_eq!( - addi(input), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADDI, - address_a: reg2mem(0), - address_b: 0, - address_c: reg2mem(0) - }] - ); - } } From 6ede14208187b47ad5ef84bf79c841fe52c09d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Mon, 1 Apr 2024 18:31:19 +0300 Subject: [PATCH 09/26] riscv_code_generator: Pass binary information to code generator. --- bitvm-transpiler/src/elf_parser.rs | 17 ++ bitvm-transpiler/src/main.rs | 10 +- bitvm-transpiler/src/riscv/generator.rs | 225 +++++++++++++----------- 3 files changed, 143 insertions(+), 109 deletions(-) diff --git a/bitvm-transpiler/src/elf_parser.rs b/bitvm-transpiler/src/elf_parser.rs index 87cf8e0..aa0e6aa 100644 --- a/bitvm-transpiler/src/elf_parser.rs +++ b/bitvm-transpiler/src/elf_parser.rs @@ -61,6 +61,23 @@ pub enum Isa { Riscv64, } +/// This struct includes summary of the input binary. It is also a subset of +/// `InputBinary`. Therefore it is initialized using the `InputBinary` struct. +#[derive(Clone, Copy)] +pub struct BinaryInfo { + pub isa: Isa, + pub pc: u64, +} + +impl BinaryInfo { + pub fn from(input_binary: InputBinary) -> Self { + Self { + isa: input_binary.isa, + pc: input_binary.code_addr, + } + } +} + /// Reads file and section headers. Returns ELF target machine information and /// actual code. pub fn read_elf_file(input_file: PathBuf) -> InputBinary { diff --git a/bitvm-transpiler/src/main.rs b/bitvm-transpiler/src/main.rs index 4c760b0..fb6afc0 100644 --- a/bitvm-transpiler/src/main.rs +++ b/bitvm-transpiler/src/main.rs @@ -37,15 +37,17 @@ fn main() { let input_file = cli::parse_cli(); let binary = elf_parser::read_elf_file(input_file); - let isa = binary.isa; + let binary_info = elf_parser::BinaryInfo::from(binary.clone()); - let decoded_binary = match isa { + let decoded_binary = match binary_info.isa { elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => riscv::decode(binary), elf_parser::Isa::None => panic!("ISA not supported!"), }; - let bitvm_instructions = match isa { - elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => riscv::generate_code(decoded_binary), + let bitvm_instructions = match binary_info.isa { + elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => { + riscv::generate_code(binary_info, decoded_binary) + } elf_parser::Isa::None => panic!("ISA not supported!"), }; diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 45cf508..dbbf3ca 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -14,9 +14,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! BitVM code generator for RISC-V targets +//! BitVM code generator for RISC-V targets. Most of the RISC-V instructions are +//! not present in BitVM. So, we need to simulate them with instructions that +//! are present in BitVM. use crate::bitvm; +use crate::elf_parser::BinaryInfo; use crate::riscv::{Instruction, RiscvInstructions::*}; fn reg2mem(reg: u32) -> u32 { @@ -33,56 +36,61 @@ fn tmp3() -> u32 { } /// Generates BitVM assembly using decoded RISC-V assembly. -pub fn generate_code(instructions: Vec) -> Vec { +pub fn generate_code( + mut info: BinaryInfo, + instructions: Vec, +) -> Vec { let mut bitvm_instructions = Vec::new(); for i in instructions { let instr = match i.instr { - ADD => add(i), - ADDI => addi(i), - SUB => sub(i), - XOR => xor(i), - XORI => xori(i), - AND => and(i), - ANDI => andi(i), - OR => or(i), - ORI => ori(i), - JAL => jal(i), - LBU => lbu(i), - LH => lh(i), - LB => lb(i), - LHU => lhu(i), - LW => lw(i), - SB => sb(i), - SH => sh(i), - SW => sw(i), - JALR => jalr(i), - AUIPC => auipc(i), - LUI => lui(i), - BEQ => beq(i), - BNE => bne(i), - SLLI => slli(i), - SRLI => srli(i), - SRAI => srai(i), - SLT => slt(i), - SLTU => sltu(i), - SLTIU => sltiu(i), - SLTI => slti(i), - BLT => blt(i), - BLTU => bltu(i), - BGE => bge(i), - BGEU => bgeu(i), - ECALL => ecall(i), - EBREAK => ebreak(i), - SRA => sra(i), - SRL => srl(i), - SLL => sll(i), + ADD => add(i, info), + ADDI => addi(i, info), + SUB => sub(i, info), + XOR => xor(i, info), + XORI => xori(i, info), + AND => and(i, info), + ANDI => andi(i, info), + OR => or(i, info), + ORI => ori(i, info), + JAL => jal(i, info), + LBU => lbu(i, info), + LH => lh(i, info), + LB => lb(i, info), + LHU => lhu(i, info), + LW => lw(i, info), + SB => sb(i, info), + SH => sh(i, info), + SW => sw(i, info), + JALR => jalr(i, info), + AUIPC => auipc(i, info), + LUI => lui(i, info), + BEQ => beq(i, info), + BNE => bne(i, info), + SLLI => slli(i, info), + SRLI => srli(i, info), + SRAI => srai(i, info), + SLT => slt(i, info), + SLTU => sltu(i, info), + SLTIU => sltiu(i, info), + SLTI => slti(i, info), + BLT => blt(i, info), + BLTU => bltu(i, info), + BGE => bge(i, info), + BGEU => bgeu(i, info), + ECALL => ecall(i, info), + EBREAK => ebreak(i, info), + SRA => sra(i, info), + SRL => srl(i, info), + SLL => sll(i, info), _ => panic!("Illegal instruction: {:#?}", i.instr), }; for j in instr { bitvm_instructions.push(j); } + + info.pc += 1; } bitvm_instructions @@ -94,7 +102,7 @@ fn test_generate_code() { // Single add instruction. let input = vec![input_instr]; assert_eq!( - generate_code(input), + generate_code(tests::INFO, input), vec![bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: reg2mem(1), @@ -105,7 +113,7 @@ fn test_generate_code() { let input = vec![input_instr, input_instr]; assert_eq!( - generate_code(input), + generate_code(tests::INFO, input), vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADD, @@ -133,7 +141,7 @@ fn test_generate_code() { }, ]; assert_eq!( - generate_code(input), + generate_code(tests::INFO, input), vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADD, @@ -168,7 +176,7 @@ fn test_generate_code() { }, ]; assert_eq!( - generate_code(input), + generate_code(tests::INFO, input), vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADD, @@ -207,10 +215,10 @@ fn test_generate_code() { address_c: reg2mem(3), }); } - assert_eq!(generate_code(input), expected); + assert_eq!(generate_code(tests::INFO, input), expected); } -fn add(instruction: Instruction) -> Vec { +fn add(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rs1), @@ -223,7 +231,7 @@ fn test_add() { let mut input = tests::INPUT; assert_eq!( - add(input), + add(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: reg2mem(1), @@ -234,7 +242,7 @@ fn test_add() { tests::make_it_zero(&mut input); assert_eq!( - add(input), + add(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: reg2mem(0), @@ -244,7 +252,7 @@ fn test_add() { ); } -fn addi(instruction: Instruction) -> Vec { +fn addi(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), @@ -257,7 +265,7 @@ fn test_addi() { let mut input = tests::INPUT; assert_eq!( - addi(input), + addi(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(1), @@ -268,7 +276,7 @@ fn test_addi() { tests::make_it_zero(&mut input); assert_eq!( - addi(input), + addi(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), @@ -278,7 +286,7 @@ fn test_addi() { ); } -fn sub(instruction: Instruction) -> Vec { +fn sub(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_SUB, address_a: reg2mem(instruction.rs1), @@ -291,7 +299,7 @@ fn test_sub() { let mut input = tests::INPUT; assert_eq!( - sub(input), + sub(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_SUB, address_a: reg2mem(1), @@ -302,7 +310,7 @@ fn test_sub() { tests::make_it_zero(&mut input); assert_eq!( - sub(input), + sub(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_SUB, address_a: reg2mem(0), @@ -312,8 +320,7 @@ fn test_sub() { ); } - -fn xor(instruction: Instruction) -> Vec { +fn xor(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_XOR, address_a: reg2mem(instruction.rs1), @@ -326,7 +333,7 @@ fn test_xor() { let mut input = tests::INPUT; assert_eq!( - xor(input), + xor(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_XOR, address_a: reg2mem(1), @@ -337,7 +344,7 @@ fn test_xor() { tests::make_it_zero(&mut input); assert_eq!( - xor(input), + xor(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_XOR, address_a: reg2mem(0), @@ -347,7 +354,7 @@ fn test_xor() { ); } -fn xori(instruction: Instruction) -> Vec { +fn xori(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_XORI, address_a: reg2mem(instruction.rs1), @@ -360,7 +367,7 @@ fn test_xori() { let mut input = tests::INPUT; assert_eq!( - xori(input), + xori(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_XORI, address_a: reg2mem(1), @@ -371,7 +378,7 @@ fn test_xori() { tests::make_it_zero(&mut input); assert_eq!( - xori(input), + xori(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_XORI, address_a: reg2mem(0), @@ -381,7 +388,7 @@ fn test_xori() { ); } -fn and(instruction: Instruction) -> Vec { +fn and(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_AND, address_a: reg2mem(instruction.rs1), @@ -394,7 +401,7 @@ fn test_and() { let mut input = tests::INPUT; assert_eq!( - and(input), + and(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_AND, address_a: reg2mem(1), @@ -405,7 +412,7 @@ fn test_and() { tests::make_it_zero(&mut input); assert_eq!( - and(input), + and(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_AND, address_a: reg2mem(0), @@ -415,7 +422,7 @@ fn test_and() { ); } -fn andi(instruction: Instruction) -> Vec { +fn andi(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rs1), @@ -428,7 +435,7 @@ fn test_andi() { let mut input = tests::INPUT; assert_eq!( - andi(input), + andi(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: reg2mem(1), @@ -439,7 +446,7 @@ fn test_andi() { tests::make_it_zero(&mut input); assert_eq!( - andi(input), + andi(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: reg2mem(0), @@ -449,7 +456,7 @@ fn test_andi() { ); } -fn or(instruction: Instruction) -> Vec { +fn or(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(instruction.rs1), @@ -462,7 +469,7 @@ fn test_or() { let mut input = tests::INPUT; assert_eq!( - or(input), + or(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(1), @@ -473,7 +480,7 @@ fn test_or() { tests::make_it_zero(&mut input); assert_eq!( - or(input), + or(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(0), @@ -483,7 +490,7 @@ fn test_or() { ); } -fn ori(instruction: Instruction) -> Vec { +fn ori(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_ORI, address_a: reg2mem(instruction.rs1), @@ -496,7 +503,7 @@ fn test_ori() { let mut input = tests::INPUT; assert_eq!( - ori(input), + ori(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_ORI, address_a: reg2mem(1), @@ -507,7 +514,7 @@ fn test_ori() { tests::make_it_zero(&mut input); assert_eq!( - ori(input), + ori(input, tests::INFO), vec![bitvm::Instruction { asm_type: bitvm::ASM_ORI, address_a: reg2mem(0), @@ -517,12 +524,14 @@ fn test_ori() { ); } -fn jal(instruction: Instruction) -> Vec { +/// Jump and link instruction in RISC-V makes unconditional jumps. +/// 1. Add program counter +fn jal(instruction: Instruction, info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), - address_b: 4, + address_b: info.pc as u32 + 4, address_c: reg2mem(instruction.rd), }, bitvm::Instruction { @@ -534,7 +543,7 @@ fn jal(instruction: Instruction) -> Vec { ] } -fn lbu(instruction: Instruction) -> Vec { +fn lbu(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -558,7 +567,7 @@ fn lbu(instruction: Instruction) -> Vec { ] } -fn lh(instruction: Instruction) -> Vec { +fn lh(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -647,7 +656,7 @@ fn lh(instruction: Instruction) -> Vec { ret } -fn lb(instruction: Instruction) -> Vec { +fn lb(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -696,7 +705,7 @@ fn lb(instruction: Instruction) -> Vec { ] } -fn lhu(instruction: Instruction) -> Vec { +fn lhu(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -757,7 +766,7 @@ fn lhu(instruction: Instruction) -> Vec { ret } -fn lw(instruction: Instruction) -> Vec { +fn lw(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -819,7 +828,7 @@ fn lw(instruction: Instruction) -> Vec { ret } -fn sb(instruction: Instruction) -> Vec { +fn sb(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -848,7 +857,7 @@ fn sb(instruction: Instruction) -> Vec { ] } -fn sh(instruction: Instruction) -> Vec { +fn sh(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ bitvm::Instruction { // tmp is now rs1 + offset which is the memroy point where we want to store rs2[0:15] @@ -919,7 +928,7 @@ fn sh(instruction: Instruction) -> Vec { ret } -fn sw(instruction: Instruction) -> Vec { +fn sw(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ bitvm::Instruction { // Calculate base address and store it in tmp() for memory access @@ -974,7 +983,7 @@ fn sw(instruction: Instruction) -> Vec { ret } -fn jalr(instruction: Instruction) -> Vec { +fn jalr(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -1015,7 +1024,7 @@ fn jalr(instruction: Instruction) -> Vec { ret } -fn auipc(instruction: Instruction) -> Vec { +fn auipc(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { // imm is already << 12'ed asm_type: bitvm::ASM_ADDI, @@ -1025,7 +1034,7 @@ fn auipc(instruction: Instruction) -> Vec { }] } -fn lui(instruction: Instruction) -> Vec { +fn lui(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), @@ -1034,7 +1043,7 @@ fn lui(instruction: Instruction) -> Vec { }] } -fn beq(instruction: Instruction) -> Vec { +fn beq(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(instruction.rs1), @@ -1043,7 +1052,7 @@ fn beq(instruction: Instruction) -> Vec { }] } -fn bne(instruction: Instruction) -> Vec { +fn bne(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_BNE, address_a: reg2mem(instruction.rs1), @@ -1052,7 +1061,7 @@ fn bne(instruction: Instruction) -> Vec { }] } -fn slli(instruction: Instruction) -> Vec { +fn slli(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![bitvm::Instruction { asm_type: bitvm::ASM_BNE, address_a: reg2mem(instruction.rs1), @@ -1083,7 +1092,7 @@ fn slli(instruction: Instruction) -> Vec { ret } -fn srli(instruction: Instruction) -> Vec { +fn srli(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), @@ -1114,7 +1123,7 @@ fn srli(instruction: Instruction) -> Vec { ret } -fn srai(instruction: Instruction) -> Vec { +fn srai(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), @@ -1148,7 +1157,7 @@ fn srai(instruction: Instruction) -> Vec { ret } -fn slt(instruction: Instruction) -> Vec { +fn slt(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_SLT, address_a: reg2mem(instruction.rs1), @@ -1157,7 +1166,7 @@ fn slt(instruction: Instruction) -> Vec { }] } -fn sltu(instruction: Instruction) -> Vec { +fn sltu(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_SLTU, address_a: reg2mem(instruction.rs1), @@ -1166,7 +1175,7 @@ fn sltu(instruction: Instruction) -> Vec { }] } -fn sltiu(instruction: Instruction) -> Vec { +fn sltiu(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -1183,7 +1192,7 @@ fn sltiu(instruction: Instruction) -> Vec { ] } -fn slti(instruction: Instruction) -> Vec { +fn slti(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -1200,7 +1209,7 @@ fn slti(instruction: Instruction) -> Vec { ] } -fn blt(instruction: Instruction) -> Vec { +fn blt(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_SLT, @@ -1217,7 +1226,7 @@ fn blt(instruction: Instruction) -> Vec { ] } -fn bltu(instruction: Instruction) -> Vec { +fn bltu(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_SLTU, @@ -1234,7 +1243,7 @@ fn bltu(instruction: Instruction) -> Vec { ] } -fn bge(instruction: Instruction) -> Vec { +fn bge(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_SLTU, @@ -1251,7 +1260,7 @@ fn bge(instruction: Instruction) -> Vec { ] } -fn bgeu(instruction: Instruction) -> Vec { +fn bgeu(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_SLTU, @@ -1268,7 +1277,7 @@ fn bgeu(instruction: Instruction) -> Vec { ] } -fn ecall(_instruction: Instruction) -> Vec { +fn ecall(_instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -1285,7 +1294,7 @@ fn ecall(_instruction: Instruction) -> Vec { ] } -fn ebreak(_instruction: Instruction) -> Vec { +fn ebreak(_instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -1302,7 +1311,7 @@ fn ebreak(_instruction: Instruction) -> Vec { ] } -fn sra(instruction: Instruction) -> Vec { +fn sra(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { // result @@ -1382,7 +1391,7 @@ fn sra(instruction: Instruction) -> Vec { ] } -fn srl(instruction: Instruction) -> Vec { +fn srl(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { // result @@ -1450,7 +1459,7 @@ fn srl(instruction: Instruction) -> Vec { ] } -fn sll(instruction: Instruction) -> Vec { +fn sll(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { // result @@ -1522,6 +1531,7 @@ fn sll(instruction: Instruction) -> Vec { mod tests { #![cfg_attr(debug_assertions, allow(dead_code, unused_imports))] use super::*; + use crate::elf_parser::Isa; use crate::riscv::{Instruction, RiscvInstructions::*}; use crate::{bitvm, riscv}; @@ -1534,6 +1544,11 @@ mod tests { imm: 4, }; + pub const INFO: BinaryInfo = BinaryInfo { + isa: Isa::Riscv32, + pc: 0, + }; + /// Update input instruction's values. pub fn update_instruction(instr: &mut Instruction, rs1: u32, rs2: u32, rd: u32, imm: u32) { instr.rs1 = rs1; From 42fc8ccd0d96dce34afc06b621f260f9819c6595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Tue, 2 Apr 2024 12:09:17 +0300 Subject: [PATCH 10/26] riscv_code_generator: Update PC relative instructions. --- bitvm-transpiler/src/riscv/generator.rs | 41 ++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index dbbf3ca..dffec9b 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -524,8 +524,6 @@ fn test_ori() { ); } -/// Jump and link instruction in RISC-V makes unconditional jumps. -/// 1. Add program counter fn jal(instruction: Instruction, info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { @@ -983,7 +981,7 @@ fn sw(instruction: Instruction, _info: BinaryInfo) -> Vec { ret } -fn jalr(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn jalr(instruction: Instruction, info: BinaryInfo) -> Vec { let mut ret = vec![ bitvm::Instruction { asm_type: bitvm::ASM_ADDI, @@ -1009,7 +1007,7 @@ fn jalr(instruction: Instruction, _info: BinaryInfo) -> Vec ret.push(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), - address_b: 4, + address_b: info.pc as u32 + 4, address_c: reg2mem(instruction.rd), }); } @@ -1024,51 +1022,60 @@ fn jalr(instruction: Instruction, _info: BinaryInfo) -> Vec ret } -fn auipc(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn auipc(instruction: Instruction, info: BinaryInfo) -> Vec { vec![bitvm::Instruction { // imm is already << 12'ed asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), - address_b: instruction.imm & 0xFFFFFFFF, + address_b: (instruction.imm + info.pc as u32) & 0xFFFFFFFF, address_c: reg2mem(instruction.rd), }] } +/// ISA data-sheet: LUI places the U-immediate value in the top 20 bits of the +/// destination register rd, filling in the lowest 12 bits with zeros. +/// +/// This is provided by decoder as the immediate value. fn lui(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), - address_b: (0b0110111 & 0xfffff000) >> 0, // 0110111: lui opcode + address_b: instruction.imm, address_c: reg2mem(instruction.rd), }] } -fn beq(instruction: Instruction, _info: BinaryInfo) -> Vec { +/// BitVM compares address_a and address_b for BEQ. If equal, changes PC to +/// address_c. Therefore we add immediate value and RISC-V PC for the address_c. +fn beq(instruction: Instruction, info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), - address_c: 0, + address_c: info.pc as u32 + instruction.imm, }] } -fn bne(instruction: Instruction, _info: BinaryInfo) -> Vec { +/// BNE works same way as the BEQ. +fn bne(instruction: Instruction, info: BinaryInfo) -> Vec { vec![bitvm::Instruction { asm_type: bitvm::ASM_BNE, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), - address_c: 0, + address_c: info.pc as u32 + instruction.imm, }] } fn slli(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![bitvm::Instruction { - asm_type: bitvm::ASM_BNE, + asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), - address_b: reg2mem(instruction.rs2), - address_c: 0, + address_b: 0, + address_c: reg2mem(instruction.rd), }]; + // Calculate the number of times to apply ASM_LSHIFT8 based on the immediate + // value. for _ in 0..(instruction.imm / 8) { for __ in 0..8 { ret.push(bitvm::Instruction { @@ -1080,6 +1087,7 @@ fn slli(instruction: Instruction, _info: BinaryInfo) -> Vec } } + // Calculate any remaining shifts that are less than 8 bits. for _ in 0..(instruction.imm % 8) { ret.push(bitvm::Instruction { asm_type: bitvm::ASM_ADD, @@ -1100,6 +1108,8 @@ fn srli(instruction: Instruction, _info: BinaryInfo) -> Vec address_c: reg2mem(instruction.rd), }]; + // Calculate the number of times to apply ASM_RSHIFT8 based on the immediate + // value. for _ in 0..(instruction.imm / 8) { for __ in 0..8 { ret.push(bitvm::Instruction { @@ -1111,6 +1121,7 @@ fn srli(instruction: Instruction, _info: BinaryInfo) -> Vec } } + // Calculate any remaining shifts that are less than 8 bits. for _ in 0..(instruction.imm % 8) { ret.push(bitvm::Instruction { asm_type: bitvm::ASM_RSHIFT1, @@ -1280,12 +1291,14 @@ fn bgeu(instruction: Instruction, _info: BinaryInfo) -> Vec fn ecall(_instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { + // tmp() acts as our status buffer: 0 = unknown 1 = OK, 2 = not OK asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: 1, address_c: tmp(), }, bitvm::Instruction { + // if x10 / a0 is 0, finish program asm_type: bitvm::ASM_BEQ, address_a: reg2mem(10), address_b: reg2mem(0), From 2e8902822e2a57fc4d6367f6d11467fb527f61e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Tue, 2 Apr 2024 15:10:15 +0300 Subject: [PATCH 11/26] riscv_code_generator: Add data page to output. --- bitvm-transpiler/src/main.rs | 3 ++- bitvm-transpiler/src/output.rs | 7 +++++-- bitvm-transpiler/src/riscv/generator.rs | 9 +++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/bitvm-transpiler/src/main.rs b/bitvm-transpiler/src/main.rs index fb6afc0..1ad73c7 100644 --- a/bitvm-transpiler/src/main.rs +++ b/bitvm-transpiler/src/main.rs @@ -38,6 +38,7 @@ fn main() { let binary = elf_parser::read_elf_file(input_file); let binary_info = elf_parser::BinaryInfo::from(binary.clone()); + let data = binary.data_page.clone(); let decoded_binary = match binary_info.isa { elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => riscv::decode(binary), @@ -51,5 +52,5 @@ fn main() { elf_parser::Isa::None => panic!("ISA not supported!"), }; - output::generate_json("bitvm", bitvm_instructions) + output::generate_json("bitvm", bitvm_instructions, data); } diff --git a/bitvm-transpiler/src/output.rs b/bitvm-transpiler/src/output.rs index 02f56c2..b814f17 100644 --- a/bitvm-transpiler/src/output.rs +++ b/bitvm-transpiler/src/output.rs @@ -20,9 +20,12 @@ use crate::bitvm::Instruction; use std::fs::File; use std::io::prelude::*; -pub fn generate_json(file_name: &str, input: Vec) { +pub fn generate_json(file_name: &str, input: Vec, data: Vec) { let serialized = serde_json::to_string_pretty(&input).unwrap(); + let data_serialized = serde_json::to_string_pretty(&data).unwrap(); let mut file = File::create(format!("{}.json", file_name)).unwrap(); - file.write_all(serialized.as_bytes()).unwrap(); + let out = String::from("{\n \"program\": ") + serialized.as_str() + ",\n \"memory_entries\": " + data_serialized.as_str() + "\n}"; + + file.write_all(out.as_bytes()).unwrap(); } diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index dffec9b..f972530 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -14,9 +14,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! # RISC-V Code Generator +//! //! BitVM code generator for RISC-V targets. Most of the RISC-V instructions are //! not present in BitVM. So, we need to simulate them with instructions that //! are present in BitVM. +//! +//! ## Memory Layout +//! +//! * XLEN = 4 if 32-bit else 8 +//! * x0 = 0 +//! * x1..x32 = 1*XLEN..32*XLEN +//! * First 3*XLEN bytes after registers are used for temporary storage use crate::bitvm; use crate::elf_parser::BinaryInfo; From c534b2ed0cf1fc177c3f562dfca7afa86fdd30dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Wed, 3 Apr 2024 16:21:41 +0300 Subject: [PATCH 12/26] elf_parser: Save every loadable section to memory. --- .vscode/settings.json | 3 +- bitvm-transpiler/src/elf_parser.rs | 45 ++++++++++++++++++++---------- bitvm-transpiler/src/main.rs | 11 +++++--- bitvm-transpiler/src/memory.rs | 35 +++++++++++++++++++++++ bitvm-transpiler/src/output.rs | 6 ++-- 5 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 bitvm-transpiler/src/memory.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 87b4b0c..887935e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "rust-analyzer.linkedProjects": [ "./Cargo.toml", "./examples/bitcoin-pow/methods/guest/Cargo.toml", - "./examples/bitcoin-pow/Cargo.toml" + "./examples/bitcoin-pow/Cargo.toml", + "./bitvm-transpiler/Cargo.toml" ] } diff --git a/bitvm-transpiler/src/elf_parser.rs b/bitvm-transpiler/src/elf_parser.rs index aa0e6aa..a3b9804 100644 --- a/bitvm-transpiler/src/elf_parser.rs +++ b/bitvm-transpiler/src/elf_parser.rs @@ -32,13 +32,13 @@ use elf::ElfStream; use std::path::PathBuf; /// Parsed binary file content, which is ready for transpiling. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct InputBinary { pub isa: Isa, pub code_page: Vec, pub code_addr: u64, - pub data_page: Vec, - pub data_addr: u64, + pub data_page: Vec>, + pub data_addr: Vec, } impl InputBinary { @@ -48,13 +48,13 @@ impl InputBinary { code_page: vec![], code_addr: 0, data_page: vec![], - data_addr: 0, + data_addr: vec![], } } } /// Supported ISA's. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum Isa { None, Riscv32, @@ -87,14 +87,6 @@ pub fn read_elf_file(input_file: PathBuf) -> InputBinary { let mut file = ElfStream::::open_stream(io).expect("Could not open ELF file as a stream."); - let text_section = get_a_section(&mut file, ".text"); - binary.code_page = text_section.0.to_vec(); - binary.code_addr = text_section.1; - - let data_section = get_a_section(&mut file, ".data"); - binary.data_page = data_section.0.to_vec(); - binary.data_addr = data_section.1; - binary.isa = match file.ehdr.e_machine { 0xF3 => match file.ehdr.class { Class::ELF32 => Isa::Riscv32, @@ -103,6 +95,12 @@ pub fn read_elf_file(input_file: PathBuf) -> InputBinary { _ => panic!("Unsupported ISA!"), }; + let text_section = get_a_section(&mut file, ".text"); + binary.code_page = text_section.0.to_vec(); + binary.code_addr = text_section.1; + + get_data_sections(&mut file, &mut binary); + binary } @@ -113,8 +111,25 @@ where { let shdr: SectionHeader = *file .section_header_by_name(section) - .expect("section table should be parseable") + .expect("section table should be parsable") .expect(format!("file should have a {} section", section).as_str()); - (file.section_data(&shdr).unwrap().0, shdr.sh_offset) + (file.section_data(&shdr).unwrap().0, shdr.sh_addr) +} + +/// Gets multiple loadable data sections. +fn get_data_sections<'a, T>(file: &'a mut ElfStream, binary: &mut InputBinary) +where + T: std::io::Read + std::io::Seek, +{ + // Get both actual section data and section name table. + let shdr = file.section_headers().clone(); + + for hdr in shdr { + if hdr.sh_addr != binary.code_addr + && hdr.sh_type == 1 && hdr.sh_addr != 0 { + binary.data_addr.push(hdr.sh_addr); + binary.data_page.push(file.section_data(&hdr).unwrap().0.to_vec()); + } + } } diff --git a/bitvm-transpiler/src/main.rs b/bitvm-transpiler/src/main.rs index 1ad73c7..bc412b7 100644 --- a/bitvm-transpiler/src/main.rs +++ b/bitvm-transpiler/src/main.rs @@ -25,11 +25,13 @@ //! 2. Read input binary file and get instructions //! 3. Run ISA specific decoder //! 4. Run ISA specific BitVM assembler -//! 5. Write BitVM assembly to a file +//! 5. Organize memory +//! 6. Write BitVM assembly and memory to a file mod bitvm; mod cli; mod elf_parser; +mod memory; mod output; mod riscv; @@ -38,10 +40,9 @@ fn main() { let binary = elf_parser::read_elf_file(input_file); let binary_info = elf_parser::BinaryInfo::from(binary.clone()); - let data = binary.data_page.clone(); let decoded_binary = match binary_info.isa { - elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => riscv::decode(binary), + elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => riscv::decode(binary.clone()), elf_parser::Isa::None => panic!("ISA not supported!"), }; @@ -52,5 +53,7 @@ fn main() { elf_parser::Isa::None => panic!("ISA not supported!"), }; - output::generate_json("bitvm", bitvm_instructions, data); + let out = memory::organize(binary); + + output::generate_json("bitvm", bitvm_instructions, out); } diff --git a/bitvm-transpiler/src/memory.rs b/bitvm-transpiler/src/memory.rs new file mode 100644 index 0000000..b35fea3 --- /dev/null +++ b/bitvm-transpiler/src/memory.rs @@ -0,0 +1,35 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// 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 . + +//! # Memory +//! +//! This module will organize output memory layout. +//! +//! ## Layout +//! +//! * XLEN = 4 if 32-bit else 8 +//! * x0 = 0 +//! * x1..x32 = 1*XLEN..32*XLEN +//! * First 3*XLEN bytes after registers are used for temporary storage +//! * code_addr..(code_addr+code_offset) has program counter (pc) values + +use crate::elf_parser::InputBinary; + +pub fn organize(binary: InputBinary) -> Vec { + let memory: Vec = Vec::new(); + + memory +} diff --git a/bitvm-transpiler/src/output.rs b/bitvm-transpiler/src/output.rs index b814f17..be7a886 100644 --- a/bitvm-transpiler/src/output.rs +++ b/bitvm-transpiler/src/output.rs @@ -20,12 +20,12 @@ use crate::bitvm::Instruction; use std::fs::File; use std::io::prelude::*; -pub fn generate_json(file_name: &str, input: Vec, data: Vec) { +pub fn generate_json(file_name: &str, input: Vec, memory: Vec) { let serialized = serde_json::to_string_pretty(&input).unwrap(); - let data_serialized = serde_json::to_string_pretty(&data).unwrap(); + let memory_serialized = serde_json::to_string_pretty(&memory).unwrap(); let mut file = File::create(format!("{}.json", file_name)).unwrap(); - let out = String::from("{\n \"program\": ") + serialized.as_str() + ",\n \"memory_entries\": " + data_serialized.as_str() + "\n}"; + let out = String::from("{\n \"program\": ") + serialized.as_str() + ",\n \"memory_entries\": " + memory_serialized.as_str() + "\n}"; file.write_all(out.as_bytes()).unwrap(); } From c112dae21b87502c1b3d7ff2fbe21ffb113ac6af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Wed, 3 Apr 2024 17:30:59 +0300 Subject: [PATCH 13/26] memory: Add memory generator for data sections. --- bitvm-transpiler/src/elf_parser.rs | 7 ++++--- bitvm-transpiler/src/main.rs | 4 ++-- bitvm-transpiler/src/memory.rs | 13 +++++++++++-- bitvm-transpiler/src/output.rs | 6 +++++- bitvm-transpiler/src/riscv/generator.rs | 8 ++++---- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/bitvm-transpiler/src/elf_parser.rs b/bitvm-transpiler/src/elf_parser.rs index a3b9804..84ac1ab 100644 --- a/bitvm-transpiler/src/elf_parser.rs +++ b/bitvm-transpiler/src/elf_parser.rs @@ -126,10 +126,11 @@ where let shdr = file.section_headers().clone(); for hdr in shdr { - if hdr.sh_addr != binary.code_addr - && hdr.sh_type == 1 && hdr.sh_addr != 0 { + if hdr.sh_addr != binary.code_addr && hdr.sh_type == 1 && hdr.sh_addr != 0 { binary.data_addr.push(hdr.sh_addr); - binary.data_page.push(file.section_data(&hdr).unwrap().0.to_vec()); + binary + .data_page + .push(file.section_data(&hdr).unwrap().0.to_vec()); } } } diff --git a/bitvm-transpiler/src/main.rs b/bitvm-transpiler/src/main.rs index bc412b7..49d6e43 100644 --- a/bitvm-transpiler/src/main.rs +++ b/bitvm-transpiler/src/main.rs @@ -53,7 +53,7 @@ fn main() { elf_parser::Isa::None => panic!("ISA not supported!"), }; - let out = memory::organize(binary); + let memory = memory::organize(binary); - output::generate_json("bitvm", bitvm_instructions, out); + output::generate_json("bitvm", bitvm_instructions, memory); } diff --git a/bitvm-transpiler/src/memory.rs b/bitvm-transpiler/src/memory.rs index b35fea3..99e4fac 100644 --- a/bitvm-transpiler/src/memory.rs +++ b/bitvm-transpiler/src/memory.rs @@ -28,8 +28,17 @@ use crate::elf_parser::InputBinary; +/// Memory size of the BitVM virtual machine in bytes. +pub const MEMSIZE: usize = 1024 * 1024 * 16; + pub fn organize(binary: InputBinary) -> Vec { - let memory: Vec = Vec::new(); + let mut memory: Vec = vec![0; MEMSIZE]; + + for i in 0..binary.data_page.len() { + for j in 0..binary.data_page[i].len() { + memory.insert(binary.data_addr[i] as usize + j, binary.data_page[i][j]); + } + } - memory + memory } diff --git a/bitvm-transpiler/src/output.rs b/bitvm-transpiler/src/output.rs index be7a886..11e6993 100644 --- a/bitvm-transpiler/src/output.rs +++ b/bitvm-transpiler/src/output.rs @@ -25,7 +25,11 @@ pub fn generate_json(file_name: &str, input: Vec, memory: Vec) let memory_serialized = serde_json::to_string_pretty(&memory).unwrap(); let mut file = File::create(format!("{}.json", file_name)).unwrap(); - let out = String::from("{\n \"program\": ") + serialized.as_str() + ",\n \"memory_entries\": " + memory_serialized.as_str() + "\n}"; + let out = String::from("{\n \"program\": ") + + serialized.as_str() + + ",\n \"memory_entries\": " + + memory_serialized.as_str() + + "\n}"; file.write_all(out.as_bytes()).unwrap(); } diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index f972530..0c0b104 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -15,13 +15,13 @@ // along with this program. If not, see . //! # RISC-V Code Generator -//! +//! //! BitVM code generator for RISC-V targets. Most of the RISC-V instructions are //! not present in BitVM. So, we need to simulate them with instructions that //! are present in BitVM. -//! +//! //! ## Memory Layout -//! +//! //! * XLEN = 4 if 32-bit else 8 //! * x0 = 0 //! * x1..x32 = 1*XLEN..32*XLEN @@ -1043,7 +1043,7 @@ fn auipc(instruction: Instruction, info: BinaryInfo) -> Vec /// ISA data-sheet: LUI places the U-immediate value in the top 20 bits of the /// destination register rd, filling in the lowest 12 bits with zeros. -/// +/// /// This is provided by decoder as the immediate value. fn lui(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![bitvm::Instruction { From 18500bf2ac2309b04e87f24f6f2331af2dc1e2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Wed, 3 Apr 2024 17:39:41 +0300 Subject: [PATCH 14/26] json_out: Don't use pretty, it wastes space. Instead, use jq after if needed. --- bitvm-transpiler/src/output.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bitvm-transpiler/src/output.rs b/bitvm-transpiler/src/output.rs index 11e6993..439dc4b 100644 --- a/bitvm-transpiler/src/output.rs +++ b/bitvm-transpiler/src/output.rs @@ -21,8 +21,8 @@ use std::fs::File; use std::io::prelude::*; pub fn generate_json(file_name: &str, input: Vec, memory: Vec) { - let serialized = serde_json::to_string_pretty(&input).unwrap(); - let memory_serialized = serde_json::to_string_pretty(&memory).unwrap(); + let serialized = serde_json::to_string(&input).unwrap(); + let memory_serialized = serde_json::to_string(&memory).unwrap(); let mut file = File::create(format!("{}.json", file_name)).unwrap(); let out = String::from("{\n \"program\": ") From ba6cdcbfd4c8f2e0d06423d8dbab5317130280d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Thu, 4 Apr 2024 12:23:45 +0300 Subject: [PATCH 15/26] riscv_code_generator: Add comments and fix wrong instructions. --- bitvm-transpiler/src/riscv/generator.rs | 91 +++++++++++++------------ 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 0c0b104..1cc608e 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -542,6 +542,7 @@ fn jal(instruction: Instruction, info: BinaryInfo) -> Vec { address_c: reg2mem(instruction.rd), }, bitvm::Instruction { + // TODO: this needs to be relative to pc asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), @@ -685,6 +686,7 @@ fn lb(instruction: Instruction, _info: BinaryInfo) -> Vec { address_c: reg2mem(instruction.rd), }, bitvm::Instruction { + // get MSB asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rd), address_b: 0x80, @@ -796,7 +798,7 @@ fn lw(instruction: Instruction, _info: BinaryInfo) -> Vec { }, ]; - for _ in 0..8 { + for _ in 0..3 { ret.push(bitvm::Instruction { asm_type: bitvm::ASM_SUBI, address_a: tmp(), @@ -912,7 +914,7 @@ fn sh(instruction: Instruction, _info: BinaryInfo) -> Vec { for _ in 0..8 { ret.push(bitvm::Instruction { - asm_type: bitvm::ASM_ADD, + asm_type: bitvm::ASM_RSHIFT1, address_a: tmp2(), address_b: tmp2(), address_c: tmp2(), @@ -963,10 +965,10 @@ fn sw(instruction: Instruction, _info: BinaryInfo) -> Vec { address_c: tmp3(), }); ret.push(bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(instruction.rs2), - address_b: 0, - address_c: tmp2(), + asm_type: bitvm::ASM_STORE, + address_a: tmp3(), + address_b: tmp(), + address_c: 0, }); // Prepare for the next byte unless it's the last byte if i < 3 { @@ -1061,7 +1063,7 @@ fn beq(instruction: Instruction, info: BinaryInfo) -> Vec { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), - address_c: info.pc as u32 + instruction.imm, + address_c: info.pc as u32 + instruction.imm, // TODO: check pc relative addressing }] } @@ -1071,7 +1073,7 @@ fn bne(instruction: Instruction, info: BinaryInfo) -> Vec { asm_type: bitvm::ASM_BNE, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), - address_c: info.pc as u32 + instruction.imm, + address_c: info.pc as u32 + instruction.imm, // TODO: check pc relative addressing }] } @@ -1089,9 +1091,9 @@ fn slli(instruction: Instruction, _info: BinaryInfo) -> Vec for __ in 0..8 { ret.push(bitvm::Instruction { asm_type: bitvm::ASM_ADD, - address_a: tmp2(), - address_b: tmp2(), - address_c: tmp2(), + address_a: reg2mem(instruction.rd), + address_b: reg2mem(instruction.rd), + address_c: reg2mem(instruction.rd), }); } } @@ -1152,26 +1154,24 @@ fn srai(instruction: Instruction, _info: BinaryInfo) -> Vec }]; for _ in 0..(instruction.imm) { - for __ in 0..8 { - ret.push(bitvm::Instruction { - asm_type: bitvm::ASM_ANDI, - address_a: reg2mem(instruction.rd), - address_b: 0x80000000, - address_c: tmp3(), - }); - ret.push(bitvm::Instruction { - asm_type: bitvm::ASM_RSHIFT1, - address_a: reg2mem(instruction.rd), - address_b: 0, - address_c: reg2mem(instruction.rd), - }); - ret.push(bitvm::Instruction { - asm_type: bitvm::ASM_OR, - address_a: reg2mem(instruction.rd), - address_b: tmp3(), - address_c: reg2mem(instruction.rd), - }); - } + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(instruction.rd), + address_b: 0x80000000, + address_c: tmp3(), + }); + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_RSHIFT1, + address_a: reg2mem(instruction.rd), + address_b: 0, + address_c: reg2mem(instruction.rd), + }); + ret.push(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(instruction.rd), + address_b: tmp3(), + address_c: reg2mem(instruction.rd), + }); } ret @@ -1241,7 +1241,7 @@ fn blt(instruction: Instruction, _info: BinaryInfo) -> Vec { asm_type: bitvm::ASM_BNE, address_a: tmp(), address_b: reg2mem(0), - address_c: 0, + address_c: 0, // TODO: Check pc relative addressing }, ] } @@ -1258,7 +1258,7 @@ fn bltu(instruction: Instruction, _info: BinaryInfo) -> Vec asm_type: bitvm::ASM_BNE, address_a: tmp(), address_b: reg2mem(0), - address_c: 0, + address_c: 0, // TODO: Check pc relative addressing }, ] } @@ -1266,7 +1266,7 @@ fn bltu(instruction: Instruction, _info: BinaryInfo) -> Vec fn bge(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ bitvm::Instruction { - asm_type: bitvm::ASM_SLTU, + asm_type: bitvm::ASM_SLT, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: tmp(), @@ -1275,7 +1275,7 @@ fn bge(instruction: Instruction, _info: BinaryInfo) -> Vec { asm_type: bitvm::ASM_BEQ, address_a: tmp(), address_b: reg2mem(0), - address_c: 0, + address_c: 0, // TODO: Check pc relative addressing }, ] } @@ -1311,7 +1311,7 @@ fn ecall(_instruction: Instruction, _info: BinaryInfo) -> Vec Vec Vec { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), - address_c: 0, + address_c: 0, // TODO: Check label }, bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: tmp2(), - address_c: 0, + address_c: 0, // TODO: Check label }, bitvm::Instruction { asm_type: bitvm::ASM_ANDI, @@ -1380,6 +1380,7 @@ fn sra(instruction: Instruction, _info: BinaryInfo) -> Vec { address_c: tmp(), }, bitvm::Instruction { + // add MSB asm_type: bitvm::ASM_OR, address_a: tmp(), address_b: tmp3(), @@ -1392,12 +1393,14 @@ fn sra(instruction: Instruction, _info: BinaryInfo) -> Vec { address_c: tmp2(), }, bitvm::Instruction { + // TODO: Check label asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, }, bitvm::Instruction { + // TODO: Check label asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), @@ -1436,12 +1439,14 @@ fn srl(instruction: Instruction, _info: BinaryInfo) -> Vec { address_c: tmp2(), }, bitvm::Instruction { + // TODO: Check label asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, }, bitvm::Instruction { + // TODO: Check label asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: tmp2(), @@ -1460,12 +1465,14 @@ fn srl(instruction: Instruction, _info: BinaryInfo) -> Vec { address_c: tmp2(), }, bitvm::Instruction { + // TODO: Check label asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, }, bitvm::Instruction { + // TODO: Check label asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), @@ -1507,13 +1514,13 @@ fn sll(instruction: Instruction, _info: BinaryInfo) -> Vec { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), - address_c: 0, + address_c: 0, // TODO: Check label }, bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: tmp2(), - address_c: 0, + address_c: 0, // TODO: Check label }, bitvm::Instruction { asm_type: bitvm::ASM_ADD, @@ -1531,7 +1538,7 @@ fn sll(instruction: Instruction, _info: BinaryInfo) -> Vec { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), - address_c: 0, + address_c: 0, // TODO: Check label }, bitvm::Instruction { asm_type: bitvm::ASM_ADDI, From e9a4752c3da728395aabc639d896d6408344a855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Thu, 4 Apr 2024 16:12:08 +0300 Subject: [PATCH 16/26] code_generators: Add unresolved BitVM instruction type. --- bitvm-transpiler/src/bitvm.rs | 54 + bitvm-transpiler/src/main.rs | 5 +- bitvm-transpiler/src/resolver.rs | 30 + bitvm-transpiler/src/riscv/generator.rs | 1378 +++++++++++------------ 4 files changed, 769 insertions(+), 698 deletions(-) create mode 100644 bitvm-transpiler/src/resolver.rs diff --git a/bitvm-transpiler/src/bitvm.rs b/bitvm-transpiler/src/bitvm.rs index 90c239a..e4ec1dd 100644 --- a/bitvm-transpiler/src/bitvm.rs +++ b/bitvm-transpiler/src/bitvm.rs @@ -47,3 +47,57 @@ pub struct Instruction { pub address_b: u32, pub address_c: u32, } + +/// Possible labels for a RISC-V instruction. +#[derive(Debug, Clone, Copy)] +pub enum Labels { + /// Represents program counter of the real RISC-V instruction. + Pc(u64), + /// Represents real program end. + _ProgramEnd, +} + +/// This struct will be used by the resolver to generate final BitVM assembly +/// instructions. +#[derive(Debug, Clone, Copy)] +pub struct UnresolvedInstruction { + pub instr: Instruction, + /// After code generation, this will be updated. + pub bitvm_pc: u64, + /// Metadata for resolver. + pub label: Labels, + /// If set, address_c will be resolved to label. + pub needs_resolving: bool, +} + +impl UnresolvedInstruction { + /// Creates a new unresolved instruction. + pub fn _new() -> Self { + Self { + instr: Instruction { + asm_type: 0, + address_a: 0, + address_b: 0, + address_c: 0, + }, + bitvm_pc: 0, + label: Labels::Pc(0), + needs_resolving: false, + } + } + + /// Creates an unresolved instruction, using a BitVM instruction. + pub fn from(instr: Instruction) -> Self { + Self { + instr: instr, + bitvm_pc: 0, + label: Labels::Pc(0), + needs_resolving: false, + } + } + + /// Returns the generated BitVM instruction, without actually resolving. + pub fn _lazy_resolve(&self) -> Instruction { + self.instr + } +} diff --git a/bitvm-transpiler/src/main.rs b/bitvm-transpiler/src/main.rs index 49d6e43..3e0aa5e 100644 --- a/bitvm-transpiler/src/main.rs +++ b/bitvm-transpiler/src/main.rs @@ -33,6 +33,7 @@ mod cli; mod elf_parser; mod memory; mod output; +mod resolver; mod riscv; fn main() { @@ -46,13 +47,15 @@ fn main() { elf_parser::Isa::None => panic!("ISA not supported!"), }; - let bitvm_instructions = match binary_info.isa { + let unresolved_instructions = match binary_info.isa { elf_parser::Isa::Riscv32 | elf_parser::Isa::Riscv64 => { riscv::generate_code(binary_info, decoded_binary) } elf_parser::Isa::None => panic!("ISA not supported!"), }; + let bitvm_instructions = resolver::resolve(unresolved_instructions); + let memory = memory::organize(binary); output::generate_json("bitvm", bitvm_instructions, memory); diff --git a/bitvm-transpiler/src/resolver.rs b/bitvm-transpiler/src/resolver.rs new file mode 100644 index 0000000..8006fbe --- /dev/null +++ b/bitvm-transpiler/src/resolver.rs @@ -0,0 +1,30 @@ +// bitvm-transpiler - Convert other assemblies to BitVM assembly. +// Copyright (C) 2024 Chainway Labs +// +// 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 +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! This module will resolve any label, that can't be resolved while generating +//! code. This operation is not ISA specific. + +use crate::bitvm; + +pub fn resolve(instructions: Vec) -> Vec { + let mut resolved = Vec::new(); + + for i in instructions { + resolved.push(i.instr); + } + + resolved +} diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 1cc608e..df5a1a6 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -48,7 +48,7 @@ fn tmp3() -> u32 { pub fn generate_code( mut info: BinaryInfo, instructions: Vec, -) -> Vec { +) -> Vec { let mut bitvm_instructions = Vec::new(); for i in instructions { @@ -104,1490 +104,1474 @@ pub fn generate_code( bitvm_instructions } -#[test] -fn test_generate_code() { - let input_instr = tests::INPUT; - - // Single add instruction. - let input = vec![input_instr]; - assert_eq!( - generate_code(tests::INFO, input), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }] - ); - - let input = vec![input_instr, input_instr]; - assert_eq!( - generate_code(tests::INFO, input), - vec![ - bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }, - bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - } - ] - ); - - let input = vec![ - input_instr, - Instruction { - instr: ADDI, - rs1: 1, - rs2: 2, - rd: 3, - imm: 4, - }, - ]; - assert_eq!( - generate_code(tests::INFO, input), - vec![ - bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }, - bitvm::Instruction { - asm_type: bitvm::ASM_ADDI, - address_a: reg2mem(1), - address_b: 4, - address_c: reg2mem(3) - } - ] - ); - - let input = vec![ - input_instr, - Instruction { - instr: ADDI, - rs1: 1, - rs2: 2, - rd: 3, - imm: 4, - }, - Instruction { - instr: SUB, - rs1: 1, - rs2: 2, - rd: 3, - imm: 4, - }, - ]; - assert_eq!( - generate_code(tests::INFO, input), - vec![ - bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }, - bitvm::Instruction { - asm_type: bitvm::ASM_ADDI, - address_a: reg2mem(1), - address_b: 4, - address_c: reg2mem(3) - }, - bitvm::Instruction { - asm_type: bitvm::ASM_SUB, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - } - ] - ); - - // Test whether big number of instructions are a problem or not. - // WARNING: This will take a long time to finish and use so much memory. - let mut input: Vec = Vec::new(); - let mut expected: Vec = Vec::new(); - let count = 5_000_000; - for _ in 0..count { - input.push(input_instr); - } - for _ in 0..count { - expected.push(bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3), - }); - } - assert_eq!(generate_code(tests::INFO, input), expected); -} -fn add(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn add(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: reg2mem(instruction.rd), - }] + })] } -#[test] -fn test_add() { - let mut input = tests::INPUT; - assert_eq!( - add(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }] - ); - - tests::make_it_zero(&mut input); - assert_eq!( - add(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADD, - address_a: reg2mem(0), - address_b: reg2mem(0), - address_c: reg2mem(0) - }] - ); -} - -fn addi(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn addi(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: reg2mem(instruction.rd), - }] -} -#[test] -fn test_addi() { - let mut input = tests::INPUT; - - assert_eq!( - addi(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADDI, - address_a: reg2mem(1), - address_b: 4, - address_c: reg2mem(3) - }] - ); - - tests::make_it_zero(&mut input); - assert_eq!( - addi(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ADDI, - address_a: reg2mem(0), - address_b: 0, - address_c: reg2mem(0) - }] - ); + })] } -fn sub(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn sub(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SUB, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: reg2mem(instruction.rd), - }] + })] } -#[test] -fn test_sub() { - let mut input = tests::INPUT; - assert_eq!( - sub(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_SUB, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }] - ); - - tests::make_it_zero(&mut input); - assert_eq!( - sub(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_SUB, - address_a: reg2mem(0), - address_b: reg2mem(0), - address_c: reg2mem(0) - }] - ); -} - -fn xor(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn xor(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_XOR, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: reg2mem(instruction.rd), - }] -} -#[test] -fn test_xor() { - let mut input = tests::INPUT; - - assert_eq!( - xor(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_XOR, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }] - ); - - tests::make_it_zero(&mut input); - assert_eq!( - xor(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_XOR, - address_a: reg2mem(0), - address_b: reg2mem(0), - address_c: reg2mem(0) - }] - ); + })] } -fn xori(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn xori(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_XORI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: reg2mem(instruction.rd), - }] -} -#[test] -fn test_xori() { - let mut input = tests::INPUT; - - assert_eq!( - xori(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_XORI, - address_a: reg2mem(1), - address_b: 4, - address_c: reg2mem(3) - }] - ); - - tests::make_it_zero(&mut input); - assert_eq!( - xori(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_XORI, - address_a: reg2mem(0), - address_b: 0, - address_c: reg2mem(0) - }] - ); + })] } -fn and(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn and(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_AND, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: reg2mem(instruction.rd), - }] + })] } -#[test] -fn test_and() { - let mut input = tests::INPUT; - - assert_eq!( - and(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_AND, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }] - ); - - tests::make_it_zero(&mut input); - assert_eq!( - and(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_AND, - address_a: reg2mem(0), - address_b: reg2mem(0), - address_c: reg2mem(0) - }] - ); -} - -fn andi(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn andi(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: reg2mem(instruction.rd), - }] + })] } -#[test] -fn test_andi() { - let mut input = tests::INPUT; - assert_eq!( - andi(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ANDI, - address_a: reg2mem(1), - address_b: 4, - address_c: reg2mem(3) - }] - ); - - tests::make_it_zero(&mut input); - assert_eq!( - andi(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ANDI, - address_a: reg2mem(0), - address_b: 0, - address_c: reg2mem(0) - }] - ); -} - -fn or(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn or(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: reg2mem(instruction.rd), - }] -} -#[test] -fn test_or() { - let mut input = tests::INPUT; - - assert_eq!( - or(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_OR, - address_a: reg2mem(1), - address_b: reg2mem(2), - address_c: reg2mem(3) - }] - ); - - tests::make_it_zero(&mut input); - assert_eq!( - or(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_OR, - address_a: reg2mem(0), - address_b: reg2mem(0), - address_c: reg2mem(0) - }] - ); + })] } -fn ori(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn ori(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ORI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: reg2mem(instruction.rd), - }] -} -#[test] -fn test_ori() { - let mut input = tests::INPUT; - - assert_eq!( - ori(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ORI, - address_a: reg2mem(1), - address_b: 4, - address_c: reg2mem(3) - }] - ); - - tests::make_it_zero(&mut input); - assert_eq!( - ori(input, tests::INFO), - vec![bitvm::Instruction { - asm_type: bitvm::ASM_ORI, - address_a: reg2mem(0), - address_b: 0, - address_c: reg2mem(0) - }] - ); + })] } -fn jal(instruction: Instruction, info: BinaryInfo) -> Vec { +fn jal(instruction: Instruction, info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: info.pc as u32 + 4, address_c: reg2mem(instruction.rd), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // TODO: this needs to be relative to pc asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, - }, + }), ] } -fn lbu(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn lbu(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), address_c: reg2mem(instruction.rd), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // just to be sure someone didn't sneak in a uint32 value instead of a bit asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rd), address_b: 0xFF, address_c: reg2mem(instruction.rd), - }, + }), ] } -fn lh(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn lh(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), address_c: reg2mem(instruction.rd), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // just to be sure someone didn't sneak in a uint32 value instead of a bit asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rd), address_b: 0xFF, address_c: reg2mem(instruction.rd), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: tmp(), address_b: 1, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // just to be sure someone didn't sneak in a uint32 value instead of a byte asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0xFF, address_c: tmp2(), - }, + }), ]; for _ in 0..8 { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: tmp2(), address_b: tmp2(), address_c: tmp2(), - }); + })); } - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(instruction.rd), address_b: tmp2(), address_c: reg2mem(instruction.rd), - }); + })); - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rd), address_b: 0x8000, address_c: tmp(), - }); + })); - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: tmp(), address_b: tmp(), address_c: tmp(), - }); + })); - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SUB, address_a: 0, address_b: tmp(), address_c: tmp(), - }); + })); - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(instruction.rd), address_b: tmp(), address_c: reg2mem(instruction.rd), - }); + })); ret } -fn lb(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn lb(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), address_c: reg2mem(instruction.rd), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // Load can return up to 32-bit asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rd), address_b: 0xFF, address_c: reg2mem(instruction.rd), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // get MSB asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rd), address_b: 0x80, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // lshift asm_type: bitvm::ASM_ADD, address_a: tmp(), address_b: tmp(), address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SUB, address_a: 0, address_b: tmp(), address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(instruction.rd), address_b: tmp(), address_c: reg2mem(instruction.rd), - }, + }), ] } -fn lhu(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn lhu(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), address_c: reg2mem(instruction.rd), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // just to be sure someone didn't sneak in a uint32 value instead of a bit asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rd), address_b: 0xFF, address_c: reg2mem(instruction.rd), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: tmp(), address_b: 1, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // just to be sure someone didn't sneak in a uint32 value instead of a byte asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0xFF, address_c: tmp2(), - }, + }), ]; for _ in 0..8 { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: tmp2(), address_b: tmp2(), address_c: tmp2(), - }); + })); } - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(instruction.rd), address_b: tmp2(), address_c: reg2mem(instruction.rd), - }); + })); ret } -fn lw(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn lw(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm + 3, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), address_c: reg2mem(instruction.rd), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // just to be sure someone didn't sneak in a uint32 value instead of a bit asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rd), address_b: 0xFF, address_c: reg2mem(instruction.rd), - }, + }), ]; for _ in 0..3 { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SUBI, address_a: tmp(), address_b: 1, address_c: tmp(), - }); - ret.push(bitvm::Instruction { + })); + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), address_c: tmp2(), - }); - ret.push(bitvm::Instruction { + })); + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { // just to be sure someone didn't sneak in a uint32 value instead of a bit asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0xFF, address_c: tmp2(), - }); + })); for __ in 0..8 { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: tmp2(), address_b: tmp2(), address_c: tmp2(), - }); + })); } - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(instruction.rd), address_b: tmp2(), address_c: reg2mem(instruction.rd), - }); + })); } ret } -fn sb(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn sb(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rs2), address_b: 0, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0xFF, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_STORE, address_a: tmp2(), address_b: tmp(), address_c: 0, - }, + }), ] } -fn sh(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn sh(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // tmp is now rs1 + offset which is the memroy point where we want to store rs2[0:15] asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // Move rs2 to tmp2, now we want to store tmp2 to the memory location in tmp. asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rs2), address_b: 0, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // we get the last 8 bit and store it in tmp2 asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0xFF, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // Finally wrote the last byte, now we have to write rs2[9:15] asm_type: bitvm::ASM_STORE, address_a: tmp2(), address_b: tmp(), address_c: 0, - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // We move 1 byte to write the second half. asm_type: bitvm::ASM_ADDI, address_a: tmp(), address_b: 1, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // rs2 is the value we want to write, moved it to tmp2 asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rs2), address_b: 0, address_c: tmp2(), - }, + }), ]; for _ in 0..8 { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_RSHIFT1, address_a: tmp2(), address_b: tmp2(), address_c: tmp2(), - }); + })); } - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0xFF, address_c: tmp2(), - }); - ret.push(bitvm::Instruction { + })); + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_STORE, address_a: tmp2(), address_b: tmp(), address_c: 0, - }); + })); ret } -fn sw(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn sw(instruction: Instruction, _info: BinaryInfo) -> Vec { let mut ret = vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // Calculate base address and store it in tmp() for memory access asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // Temporarily store rs2 value for manipulation asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rs2), address_b: 0, address_c: tmp2(), - }, + }), ]; for i in 0..4 { // Isolate the current byte from tmp2() and store it - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { // Use a new tmp register if necessary asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0xFF, address_c: tmp3(), - }); - ret.push(bitvm::Instruction { + })); + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_STORE, address_a: tmp3(), address_b: tmp(), address_c: 0, - }); + })); // Prepare for the next byte unless it's the last byte if i < 3 { for _ in 0..8 { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_RSHIFT1, address_a: tmp2(), address_b: tmp2(), address_c: tmp2(), - }); + })); } - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: tmp(), address_b: 1, address_c: tmp(), - }); + })); } } ret } -fn jalr(instruction: Instruction, info: BinaryInfo) -> Vec { +fn jalr(instruction: Instruction, info: BinaryInfo) -> Vec { let mut ret = vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: tmp(), address_b: 0xFFFFFFFE, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_LOAD, address_a: 0, address_b: tmp(), address_c: tmp(), - }, + }), ]; if instruction.rd != 0 { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: info.pc as u32 + 4, address_c: reg2mem(instruction.rd), - }); + })); } - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_JMP, address_a: tmp(), address_b: 0, address_c: 0, - }); + })); ret } -fn auipc(instruction: Instruction, info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn auipc(instruction: Instruction, info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { // imm is already << 12'ed asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: (instruction.imm + info.pc as u32) & 0xFFFFFFFF, address_c: reg2mem(instruction.rd), - }] + })] } /// ISA data-sheet: LUI places the U-immediate value in the top 20 bits of the /// destination register rd, filling in the lowest 12 bits with zeros. /// /// This is provided by decoder as the immediate value. -fn lui(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn lui(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: instruction.imm, address_c: reg2mem(instruction.rd), - }] + })] } /// BitVM compares address_a and address_b for BEQ. If equal, changes PC to /// address_c. Therefore we add immediate value and RISC-V PC for the address_c. -fn beq(instruction: Instruction, info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn beq(instruction: Instruction, info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: info.pc as u32 + instruction.imm, // TODO: check pc relative addressing - }] + })] } /// BNE works same way as the BEQ. -fn bne(instruction: Instruction, info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn bne(instruction: Instruction, info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BNE, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: info.pc as u32 + instruction.imm, // TODO: check pc relative addressing - }] + })] } -fn slli(instruction: Instruction, _info: BinaryInfo) -> Vec { - let mut ret = vec![bitvm::Instruction { +fn slli(instruction: Instruction, _info: BinaryInfo) -> Vec { + let mut ret = vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: 0, address_c: reg2mem(instruction.rd), - }]; + })]; // Calculate the number of times to apply ASM_LSHIFT8 based on the immediate // value. for _ in 0..(instruction.imm / 8) { for __ in 0..8 { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rd), address_b: reg2mem(instruction.rd), address_c: reg2mem(instruction.rd), - }); + })); } } // Calculate any remaining shifts that are less than 8 bits. for _ in 0..(instruction.imm % 8) { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: reg2mem(instruction.rd), address_b: reg2mem(instruction.rd), address_c: reg2mem(instruction.rd), - }); + })); } ret } -fn srli(instruction: Instruction, _info: BinaryInfo) -> Vec { - let mut ret = vec![bitvm::Instruction { +fn srli(instruction: Instruction, _info: BinaryInfo) -> Vec { + let mut ret = vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: 0, address_c: reg2mem(instruction.rd), - }]; + })]; // Calculate the number of times to apply ASM_RSHIFT8 based on the immediate // value. for _ in 0..(instruction.imm / 8) { for __ in 0..8 { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_RSHIFT1, address_a: reg2mem(instruction.rd), address_b: 0, address_c: reg2mem(instruction.rd), - }); + })); } } // Calculate any remaining shifts that are less than 8 bits. for _ in 0..(instruction.imm % 8) { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_RSHIFT1, address_a: reg2mem(instruction.rd), address_b: 0, address_c: reg2mem(instruction.rd), - }); + })); } ret } -fn srai(instruction: Instruction, _info: BinaryInfo) -> Vec { - let mut ret = vec![bitvm::Instruction { +fn srai(instruction: Instruction, _info: BinaryInfo) -> Vec { + let mut ret = vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: 0, address_c: reg2mem(instruction.rd), - }]; + })]; for _ in 0..(instruction.imm) { - ret.push(bitvm::Instruction { + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: reg2mem(instruction.rd), address_b: 0x80000000, address_c: tmp3(), - }); - ret.push(bitvm::Instruction { + })); + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_RSHIFT1, address_a: reg2mem(instruction.rd), address_b: 0, address_c: reg2mem(instruction.rd), - }); - ret.push(bitvm::Instruction { + })); + ret.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_OR, address_a: reg2mem(instruction.rd), address_b: tmp3(), address_c: reg2mem(instruction.rd), - }); + })); } ret } -fn slt(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn slt(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLT, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: reg2mem(instruction.rd), - }] + })] } -fn sltu(instruction: Instruction, _info: BinaryInfo) -> Vec { - vec![bitvm::Instruction { +fn sltu(instruction: Instruction, _info: BinaryInfo) -> Vec { + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLTU, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: reg2mem(instruction.rd), - }] + })] } -fn sltiu(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn sltiu(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLTU, address_a: reg2mem(instruction.rs1), address_b: tmp(), address_c: reg2mem(instruction.rd), - }, + }), ] } -fn slti(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn slti(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: instruction.imm, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLT, address_a: reg2mem(instruction.rs1), address_b: tmp(), address_c: reg2mem(instruction.rd), - }, + }), ] } -fn blt(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn blt(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLT, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BNE, address_a: tmp(), address_b: reg2mem(0), address_c: 0, // TODO: Check pc relative addressing - }, + }), ] } -fn bltu(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn bltu(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLTU, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BNE, address_a: tmp(), address_b: reg2mem(0), address_c: 0, // TODO: Check pc relative addressing - }, + }), ] } -fn bge(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn bge(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLT, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: tmp(), address_b: reg2mem(0), address_c: 0, // TODO: Check pc relative addressing - }, + }), ] } -fn bgeu(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn bgeu(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLTU, address_a: reg2mem(instruction.rs1), address_b: reg2mem(instruction.rs2), address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: tmp(), address_b: reg2mem(0), address_c: 0, - }, + }), ] } -fn ecall(_instruction: Instruction, _info: BinaryInfo) -> Vec { +fn ecall(_instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // tmp() acts as our status buffer: 0 = unknown 1 = OK, 2 = not OK asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: 1, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // if x10 / a0 is 0, finish program asm_type: bitvm::ASM_BEQ, address_a: reg2mem(10), address_b: reg2mem(0), address_c: 0, // TODO: Check label - }, + }), ] } -fn ebreak(_instruction: Instruction, _info: BinaryInfo) -> Vec { +fn ebreak(_instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: 2, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, // TODO: Check label - }, + }), ] } -fn sra(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn sra(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // result asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: 0, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // shift amount asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs2), address_b: 0, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0x1F, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, // TODO: Check label - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: tmp2(), address_c: 0, // TODO: Check label - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: tmp(), address_b: 0x80000000, address_c: tmp3(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_RSHIFT1, address_a: tmp(), address_b: 0, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // add MSB asm_type: bitvm::ASM_OR, address_a: tmp(), address_b: tmp3(), address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SUBI, address_a: tmp2(), address_b: 1, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // TODO: Check label asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // TODO: Check label asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // result asm_type: bitvm::ASM_ADDI, address_a: tmp(), address_b: 0, address_c: reg2mem(instruction.rd), - }, + }), ] } -fn srl(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn srl(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // result asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: 0, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // shift amount asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs2), address_b: 0, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0x1F, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // TODO: Check label asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // TODO: Check label asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: tmp2(), address_c: 0, - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_RSHIFT1, address_a: tmp(), address_b: 0, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SUBI, address_a: tmp2(), address_b: 1, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // TODO: Check label asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // TODO: Check label asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // result asm_type: bitvm::ASM_ADDI, address_a: tmp(), address_b: 0, address_c: reg2mem(instruction.rd), - }, + }), ] } -fn sll(instruction: Instruction, _info: BinaryInfo) -> Vec { +fn sll(instruction: Instruction, _info: BinaryInfo) -> Vec { vec![ - bitvm::Instruction { + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // result asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs1), address_b: 0, address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // shift amount asm_type: bitvm::ASM_ADDI, address_a: reg2mem(instruction.rs2), address_b: 0, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ANDI, address_a: tmp2(), address_b: 0x1F, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, // TODO: Check label - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: tmp2(), address_c: 0, // TODO: Check label - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADD, address_a: tmp(), address_b: tmp(), address_c: tmp(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SUBI, address_a: tmp2(), address_b: 1, address_c: tmp2(), - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_BEQ, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, // TODO: Check label - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_ADDI, address_a: reg2mem(0), address_b: reg2mem(0), address_c: 0, - }, - bitvm::Instruction { + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { // result asm_type: bitvm::ASM_ADDI, address_a: tmp(), address_b: 0, address_c: reg2mem(instruction.rd), - }, + }), ] } -#[cfg(test)] -mod tests { - #![cfg_attr(debug_assertions, allow(dead_code, unused_imports))] - use super::*; - use crate::elf_parser::Isa; - use crate::riscv::{Instruction, RiscvInstructions::*}; - use crate::{bitvm, riscv}; - - // For most of the instructions, this is a good default. - pub const INPUT: Instruction = Instruction { - instr: ADD, - rs1: 1, - rs2: 2, - rd: 3, - imm: 4, - }; - - pub const INFO: BinaryInfo = BinaryInfo { - isa: Isa::Riscv32, - pc: 0, - }; - - /// Update input instruction's values. - pub fn update_instruction(instr: &mut Instruction, rs1: u32, rs2: u32, rd: u32, imm: u32) { - instr.rs1 = rs1; - instr.rs2 = rs2; - instr.rd = rd; - instr.imm = imm; - } - - /// Convert input instruction values to zero. - pub fn make_it_zero(instr: &mut Instruction) { - update_instruction(instr, 0, 0, 0, 0); - } -} +// #[cfg(test)] +// mod tests { +// #![cfg_attr(debug_assertions, allow(dead_code, unused_imports))] +// use super::*; +// use crate::elf_parser::Isa; +// use crate::riscv::{Instruction, RiscvInstructions::*}; +// use crate::{bitvm, riscv}; + +// // For most of the instructions, this is a good default. +// pub const INPUT: Instruction = Instruction { +// instr: ADD, +// rs1: 1, +// rs2: 2, +// rd: 3, +// imm: 4, +// }; + +// pub const INFO: BinaryInfo = BinaryInfo { +// isa: Isa::Riscv32, +// pc: 0, +// }; + +// /// Update input instruction's values. +// pub fn update_instruction(instr: &mut Instruction, rs1: u32, rs2: u32, rd: u32, imm: u32) { +// instr.rs1 = rs1; +// instr.rs2 = rs2; +// instr.rd = rd; +// instr.imm = imm; +// } + +// /// Convert input instruction values to zero. +// pub fn make_it_zero(instr: &mut Instruction) { +// update_instruction(instr, 0, 0, 0, 0); +// } + +// #[test] +// fn test_generate_code() { +// let input_instr = tests::INPUT; + +// // Single add instruction. +// let input = vec![input_instr]; +// assert_eq!( +// generate_code(tests::INFO, input), +// vec![bitvm::UnresolvedInstruction::(Instruction { +// asm_type: bitvm::ASM_ADD, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// })] +// ); + +// let input = vec![input_instr, input_instr]; +// assert_eq!( +// generate_code(tests::INFO, input), +// vec![ +// bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADD, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// }, +// bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADD, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// } +// ] +// ); + +// let input = vec![ +// input_instr, +// Instruction { +// instr: ADDI, +// rs1: 1, +// rs2: 2, +// rd: 3, +// imm: 4, +// }, +// ]; +// assert_eq!( +// generate_code(tests::INFO, input), +// vec![ +// bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADD, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// }, +// bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADDI, +// address_a: reg2mem(1), +// address_b: 4, +// address_c: reg2mem(3) +// } +// ] +// ); + +// let input = vec![ +// input_instr, +// Instruction { +// instr: ADDI, +// rs1: 1, +// rs2: 2, +// rd: 3, +// imm: 4, +// }, +// Instruction { +// instr: SUB, +// rs1: 1, +// rs2: 2, +// rd: 3, +// imm: 4, +// }, +// ]; +// assert_eq!( +// generate_code(tests::INFO, input), +// vec![ +// bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADD, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// }, +// bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADDI, +// address_a: reg2mem(1), +// address_b: 4, +// address_c: reg2mem(3) +// }, +// bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_SUB, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// } +// ] +// ); + +// // Test whether big number of instructions are a problem or not. +// // WARNING: This will take a long time to finish and use so much memory. +// let mut input: Vec = Vec::new(); +// let mut expected: Vec = Vec::new(); +// let count = 5_000_000; +// for _ in 0..count { +// input.push(input_instr); +// } +// for _ in 0..count { +// expected.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADD, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3), +// }); +// } +// assert_eq!(generate_code(tests::INFO, input), expected); +// } + +// #[test] +// fn test_add() { +// let mut input = tests::INPUT; + +// assert_eq!( +// add(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADD, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// })] +// ); + +// tests::make_it_zero(&mut input); +// assert_eq!( +// add(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADD, +// address_a: reg2mem(0), +// address_b: reg2mem(0), +// address_c: reg2mem(0) +// })] +// ); +// } + +// #[test] +// fn test_addi() { +// let mut input = tests::INPUT; + +// assert_eq!( +// addi(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADDI, +// address_a: reg2mem(1), +// address_b: 4, +// address_c: reg2mem(3) +// })] +// ); + +// tests::make_it_zero(&mut input); +// assert_eq!( +// addi(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ADDI, +// address_a: reg2mem(0), +// address_b: 0, +// address_c: reg2mem(0) +// })] +// ); +// } + +// #[test] +// fn test_sub() { +// let mut input = tests::INPUT; + +// assert_eq!( +// sub(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_SUB, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// })] +// ); + +// tests::make_it_zero(&mut input); +// assert_eq!( +// sub(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_SUB, +// address_a: reg2mem(0), +// address_b: reg2mem(0), +// address_c: reg2mem(0) +// })] +// ); +// } + +// #[test] +// fn test_xor() { +// let mut input = tests::INPUT; + +// assert_eq!( +// xor(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_XOR, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// })] +// ); + +// tests::make_it_zero(&mut input); +// assert_eq!( +// xor(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_XOR, +// address_a: reg2mem(0), +// address_b: reg2mem(0), +// address_c: reg2mem(0) +// })] +// ); +// } + +// #[test] +// fn test_xori() { +// let mut input = tests::INPUT; + +// assert_eq!( +// xori(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_XORI, +// address_a: reg2mem(1), +// address_b: 4, +// address_c: reg2mem(3) +// })] +// ); + +// tests::make_it_zero(&mut input); +// assert_eq!( +// xori(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_XORI, +// address_a: reg2mem(0), +// address_b: 0, +// address_c: reg2mem(0) +// })] +// ); +// } + +// #[test] +// fn test_andi() { +// let mut input = tests::INPUT; + +// assert_eq!( +// andi(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ANDI, +// address_a: reg2mem(1), +// address_b: 4, +// address_c: reg2mem(3) +// })] +// ); + +// tests::make_it_zero(&mut input); +// assert_eq!( +// andi(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ANDI, +// address_a: reg2mem(0), +// address_b: 0, +// address_c: reg2mem(0) +// })] +// ); +// } + +// #[test] +// fn test_or() { +// let mut input = tests::INPUT; + +// assert_eq!( +// or(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_OR, +// address_a: reg2mem(1), +// address_b: reg2mem(2), +// address_c: reg2mem(3) +// })] +// ); + +// tests::make_it_zero(&mut input); +// assert_eq!( +// or(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_OR, +// address_a: reg2mem(0), +// address_b: reg2mem(0), +// address_c: reg2mem(0) +// })] +// ); +// } + +// #[test] +// fn test_ori() { +// let mut input = tests::INPUT; + +// assert_eq!( +// ori(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ORI, +// address_a: reg2mem(1), +// address_b: 4, +// address_c: reg2mem(3) +// })] +// ); + +// tests::make_it_zero(&mut input); +// assert_eq!( +// ori(input, tests::INFO), +// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { +// asm_type: bitvm::ASM_ORI, +// address_a: reg2mem(0), +// address_b: 0, +// address_c: reg2mem(0) +// })] +// ); +// } + +// } From 4e04be9177cf229d4c83a44263b82b2466290c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Fri, 5 Apr 2024 10:52:47 +0300 Subject: [PATCH 17/26] resolver: Add initial resolver. --- bitvm-transpiler/src/bitvm.rs | 16 +++++++------ bitvm-transpiler/src/resolver.rs | 30 +++++++++++++++++++++---- bitvm-transpiler/src/riscv/generator.rs | 12 +++++++++- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/bitvm-transpiler/src/bitvm.rs b/bitvm-transpiler/src/bitvm.rs index e4ec1dd..3c57300 100644 --- a/bitvm-transpiler/src/bitvm.rs +++ b/bitvm-transpiler/src/bitvm.rs @@ -51,6 +51,7 @@ pub struct Instruction { /// Possible labels for a RISC-V instruction. #[derive(Debug, Clone, Copy)] pub enum Labels { + None, /// Represents program counter of the real RISC-V instruction. Pc(u64), /// Represents real program end. @@ -62,12 +63,13 @@ pub enum Labels { #[derive(Debug, Clone, Copy)] pub struct UnresolvedInstruction { pub instr: Instruction, + /// Real program counter in the actual binary. + pub real_pc: u64, /// After code generation, this will be updated. pub bitvm_pc: u64, - /// Metadata for resolver. + /// Metadata for resolver. If set other than Labels::None, it will be + /// resolved by the resolver. pub label: Labels, - /// If set, address_c will be resolved to label. - pub needs_resolving: bool, } impl UnresolvedInstruction { @@ -80,9 +82,9 @@ impl UnresolvedInstruction { address_b: 0, address_c: 0, }, + real_pc: 0, bitvm_pc: 0, - label: Labels::Pc(0), - needs_resolving: false, + label: Labels::None, } } @@ -90,9 +92,9 @@ impl UnresolvedInstruction { pub fn from(instr: Instruction) -> Self { Self { instr: instr, + real_pc: 0, bitvm_pc: 0, - label: Labels::Pc(0), - needs_resolving: false, + label: Labels::None, } } diff --git a/bitvm-transpiler/src/resolver.rs b/bitvm-transpiler/src/resolver.rs index 8006fbe..8085e02 100644 --- a/bitvm-transpiler/src/resolver.rs +++ b/bitvm-transpiler/src/resolver.rs @@ -18,13 +18,35 @@ //! code. This operation is not ISA specific. use crate::bitvm; +use crate::bitvm::Labels; pub fn resolve(instructions: Vec) -> Vec { let mut resolved = Vec::new(); - for i in instructions { - resolved.push(i.instr); - } + for mut i in instructions.clone() { + match i.label { + // This instruction does not need any afterwork. + Labels::None => (), + // This instruction needs a new PC assignment. + Labels::Pc(pc) => { + for j in instructions.clone() { + if j.real_pc == pc { + // We need to convert real pc to bitvm counterpart. + i.instr.address_c = j.bitvm_pc as u32; + break; + } else if j.real_pc > pc { + // No need to keep looking: PC will only go upwards. + break; + } + // TODO: If this loop can't find what it's looking for, it + // will silently skip. Is it safe? + } + } + _ => (), + } - resolved + resolved.push(i.instr); + } + + resolved } diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index df5a1a6..45505dd 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -95,13 +95,23 @@ pub fn generate_code( _ => panic!("Illegal instruction: {:#?}", i.instr), }; - for j in instr { + // Assign actual RISC-V PC to every instruction. This can help resolver + // to determine new jump location. Also, add instructions one by one to + // return value. + for mut j in instr { + j.real_pc = info.pc; bitvm_instructions.push(j); } + // Iterate RISc-V PC. info.pc += 1; } + // Assign BitVM program counters. + for i in 0..bitvm_instructions.len() { + bitvm_instructions[i].bitvm_pc = i as u64; + } + bitvm_instructions } From 2c8f4ba7952aae3cf8973594561624ce80ebc0a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Fri, 5 Apr 2024 10:55:31 +0300 Subject: [PATCH 18/26] comments: Update program flow. --- bitvm-transpiler/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bitvm-transpiler/src/main.rs b/bitvm-transpiler/src/main.rs index 3e0aa5e..9acb792 100644 --- a/bitvm-transpiler/src/main.rs +++ b/bitvm-transpiler/src/main.rs @@ -24,7 +24,9 @@ //! 1. Parse CLI flags and options //! 2. Read input binary file and get instructions //! 3. Run ISA specific decoder -//! 4. Run ISA specific BitVM assembler +//! 4. Run ISA specific BitVM code generator +//! 5. Run resolver to resolve addresses that can't be determined while +//! generating code //! 5. Organize memory //! 6. Write BitVM assembly and memory to a file From a3a10b6628c955551b40a7de08c18496e5b98a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Fri, 5 Apr 2024 12:57:29 +0300 Subject: [PATCH 19/26] riscv_code_generator: Add labels to relative jumps. --- bitvm-transpiler/src/bitvm.rs | 12 +- bitvm-transpiler/src/riscv/generator.rs | 324 ++++++++++++++---------- 2 files changed, 191 insertions(+), 145 deletions(-) diff --git a/bitvm-transpiler/src/bitvm.rs b/bitvm-transpiler/src/bitvm.rs index 3c57300..215b6b7 100644 --- a/bitvm-transpiler/src/bitvm.rs +++ b/bitvm-transpiler/src/bitvm.rs @@ -54,8 +54,10 @@ pub enum Labels { None, /// Represents program counter of the real RISC-V instruction. Pc(u64), - /// Represents real program end. - _ProgramEnd, + /// Jump to an address relative to current pc. This can help creating loops. + Relative(i64), + /// Can be used to exit program early. + ProgramEnd, } /// This struct will be used by the resolver to generate final BitVM assembly @@ -63,13 +65,13 @@ pub enum Labels { #[derive(Debug, Clone, Copy)] pub struct UnresolvedInstruction { pub instr: Instruction, + /// Metadata for resolver. If set other than Labels::None, it will be + /// resolved by the resolver. + pub label: Labels, /// Real program counter in the actual binary. pub real_pc: u64, /// After code generation, this will be updated. pub bitvm_pc: u64, - /// Metadata for resolver. If set other than Labels::None, it will be - /// resolved by the resolver. - pub label: Labels, } impl UnresolvedInstruction { diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 45505dd..decfc94 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -203,13 +203,17 @@ fn jal(instruction: Instruction, info: BinaryInfo) -> Vec Vec Vec { - vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - asm_type: bitvm::ASM_BEQ, - address_a: reg2mem(instruction.rs1), - address_b: reg2mem(instruction.rs2), - address_c: info.pc as u32 + instruction.imm, // TODO: check pc relative addressing - })] + vec![bitvm::UnresolvedInstruction { + instr: bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: 0, + }, + label: bitvm::Labels::Pc(info.pc as u64 + instruction.imm as u64), + real_pc: 0, // This will be overridden later. + bitvm_pc: 0, // This will be overridden later. + }] } /// BNE works same way as the BEQ. fn bne(instruction: Instruction, info: BinaryInfo) -> Vec { - vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - asm_type: bitvm::ASM_BNE, - address_a: reg2mem(instruction.rs1), - address_b: reg2mem(instruction.rs2), - address_c: info.pc as u32 + instruction.imm, // TODO: check pc relative addressing - })] + vec![bitvm::UnresolvedInstruction { + instr: bitvm::Instruction { + asm_type: bitvm::ASM_BNE, + address_a: reg2mem(instruction.rs1), + address_b: reg2mem(instruction.rs2), + address_c: 0, + }, + label: bitvm::Labels::Pc(info.pc as u64 + instruction.imm as u64), + real_pc: 0, // This will be overridden later. + bitvm_pc: 0, // This will be overridden later. + }] } fn slli(instruction: Instruction, _info: BinaryInfo) -> Vec { @@ -891,7 +905,7 @@ fn slti(instruction: Instruction, _info: BinaryInfo) -> Vec Vec { +fn blt(instruction: Instruction, info: BinaryInfo) -> Vec { vec![ bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLT, @@ -899,16 +913,21 @@ fn blt(instruction: Instruction, _info: BinaryInfo) -> Vec Vec { +fn bltu(instruction: Instruction, info: BinaryInfo) -> Vec { vec![ bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLTU, @@ -916,16 +935,21 @@ fn bltu(instruction: Instruction, _info: BinaryInfo) -> Vec Vec { +fn bge(instruction: Instruction, info: BinaryInfo) -> Vec { vec![ bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLT, @@ -933,16 +957,21 @@ fn bge(instruction: Instruction, _info: BinaryInfo) -> Vec Vec { +fn bgeu(instruction: Instruction, info: BinaryInfo) -> Vec { vec![ bitvm::UnresolvedInstruction::from(bitvm::Instruction { asm_type: bitvm::ASM_SLTU, @@ -950,12 +979,17 @@ fn bgeu(instruction: Instruction, _info: BinaryInfo) -> Vec Vec Vec Vec Vec Vec Vec Vec Vec Date: Fri, 5 Apr 2024 14:26:53 +0300 Subject: [PATCH 20/26] resolver: Add program end label resolver. --- bitvm-transpiler/src/resolver.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bitvm-transpiler/src/resolver.rs b/bitvm-transpiler/src/resolver.rs index 8085e02..b9d29b4 100644 --- a/bitvm-transpiler/src/resolver.rs +++ b/bitvm-transpiler/src/resolver.rs @@ -22,6 +22,7 @@ use crate::bitvm::Labels; pub fn resolve(instructions: Vec) -> Vec { let mut resolved = Vec::new(); + let program_end = instructions.len() - 1; for mut i in instructions.clone() { match i.label { @@ -42,6 +43,9 @@ pub fn resolve(instructions: Vec) -> Vec { + i.instr.address_c = program_end as u32; + } _ => (), } From 633d8b179bde162374826e29930c8af9f02a0818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Fri, 5 Apr 2024 18:17:52 +0300 Subject: [PATCH 21/26] riscv_decoder: Add add* tests. --- bitvm-transpiler/src/riscv/decoder.rs | 112 ++++++++++++++++++++++++++ bitvm-transpiler/src/riscv/mod.rs | 4 +- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/bitvm-transpiler/src/riscv/decoder.rs b/bitvm-transpiler/src/riscv/decoder.rs index 7cfe108..0d4fdb2 100644 --- a/bitvm-transpiler/src/riscv/decoder.rs +++ b/bitvm-transpiler/src/riscv/decoder.rs @@ -360,3 +360,115 @@ fn decode_raw_instruction(raw_instruction: u32) -> Result { imm, }) } + +/// These tests currently does not covers all of the instructions. I just chose +/// some random instructions and called it a day. In the future, we can add full +/// coverage if needed. +#[cfg(test)] +mod tests { + use super::*; + use crate::riscv::{Instruction, RiscvInstructions::*}; + + #[test] + fn add() { + // add x10, x2, x5 + let raw: u32 = 0x00510533; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!( + result, + Instruction { + instr: ADD, + rs1: 2, + rs2: 5, + rd: 10, + imm: 0, + } + ); + + // add x31 x1 x21 + let raw: u32 = 0x01508fb3; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!( + result, + Instruction { + instr: ADD, + rs1: 1, + rs2: 21, + rd: 31, + imm: 0, + } + ); + + // add x31 x1 x21 + let raw: u32 = 0x01508fb3; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!( + result, + Instruction { + instr: ADD, + rs1: 1, + rs2: 21, + rd: 31, + imm: 0, + } + ); + + // addi x31 x1 21 + let raw: u32 = 0x01508f93; + let result = decode_raw_instruction(raw).unwrap(); + assert_ne!( + result, + Instruction { + instr: ADD, + rs1: 1, + rs2: 21, + rd: 31, + imm: 0, + } + ); + } + + #[test] + fn addi() { + // addi x11 x1 21 + let raw: u32 = 0x01508593; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!(result.instr, ADDI); + assert_eq!(result.rs1, 1); + assert_eq!(result.rd, 11); + assert_eq!(result.imm, 21); + + // addi x31 x30 0 + let raw: u32 = 0x000f0f93; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!(result.instr, ADDI); + assert_eq!(result.rs1, 30); + assert_eq!(result.rd, 31); + assert_eq!(result.imm, 0); + + // addi x14 x30 345 + let raw: u32 = 0x159f0713; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!(result.instr, ADDI); + assert_eq!(result.rs1, 30); + assert_eq!(result.rd, 14); + assert_eq!(result.imm, 345); + + // addi x14 x15 9999999 -> addi x14 x15 1663 + let raw: u32 = 0x67f78713; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!(result.instr, ADDI); + assert_eq!(result.rs1, 15); + assert_eq!(result.rd, 14); + assert_ne!(result.imm, 9999999); + assert_eq!(result.imm, 1663); + + // add x31 x1 x21 + let raw: u32 = 0x01508fb3; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!(result.instr, ADD); + assert_eq!(result.rs1, 1); + assert_eq!(result.rs2, 21); + assert_eq!(result.rd, 31); + } +} diff --git a/bitvm-transpiler/src/riscv/mod.rs b/bitvm-transpiler/src/riscv/mod.rs index 2d5fdbe..34e8652 100644 --- a/bitvm-transpiler/src/riscv/mod.rs +++ b/bitvm-transpiler/src/riscv/mod.rs @@ -32,7 +32,7 @@ pub use decoder::decode; pub use generator::generate_code; /// A decoded RISC-V instruction, ready for the use of RISC-V BitVM assembler. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Instruction { pub instr: RiscvInstructions, pub rs1: u32, @@ -43,7 +43,7 @@ pub struct Instruction { /// Instruction list for RISC-V targets. #[allow(dead_code)] -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum RiscvInstructions { NONE, // RV32I/RV64I From 7872076f96dcb025375cdaba7fe1f3a714c8a230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Mon, 8 Apr 2024 10:30:36 +0300 Subject: [PATCH 22/26] riscv_decoder: Add beq and jal tests. --- bitvm-transpiler/src/riscv/decoder.rs | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/bitvm-transpiler/src/riscv/decoder.rs b/bitvm-transpiler/src/riscv/decoder.rs index 0d4fdb2..5d49e81 100644 --- a/bitvm-transpiler/src/riscv/decoder.rs +++ b/bitvm-transpiler/src/riscv/decoder.rs @@ -471,4 +471,40 @@ mod tests { assert_eq!(result.rs2, 21); assert_eq!(result.rd, 31); } + + #[test] + fn beq() { + // beq x23 x13 132 + let raw: u32 = 0x08db8263; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!(result.instr, BEQ); + assert_eq!(result.rs1, 23); + assert_eq!(result.rs2, 13); + assert_eq!(result.imm, 132); + + // beq x3 x4 1324 + let raw: u32 = 0x52418663; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!(result.instr, BEQ); + assert_eq!(result.rs1, 3); + assert_eq!(result.rs2, 4); + assert_eq!(result.imm, 1324); + } + + #[test] + fn jal() { + // jal x11 1324 + let raw: u32 = 0x52c005ef; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!(result.instr, JAL); + assert_eq!(result.rd, 11); + assert_eq!(result.imm, 1324); + + // jal x3 9998 + let raw: u32 = 0x70e021ef; + let result = decode_raw_instruction(raw).unwrap(); + assert_eq!(result.instr, JAL); + assert_eq!(result.rd, 3); + assert_eq!(result.imm, 9998); + } } From ff4978602c743834badad170c3650e7e70414437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Tue, 9 Apr 2024 12:35:19 +0300 Subject: [PATCH 23/26] riscv_code_generator: Add tests again. --- bitvm-transpiler/src/bitvm.rs | 4 +- bitvm-transpiler/src/riscv/generator.rs | 758 ++++++++++++------------ 2 files changed, 393 insertions(+), 369 deletions(-) diff --git a/bitvm-transpiler/src/bitvm.rs b/bitvm-transpiler/src/bitvm.rs index 215b6b7..69f1217 100644 --- a/bitvm-transpiler/src/bitvm.rs +++ b/bitvm-transpiler/src/bitvm.rs @@ -49,7 +49,7 @@ pub struct Instruction { } /// Possible labels for a RISC-V instruction. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum Labels { None, /// Represents program counter of the real RISC-V instruction. @@ -62,7 +62,7 @@ pub enum Labels { /// This struct will be used by the resolver to generate final BitVM assembly /// instructions. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct UnresolvedInstruction { pub instr: Instruction, /// Metadata for resolver. If set other than Labels::None, it will be diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index decfc94..3fb801f 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -1262,370 +1262,394 @@ fn sll(instruction: Instruction, _info: BinaryInfo) -> Vec = Vec::new(); -// let mut expected: Vec = Vec::new(); -// let count = 5_000_000; -// for _ in 0..count { -// input.push(input_instr); -// } -// for _ in 0..count { -// expected.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_ADD, -// address_a: reg2mem(1), -// address_b: reg2mem(2), -// address_c: reg2mem(3), -// }); -// } -// assert_eq!(generate_code(tests::INFO, input), expected); -// } - -// #[test] -// fn test_add() { -// let mut input = tests::INPUT; - -// assert_eq!( -// add(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_ADD, -// address_a: reg2mem(1), -// address_b: reg2mem(2), -// address_c: reg2mem(3) -// })] -// ); - -// tests::make_it_zero(&mut input); -// assert_eq!( -// add(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_ADD, -// address_a: reg2mem(0), -// address_b: reg2mem(0), -// address_c: reg2mem(0) -// })] -// ); -// } - -// #[test] -// fn test_addi() { -// let mut input = tests::INPUT; - -// assert_eq!( -// addi(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_ADDI, -// address_a: reg2mem(1), -// address_b: 4, -// address_c: reg2mem(3) -// })] -// ); - -// tests::make_it_zero(&mut input); -// assert_eq!( -// addi(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_ADDI, -// address_a: reg2mem(0), -// address_b: 0, -// address_c: reg2mem(0) -// })] -// ); -// } - -// #[test] -// fn test_sub() { -// let mut input = tests::INPUT; - -// assert_eq!( -// sub(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_SUB, -// address_a: reg2mem(1), -// address_b: reg2mem(2), -// address_c: reg2mem(3) -// })] -// ); - -// tests::make_it_zero(&mut input); -// assert_eq!( -// sub(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_SUB, -// address_a: reg2mem(0), -// address_b: reg2mem(0), -// address_c: reg2mem(0) -// })] -// ); -// } - -// #[test] -// fn test_xor() { -// let mut input = tests::INPUT; - -// assert_eq!( -// xor(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_XOR, -// address_a: reg2mem(1), -// address_b: reg2mem(2), -// address_c: reg2mem(3) -// })] -// ); - -// tests::make_it_zero(&mut input); -// assert_eq!( -// xor(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_XOR, -// address_a: reg2mem(0), -// address_b: reg2mem(0), -// address_c: reg2mem(0) -// })] -// ); -// } - -// #[test] -// fn test_xori() { -// let mut input = tests::INPUT; - -// assert_eq!( -// xori(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_XORI, -// address_a: reg2mem(1), -// address_b: 4, -// address_c: reg2mem(3) -// })] -// ); - -// tests::make_it_zero(&mut input); -// assert_eq!( -// xori(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_XORI, -// address_a: reg2mem(0), -// address_b: 0, -// address_c: reg2mem(0) -// })] -// ); -// } - -// #[test] -// fn test_andi() { -// let mut input = tests::INPUT; - -// assert_eq!( -// andi(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_ANDI, -// address_a: reg2mem(1), -// address_b: 4, -// address_c: reg2mem(3) -// })] -// ); - -// tests::make_it_zero(&mut input); -// assert_eq!( -// andi(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_ANDI, -// address_a: reg2mem(0), -// address_b: 0, -// address_c: reg2mem(0) -// })] -// ); -// } - -// #[test] -// fn test_or() { -// let mut input = tests::INPUT; - -// assert_eq!( -// or(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_OR, -// address_a: reg2mem(1), -// address_b: reg2mem(2), -// address_c: reg2mem(3) -// })] -// ); - -// tests::make_it_zero(&mut input); -// assert_eq!( -// or(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_OR, -// address_a: reg2mem(0), -// address_b: reg2mem(0), -// address_c: reg2mem(0) -// })] -// ); -// } - -// #[test] -// fn test_ori() { -// let mut input = tests::INPUT; - -// assert_eq!( -// ori(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_ORI, -// address_a: reg2mem(1), -// address_b: 4, -// address_c: reg2mem(3) -// })] -// ); - -// tests::make_it_zero(&mut input); -// assert_eq!( -// ori(input, tests::INFO), -// vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { -// asm_type: bitvm::ASM_ORI, -// address_a: reg2mem(0), -// address_b: 0, -// address_c: reg2mem(0) -// })] -// ); -// } - -// } +#[cfg(test)] +mod tests { + #![cfg_attr(debug_assertions, allow(dead_code, unused_imports))] + use super::*; + use crate::elf_parser::Isa; + use crate::riscv::{Instruction, RiscvInstructions::*}; + use crate::{bitvm, riscv}; + + // For most of the instructions, this is a good default. + pub const INPUT: Instruction = Instruction { + instr: ADD, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }; + + pub const INFO: BinaryInfo = BinaryInfo { + isa: Isa::Riscv32, + pc: 0, + }; + + /// Update input instruction's values. + pub fn update_instruction(instr: &mut Instruction, rs1: u32, rs2: u32, rd: u32, imm: u32) { + instr.rs1 = rs1; + instr.rs2 = rs2; + instr.rd = rd; + instr.imm = imm; + } + + /// Convert input instruction values to zero. + pub fn make_it_zero(instr: &mut Instruction) { + update_instruction(instr, 0, 0, 0, 0); + } + + #[test] + fn test_generate_code() { + let input_instr = tests::INPUT; + + // Single add instruction. + let input = vec![input_instr]; + assert_eq!( + generate_code(tests::INFO, input), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + })] + ); + + let input = vec![input_instr, input_instr]; + assert_eq!( + generate_code(tests::INFO, input), + vec![ + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }), + bitvm::UnresolvedInstruction { + instr: bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }, + label: bitvm::Labels::None, + real_pc: 1, + bitvm_pc: 1, + } + ] + ); + + let input = vec![ + input_instr, + Instruction { + instr: ADDI, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }, + ]; + assert_eq!( + generate_code(tests::INFO, input), + vec![ + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }), + bitvm::UnresolvedInstruction { + instr: bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + }, + label: bitvm::Labels::None, + real_pc: 1, + bitvm_pc: 1, + } + ] + ); + + let input = vec![ + input_instr, + Instruction { + instr: ADDI, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }, + Instruction { + instr: SUB, + rs1: 1, + rs2: 2, + rd: 3, + imm: 4, + }, + ]; + assert_eq!( + generate_code(tests::INFO, input), + vec![ + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }), + bitvm::UnresolvedInstruction { + instr: bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + }, + label: bitvm::Labels::None, + real_pc: 1, + bitvm_pc: 1, + }, + bitvm::UnresolvedInstruction { + instr: bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + }, + label: bitvm::Labels::None, + real_pc: 2, + bitvm_pc: 2, + } + ] + ); + + // Test whether big number of instructions are a problem or not. + // WARNING: This will take a long time to finish and use so much memory. + let mut input: Vec = Vec::new(); + let mut expected: Vec = Vec::new(); + let count = 5_000_000; + for _ in 0..count { + input.push(input_instr); + } + for i in 0..count { + expected.push(bitvm::UnresolvedInstruction { + instr: bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3), + }, + label: bitvm::Labels::None, + real_pc: i, + bitvm_pc: i, + }); + } + assert_eq!(generate_code(tests::INFO, input), expected); + } + + // #[test] + // fn test_add() { + // let mut input = tests::INPUT; + + // assert_eq!( + // add(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_ADD, + // address_a: reg2mem(1), + // address_b: reg2mem(2), + // address_c: reg2mem(3) + // })] + // ); + + // tests::make_it_zero(&mut input); + // assert_eq!( + // add(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_ADD, + // address_a: reg2mem(0), + // address_b: reg2mem(0), + // address_c: reg2mem(0) + // })] + // ); + // } + + // #[test] + // fn test_addi() { + // let mut input = tests::INPUT; + + // assert_eq!( + // addi(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_ADDI, + // address_a: reg2mem(1), + // address_b: 4, + // address_c: reg2mem(3) + // })] + // ); + + // tests::make_it_zero(&mut input); + // assert_eq!( + // addi(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_ADDI, + // address_a: reg2mem(0), + // address_b: 0, + // address_c: reg2mem(0) + // })] + // ); + // } + + // #[test] + // fn test_sub() { + // let mut input = tests::INPUT; + + // assert_eq!( + // sub(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_SUB, + // address_a: reg2mem(1), + // address_b: reg2mem(2), + // address_c: reg2mem(3) + // })] + // ); + + // tests::make_it_zero(&mut input); + // assert_eq!( + // sub(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_SUB, + // address_a: reg2mem(0), + // address_b: reg2mem(0), + // address_c: reg2mem(0) + // })] + // ); + // } + + // #[test] + // fn test_xor() { + // let mut input = tests::INPUT; + + // assert_eq!( + // xor(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_XOR, + // address_a: reg2mem(1), + // address_b: reg2mem(2), + // address_c: reg2mem(3) + // })] + // ); + + // tests::make_it_zero(&mut input); + // assert_eq!( + // xor(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_XOR, + // address_a: reg2mem(0), + // address_b: reg2mem(0), + // address_c: reg2mem(0) + // })] + // ); + // } + + // #[test] + // fn test_xori() { + // let mut input = tests::INPUT; + + // assert_eq!( + // xori(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_XORI, + // address_a: reg2mem(1), + // address_b: 4, + // address_c: reg2mem(3) + // })] + // ); + + // tests::make_it_zero(&mut input); + // assert_eq!( + // xori(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_XORI, + // address_a: reg2mem(0), + // address_b: 0, + // address_c: reg2mem(0) + // })] + // ); + // } + + // #[test] + // fn test_andi() { + // let mut input = tests::INPUT; + + // assert_eq!( + // andi(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_ANDI, + // address_a: reg2mem(1), + // address_b: 4, + // address_c: reg2mem(3) + // })] + // ); + + // tests::make_it_zero(&mut input); + // assert_eq!( + // andi(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_ANDI, + // address_a: reg2mem(0), + // address_b: 0, + // address_c: reg2mem(0) + // })] + // ); + // } + + // #[test] + // fn test_or() { + // let mut input = tests::INPUT; + + // assert_eq!( + // or(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_OR, + // address_a: reg2mem(1), + // address_b: reg2mem(2), + // address_c: reg2mem(3) + // })] + // ); + + // tests::make_it_zero(&mut input); + // assert_eq!( + // or(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_OR, + // address_a: reg2mem(0), + // address_b: reg2mem(0), + // address_c: reg2mem(0) + // })] + // ); + // } + + // #[test] + // fn test_ori() { + // let mut input = tests::INPUT; + + // assert_eq!( + // ori(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_ORI, + // address_a: reg2mem(1), + // address_b: 4, + // address_c: reg2mem(3) + // })] + // ); + + // tests::make_it_zero(&mut input); + // assert_eq!( + // ori(input, tests::INFO), + // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + // asm_type: bitvm::ASM_ORI, + // address_a: reg2mem(0), + // address_b: 0, + // address_c: reg2mem(0) + // })] + // ); + // } +} From a547190d3b707168816b21891658339de6d90a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Tue, 9 Apr 2024 12:36:43 +0300 Subject: [PATCH 24/26] riscv_code_generator: Uncomment rest of the tests. --- bitvm-transpiler/src/riscv/generator.rs | 414 ++++++++++++------------ 1 file changed, 207 insertions(+), 207 deletions(-) diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 3fb801f..be03b1d 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -1445,211 +1445,211 @@ mod tests { assert_eq!(generate_code(tests::INFO, input), expected); } - // #[test] - // fn test_add() { - // let mut input = tests::INPUT; - - // assert_eq!( - // add(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_ADD, - // address_a: reg2mem(1), - // address_b: reg2mem(2), - // address_c: reg2mem(3) - // })] - // ); - - // tests::make_it_zero(&mut input); - // assert_eq!( - // add(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_ADD, - // address_a: reg2mem(0), - // address_b: reg2mem(0), - // address_c: reg2mem(0) - // })] - // ); - // } - - // #[test] - // fn test_addi() { - // let mut input = tests::INPUT; - - // assert_eq!( - // addi(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_ADDI, - // address_a: reg2mem(1), - // address_b: 4, - // address_c: reg2mem(3) - // })] - // ); - - // tests::make_it_zero(&mut input); - // assert_eq!( - // addi(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_ADDI, - // address_a: reg2mem(0), - // address_b: 0, - // address_c: reg2mem(0) - // })] - // ); - // } - - // #[test] - // fn test_sub() { - // let mut input = tests::INPUT; - - // assert_eq!( - // sub(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_SUB, - // address_a: reg2mem(1), - // address_b: reg2mem(2), - // address_c: reg2mem(3) - // })] - // ); - - // tests::make_it_zero(&mut input); - // assert_eq!( - // sub(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_SUB, - // address_a: reg2mem(0), - // address_b: reg2mem(0), - // address_c: reg2mem(0) - // })] - // ); - // } - - // #[test] - // fn test_xor() { - // let mut input = tests::INPUT; - - // assert_eq!( - // xor(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_XOR, - // address_a: reg2mem(1), - // address_b: reg2mem(2), - // address_c: reg2mem(3) - // })] - // ); - - // tests::make_it_zero(&mut input); - // assert_eq!( - // xor(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_XOR, - // address_a: reg2mem(0), - // address_b: reg2mem(0), - // address_c: reg2mem(0) - // })] - // ); - // } - - // #[test] - // fn test_xori() { - // let mut input = tests::INPUT; - - // assert_eq!( - // xori(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_XORI, - // address_a: reg2mem(1), - // address_b: 4, - // address_c: reg2mem(3) - // })] - // ); - - // tests::make_it_zero(&mut input); - // assert_eq!( - // xori(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_XORI, - // address_a: reg2mem(0), - // address_b: 0, - // address_c: reg2mem(0) - // })] - // ); - // } - - // #[test] - // fn test_andi() { - // let mut input = tests::INPUT; - - // assert_eq!( - // andi(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_ANDI, - // address_a: reg2mem(1), - // address_b: 4, - // address_c: reg2mem(3) - // })] - // ); - - // tests::make_it_zero(&mut input); - // assert_eq!( - // andi(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_ANDI, - // address_a: reg2mem(0), - // address_b: 0, - // address_c: reg2mem(0) - // })] - // ); - // } - - // #[test] - // fn test_or() { - // let mut input = tests::INPUT; - - // assert_eq!( - // or(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_OR, - // address_a: reg2mem(1), - // address_b: reg2mem(2), - // address_c: reg2mem(3) - // })] - // ); - - // tests::make_it_zero(&mut input); - // assert_eq!( - // or(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_OR, - // address_a: reg2mem(0), - // address_b: reg2mem(0), - // address_c: reg2mem(0) - // })] - // ); - // } - - // #[test] - // fn test_ori() { - // let mut input = tests::INPUT; - - // assert_eq!( - // ori(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_ORI, - // address_a: reg2mem(1), - // address_b: 4, - // address_c: reg2mem(3) - // })] - // ); - - // tests::make_it_zero(&mut input); - // assert_eq!( - // ori(input, tests::INFO), - // vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { - // asm_type: bitvm::ASM_ORI, - // address_a: reg2mem(0), - // address_b: 0, - // address_c: reg2mem(0) - // })] - // ); - // } + #[test] + fn test_add() { + let mut input = tests::INPUT; + + assert_eq!( + add(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + })] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + add(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + })] + ); + } + + #[test] + fn test_addi() { + let mut input = tests::INPUT; + + assert_eq!( + addi(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + })] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + addi(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 0, + address_c: reg2mem(0) + })] + ); + } + + #[test] + fn test_sub() { + let mut input = tests::INPUT; + + assert_eq!( + sub(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + })] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + sub(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + })] + ); + } + + #[test] + fn test_xor() { + let mut input = tests::INPUT; + + assert_eq!( + xor(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_XOR, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + })] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + xor(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_XOR, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + })] + ); + } + + #[test] + fn test_xori() { + let mut input = tests::INPUT; + + assert_eq!( + xori(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_XORI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + })] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + xori(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_XORI, + address_a: reg2mem(0), + address_b: 0, + address_c: reg2mem(0) + })] + ); + } + + #[test] + fn test_andi() { + let mut input = tests::INPUT; + + assert_eq!( + andi(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + })] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + andi(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(0), + address_b: 0, + address_c: reg2mem(0) + })] + ); + } + + #[test] + fn test_or() { + let mut input = tests::INPUT; + + assert_eq!( + or(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + })] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + or(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + })] + ); + } + + #[test] + fn test_ori() { + let mut input = tests::INPUT; + + assert_eq!( + ori(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ORI, + address_a: reg2mem(1), + address_b: 4, + address_c: reg2mem(3) + })] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + ori(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ORI, + address_a: reg2mem(0), + address_b: 0, + address_c: reg2mem(0) + })] + ); + } } From 495d9a2af520163145541ec92f77c8b8ed2281a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Tue, 9 Apr 2024 12:54:38 +0300 Subject: [PATCH 25/26] riscv_code_generator: Add jal tests. --- bitvm-transpiler/src/riscv/generator.rs | 80 +++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index be03b1d..0be259b 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -1575,6 +1575,32 @@ mod tests { ); } + #[test] + fn test_and() { + let mut input = tests::INPUT; + + assert_eq!( + and(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_AND, + address_a: reg2mem(1), + address_b: reg2mem(2), + address_c: reg2mem(3) + })] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + and(input, tests::INFO), + vec![bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_AND, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + })] + ); + } + #[test] fn test_andi() { let mut input = tests::INPUT; @@ -1652,4 +1678,58 @@ mod tests { })] ); } + + #[test] + fn test_jal() { + let mut input = tests::INPUT; + + assert_eq!( + jal(input, tests::INFO), + vec![ + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 4, + address_c: reg2mem(3) + }), + bitvm::UnresolvedInstruction { + instr: bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + }, + // Code generator won't modify pc values directly. + label: bitvm::Labels::Pc(4), + real_pc: 0, + bitvm_pc: 0, + } + ] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + jal(input, tests::INFO), + vec![ + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 4, + address_c: reg2mem(0) + }), + bitvm::UnresolvedInstruction { + instr: bitvm::Instruction { + asm_type: bitvm::ASM_BEQ, + address_a: reg2mem(0), + address_b: reg2mem(0), + address_c: reg2mem(0) + }, + // Code generator won't modify pc values directly. + label: bitvm::Labels::Pc(0), + real_pc: 0, + bitvm_pc: 0, + } + ] + ); + } } From 567849017563f96b5c14ff3a238e9721fafeaca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Tue, 9 Apr 2024 14:19:37 +0300 Subject: [PATCH 26/26] riscv_code_generator: Add more tests. --- bitvm-transpiler/src/riscv/generator.rs | 141 ++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/bitvm-transpiler/src/riscv/generator.rs b/bitvm-transpiler/src/riscv/generator.rs index 0be259b..6b0fc7b 100644 --- a/bitvm-transpiler/src/riscv/generator.rs +++ b/bitvm-transpiler/src/riscv/generator.rs @@ -1732,4 +1732,145 @@ mod tests { ] ); } + + #[test] + fn test_lbu() { + let mut input = tests::INPUT; + + assert_eq!( + lbu(input, tests::INFO), + vec![ + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: tmp() + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: reg2mem(3) + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(3), + address_b: 0xFF, + address_c: reg2mem(3) + }) + ] + ); + + tests::make_it_zero(&mut input); + assert_eq!( + lbu(input, tests::INFO), + vec![ + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(0), + address_b: 0, + address_c: tmp() + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: reg2mem(0) + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(0), + address_b: 0xFF, + address_c: reg2mem(0) + }) + ] + ); + } + + #[test] + fn test_lh() { + let input = tests::INPUT; + let mut expected = vec![ + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: reg2mem(1), + address_b: 4, + address_c: tmp(), + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: reg2mem(3), + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(3), + address_b: 0xFF, + address_c: reg2mem(3), + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADDI, + address_a: tmp(), + address_b: 1, + address_c: tmp(), + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_LOAD, + address_a: 0, + address_b: tmp(), + address_c: tmp2(), + }), + bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: tmp2(), + address_b: 0xFF, + address_c: tmp2(), + }), + ]; + + for _ in 0..8 { + expected.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: tmp2(), + address_b: tmp2(), + address_c: tmp2(), + })); + } + + expected.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(3), + address_b: tmp2(), + address_c: reg2mem(3), + })); + + expected.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ANDI, + address_a: reg2mem(3), + address_b: 0x8000, + address_c: tmp(), + })); + expected.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_ADD, + address_a: tmp(), + address_b: tmp(), + address_c: tmp(), + })); + + expected.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_SUB, + address_a: 0, + address_b: tmp(), + address_c: tmp(), + })); + expected.push(bitvm::UnresolvedInstruction::from(bitvm::Instruction { + asm_type: bitvm::ASM_OR, + address_a: reg2mem(3), + address_b: tmp(), + address_c: reg2mem(3), + })); + + assert_eq!(lh(input, tests::INFO), expected); + } }