├── Module.manifest ├── data ├── languages │ ├── md32.slaspec │ ├── md32.opinion │ ├── md32.dwarf │ ├── md32.ldefs │ ├── md32.pspec │ ├── md32.cspec │ └── md32.sinc ├── sleighArgs.txt └── build.xml ├── .gitignore ├── extension.properties ├── README.md └── LICENSE.txt /Module.manifest: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/languages/md32.slaspec: -------------------------------------------------------------------------------- 1 | @include "md32.sinc" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.gradle 2 | /build 3 | /dist 4 | *.sla 5 | -------------------------------------------------------------------------------- /extension.properties: -------------------------------------------------------------------------------- 1 | name=@extname@ 2 | description=MediaTek MD32 processor module 3 | author=cyrozap 4 | createdOn=2020-12-06 5 | version=@extversion@ 6 | -------------------------------------------------------------------------------- /data/languages/md32.opinion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /data/languages/md32.dwarf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /data/languages/md32.ldefs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | MediaTek MD32, little endian 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /data/sleighArgs.txt: -------------------------------------------------------------------------------- 1 | # Add sleigh compiler options to this file (one per line) which will 2 | # be used when compiling each language within this module. 3 | # All options should start with a '-' character. 4 | # 5 | # IMPORTANT: The -a option should NOT be specified 6 | # 7 | 8 | # Turn on parser debugging. 9 | -x 10 | 11 | # Print warnings for unnecessary pcode instructions. 12 | -u 13 | 14 | # Report pattern conflicts. 15 | -l 16 | 17 | # Print warnings for all NOP constructors. 18 | -n 19 | 20 | # Print warnings for dead temporaries. 21 | -t 22 | 23 | # Enforce use of 'local' keyword for temporaries. 24 | -e 25 | 26 | # Print warnings for unused token fields. 27 | -f 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MediaTek MD32 Processor Module for Ghidra 2 | 3 | Work-in-progress, most instructions not yet supported. 4 | 5 | **Current status**: Progress has stalled due to both the difficulty I've had 6 | getting Ghidra to understand MD32 instruction bundles as well as [Ghidra's 7 | current inability to support delay slots for ISAs that have variable-length 8 | instructions][delayslot]. 9 | 10 | Fortunately, it may be possible to fix the issue with instruction bundles (see 11 | Ghidra issues [\#4390][ghidra-4390] and [\#4581][ghidra-4581]), and I may be 12 | able to work around the [delay slot issue][delayslot] using [P-code 13 | injection][pcode]. 14 | 15 | 16 | ## Build and Install 17 | 18 | ``` 19 | $ git clone https://github.com/cyrozap/ghidra-md32.git 20 | $ cd ghidra-md32 21 | $ gradle 22 | ``` 23 | 24 | The `dist` directory will now contain the extension zip file that you can 25 | install into Ghidra. 26 | 27 | 28 | [delayslot]: https://github.com/NationalSecurityAgency/ghidra/issues/3942 29 | [ghidra-4390]: https://github.com/NationalSecurityAgency/ghidra/issues/4390 30 | [ghidra-4581]: https://github.com/NationalSecurityAgency/ghidra/issues/4581 31 | [pcode]: https://swarm.ptsecurity.com/guide-to-p-code-injection/ 32 | -------------------------------------------------------------------------------- /data/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /data/languages/md32.pspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /data/languages/md32.cspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /data/languages/md32.sinc: -------------------------------------------------------------------------------- 1 | define endian=big; 2 | define alignment=2; 3 | 4 | define space PMEM type=ram_space size=4 default; 5 | define space DMEM type=ram_space size=4; 6 | define space register type=register_space size=4; 7 | 8 | define register offset=0 size=4 [ 9 | r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 10 | ]; 11 | 12 | define register offset=0x100 size=4 [ 13 | sr ipc isr 14 | lf 15 | ls0 le0 lc0 16 | ls1 le1 lc1 17 | ls2 le2 lc2 18 | dbg 19 | ]; 20 | 21 | define register offset=0x200 size=4 [ 22 | a0l a0h 23 | ]; 24 | 25 | define register offset=0x200 size=8 [ 26 | a0 27 | ]; 28 | 29 | define register offset=0x1000 size=4 pc; 30 | 31 | define register offset=0x2000 size=4 contextreg; 32 | 33 | define context contextreg 34 | bundle = (0, 0) noflow 35 | 36 | # Instruction decoding phase. 37 | phase = (1, 1) 38 | 39 | # Indicate that this is the last instruction in a loop. 40 | end_of_loop = (2, 2) noflow 41 | ; 42 | 43 | define token instr32(32) 44 | op_31_25 = (25, 31) 45 | op_31_24 = (24, 31) 46 | op_31_23 = (23, 31) 47 | op_31_22 = (22, 31) 48 | op_31_21 = (21, 31) 49 | op_31_20 = (20, 31) 50 | op_31_19 = (19, 31) 51 | op_31_18 = (18, 31) 52 | op_31_17 = (17, 31) 53 | op_31_16 = (16, 31) 54 | op_31_13 = (13, 31) 55 | op_31_12 = (12, 31) 56 | op_31_8 = (8, 31) 57 | op_31_4 = (4, 31) 58 | op_31_0 = (0, 31) 59 | op_15_13 = (13, 15) 60 | op_8_8 = (8, 8) 61 | imm_23_8 = (8, 23) 62 | imm_21_18 = (18, 21) 63 | imm_21_17 = (17, 21) 64 | imm_19_8 = (8, 19) 65 | imm_18_14 = (14, 18) 66 | imm_18_9 = (9, 18) 67 | imm_17_13 = (13, 17) 68 | imm_16_12 = (12, 16) 69 | imm_15_0 = (0, 15) 70 | imm_12_12 = (12, 12) 71 | imm_13_9 = (9, 13) 72 | imm_12_8 = (8, 12) 73 | imm_11_4 = (4, 11) 74 | imm32_7_0 = (0, 7) 75 | imm_4_0 = (0, 4) 76 | simm_24_4 = (4, 24) signed 77 | simm_23_8 = (8, 23) signed 78 | simm_22_8 = (8, 22) signed 79 | simm_21_18 = (18, 21) signed 80 | simm_20_0 = (0, 20) signed 81 | simm_19_8 = (8, 19) signed 82 | simm_17_9 = (9, 17) signed 83 | r_8_5 = (5, 8) 84 | rs2 = (8, 11) 85 | csrs1 = (4, 7) 86 | rs1 = (4, 7) 87 | csrd = (0, 3) 88 | rd = (0, 3) 89 | ; 90 | 91 | define token instr16(16) 92 | op_15_15 = (15, 15) 93 | op_15_11 = (11, 15) 94 | op_15_10 = (10, 15) 95 | op_15_9 = (9, 15) 96 | op_15_8 = (8, 15) 97 | op_15_7 = (7, 15) 98 | op_15_6 = (6, 15) 99 | op_15_4 = (4, 15) 100 | op_15_3 = (3, 15) 101 | op_15_0 = (0, 15) 102 | op_14_10 = (10, 14) 103 | op_14_9 = (9, 14) 104 | op_14_8 = (8, 14) 105 | op_14_7 = (7, 14) 106 | op_14_6 = (6, 14) 107 | op_14_4 = (4, 14) 108 | op_14_0 = (0, 14) 109 | op_8_6 = (6, 8) 110 | imm_9_7 = (7, 9) 111 | imm_9_6 = (6, 9) 112 | imm_9_4 = (4, 9) 113 | imm_8_6 = (6, 8) 114 | imm_8_4 = (4, 8) 115 | imm_8_3 = (3, 8) 116 | imm_7_4 = (4, 7) 117 | imm_7_0 = (0, 7) 118 | imm_6_6 = (6, 6) 119 | imm_6_3 = (3, 6) 120 | simm_10_4 = (4, 10) signed 121 | simm_9_7 = (7, 9) signed 122 | simm_8_6 = (6, 8) signed 123 | simm_8_4 = (4, 8) signed 124 | simm_6_0 = (0, 6) signed 125 | rm_r1_r8_8_6 = (6, 8) 126 | rm = (4, 7) 127 | rm_r1_r8_6_4 = (4, 6) 128 | csrm_6_3 = (3, 6) 129 | rm_6_3 = (3, 6) 130 | rm_r1_r8_5_3 = (3, 5) 131 | csrn = (0, 3) 132 | rn = (0, 3) 133 | rn_even = (0, 2) 134 | rn_odd = (0, 2) 135 | rn_r1_r8 = (0, 2) 136 | ; 137 | 138 | attach variables [ rd rs1 rs2 r_8_5 rn rm rm_6_3 ] [ 139 | r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 140 | ]; 141 | 142 | attach variables [ rn_r1_r8 rm_r1_r8_5_3 rm_r1_r8_6_4 rm_r1_r8_8_6 ] [ 143 | r1 r2 r3 r4 r5 r6 r7 r8 144 | ]; 145 | 146 | attach variables [ rn_even ] [ 147 | r0 r2 r4 r6 r8 r10 r12 r14 148 | ]; 149 | 150 | attach variables [ rn_odd ] [ 151 | r1 r3 r5 r7 r9 r11 r13 r15 152 | ]; 153 | 154 | attach variables [ csrd csrs1 csrn csrm_6_3 ] [ 155 | sr ipc isr _ lf ls0 le0 lc0 ls1 le1 lc1 ls2 le2 lc2 _ _ 156 | ]; 157 | 158 | 159 | define pcodeop halt; 160 | define pcodeop ieon; 161 | define pcodeop ieoff; 162 | define pcodeop ior; 163 | define pcodeop iow; 164 | define pcodeop swi; 165 | 166 | 167 | :^instruction is phase=0 & instruction [ phase = 1; ] { 168 | build instruction; 169 | } 170 | 171 | :^instruction is phase=0 & end_of_loop=1 & instruction [ phase = 1; ] { 172 | build instruction; 173 | if (lc0 == 1) goto ; 174 | lc0 = lc0 - 1; 175 | goto [ls0]; 176 | 177 | } 178 | 179 | with: phase=1 { 180 | 181 | 182 | # 32-bit instructions 183 | 184 | with: bundle=0 { 185 | 186 | # Move signed immediate to register. 187 | :mv rd, #simm_24_4 is op_31_25=0 & simm_24_4 & rd { 188 | rd = simm_24_4; 189 | } 190 | 191 | :add rd, rs1, rs2 is op_31_12=0x0400e & rs2 & rs1 & rd { 192 | rd = rs1 + rs2; 193 | } 194 | 195 | :sub rd, rs1, rs2 is op_31_12=0x0401e & rs2 & rs1 & rd { 196 | rd = rs1 - rs2; 197 | } 198 | 199 | # Add with carry. 200 | # TODO: Implement carry. 201 | :addx rd, rs1, rs2 is op_31_12=0x0402e & rs2 & rs1 & rd { 202 | rd = rs1 + rs2; 203 | } 204 | 205 | # Subtract with borrow. 206 | # TODO: Implement borrow. 207 | :subx rd, rs1, rs2 is op_31_12=0x0403e & rs2 & rs1 & rd { 208 | rd = rs1 - rs2; 209 | } 210 | 211 | :and rd, rs1, rs2 is op_31_12=0x0404e & rs2 & rs1 & rd { 212 | rd = rs1 & rs2; 213 | } 214 | 215 | :or rd, rs1, rs2 is op_31_12=0x0405e & rs2 & rs1 & rd { 216 | rd = rs1 | rs2; 217 | } 218 | 219 | :xor rd, rs1, rs2 is op_31_12=0x0406e & rs2 & rs1 & rd { 220 | rd = rs1 ^ rs2; 221 | } 222 | 223 | # Conditional inversion. 224 | :cinv rd, rs1, rs2 is op_31_12=0x0407e & rs2 & rs1 & rd { 225 | # If rs1 is positive, rd=rs2. 226 | if (rs1 s< 0) goto ; 227 | rd = rs2; 228 | goto ; 229 | 230 | # If rs1 is negative, rd=-rs2. 231 | rd = -rs2; 232 | 233 | } 234 | 235 | :xtd rd, rs1, rs2 is op_31_12=0x0408e & rs2 & rs1 & rd unimpl 236 | 237 | :sll rd, rs1, rs2 is op_31_12=0x0409e & rs2 & rs1 & rd { 238 | rd = rs1 << rs2; 239 | } 240 | 241 | :sra rd, rs1, rs2 is op_31_12=0x040ae & rs2 & rs1 & rd { 242 | rd = rs1 s>> rs2; 243 | } 244 | 245 | :srl rd, rs1, rs2 is op_31_12=0x040be & rs2 & rs1 & rd { 246 | rd = rs1 >> rs2; 247 | } 248 | 249 | :mul rd, rs1, rs2 is op_31_12=0x040ce & rs2 & rs1 & rd { 250 | rd = rs1 * rs2; 251 | } 252 | 253 | # Unsigned division. 254 | :udiv rd, rs2 is op_31_12=0x040dc & rs2 & rd { 255 | a0l = rd / rs2; 256 | a0h = rd % rs2; 257 | } 258 | 259 | # Also unsigned division. Maybe the u/s are for unsaturating/saturating? 260 | # TODO: Find out how sdiv differs from udiv. 261 | :sdiv rd, rs2 is op_31_12=0x040dd & rs2 & rd { 262 | a0l = rd / rs2; 263 | a0h = rd % rs2; 264 | } 265 | 266 | # Move from registers to accumulator(?). 267 | :mv a0, rs1, rs2 is op_31_12=0x0412c & rs2 & rs1 & a0 { 268 | a0l = rs1; 269 | a0h = rs2; 270 | } 271 | 272 | # Move from register to accumulator(?) low. 273 | :mv a0l, rs1 is op_31_12=0x04134 & rs1 & a0l { 274 | a0l = rs1; 275 | } 276 | 277 | # Move from register to accumulator(?) high. 278 | :mv a0h, rs2 is op_31_12=0x04148 & rs2 & a0h { 279 | a0h = rs2; 280 | } 281 | 282 | # Move from CSR to register. 283 | :mv rd, csrs1 is op_31_12=0x04154 & csrs1 & rd { 284 | rd = csrs1; 285 | } 286 | 287 | # Move from accumulator(?) high to register. 288 | :mv rd, a0h is op_31_12=0x04162 & rd & a0h { 289 | rd = a0h; 290 | } 291 | 292 | # Move from accumulator(?) low to register. 293 | :mv rd, a0l is op_31_12=0x04172 & rd & a0l { 294 | rd = a0l; 295 | } 296 | 297 | # Move from register to CSR. 298 | :mv csrd, rs1 is op_31_12=0x04182 & rs1 & csrd { 299 | csrd = rs1; 300 | } 301 | 302 | # Count leading bits. Starting from the most significant bit in rs1, count the 303 | # number of contiguous bits that match the most significant bit and store that 304 | # count in rd. 305 | :clb rd, rs1 is op_31_12=0x04196 & rs1 & rd { 306 | local tmp = rs1; 307 | if (tmp & (1 << 31)) == 0 goto ; 308 | tmp = ~rs1; 309 | 310 | rd = 1; 311 | if (tmp & (1 << 30)) != 0 goto inst_next; 312 | rd = rd + 1; 313 | if (tmp & (1 << 29)) != 0 goto inst_next; 314 | rd = rd + 1; 315 | if (tmp & (1 << 28)) != 0 goto inst_next; 316 | rd = rd + 1; 317 | if (tmp & (1 << 27)) != 0 goto inst_next; 318 | rd = rd + 1; 319 | if (tmp & (1 << 26)) != 0 goto inst_next; 320 | rd = rd + 1; 321 | if (tmp & (1 << 25)) != 0 goto inst_next; 322 | rd = rd + 1; 323 | if (tmp & (1 << 24)) != 0 goto inst_next; 324 | rd = rd + 1; 325 | if (tmp & (1 << 23)) != 0 goto inst_next; 326 | rd = rd + 1; 327 | if (tmp & (1 << 22)) != 0 goto inst_next; 328 | rd = rd + 1; 329 | if (tmp & (1 << 21)) != 0 goto inst_next; 330 | rd = rd + 1; 331 | if (tmp & (1 << 20)) != 0 goto inst_next; 332 | rd = rd + 1; 333 | if (tmp & (1 << 19)) != 0 goto inst_next; 334 | rd = rd + 1; 335 | if (tmp & (1 << 18)) != 0 goto inst_next; 336 | rd = rd + 1; 337 | if (tmp & (1 << 17)) != 0 goto inst_next; 338 | rd = rd + 1; 339 | if (tmp & (1 << 16)) != 0 goto inst_next; 340 | rd = rd + 1; 341 | if (tmp & (1 << 15)) != 0 goto inst_next; 342 | rd = rd + 1; 343 | if (tmp & (1 << 14)) != 0 goto inst_next; 344 | rd = rd + 1; 345 | if (tmp & (1 << 13)) != 0 goto inst_next; 346 | rd = rd + 1; 347 | if (tmp & (1 << 12)) != 0 goto inst_next; 348 | rd = rd + 1; 349 | if (tmp & (1 << 11)) != 0 goto inst_next; 350 | rd = rd + 1; 351 | if (tmp & (1 << 10)) != 0 goto inst_next; 352 | rd = rd + 1; 353 | if (tmp & (1 << 9)) != 0 goto inst_next; 354 | rd = rd + 1; 355 | if (tmp & (1 << 8)) != 0 goto inst_next; 356 | rd = rd + 1; 357 | if (tmp & (1 << 7)) != 0 goto inst_next; 358 | rd = rd + 1; 359 | if (tmp & (1 << 6)) != 0 goto inst_next; 360 | rd = rd + 1; 361 | if (tmp & (1 << 5)) != 0 goto inst_next; 362 | rd = rd + 1; 363 | if (tmp & (1 << 4)) != 0 goto inst_next; 364 | rd = rd + 1; 365 | if (tmp & (1 << 3)) != 0 goto inst_next; 366 | rd = rd + 1; 367 | if (tmp & (1 << 2)) != 0 goto inst_next; 368 | rd = rd + 1; 369 | if (tmp & (1 << 1)) != 0 goto inst_next; 370 | rd = rd + 1; 371 | if (tmp & (1 << 0)) != 0 goto inst_next; 372 | rd = rd + 1; 373 | } 374 | 375 | :xtd rd, rs1, #imm_12_8 is op_31_13=0b0000010000011011011 & imm_12_8 & rs1 & rd unimpl 376 | 377 | # Shift register right (logical) by an immediate. 378 | :srl rd, rs1, #imm_12_8 is op_31_13=0b0000010000011100011 & imm_12_8 & rs1 & rd { 379 | rd = rs1 >> imm_12_8; 380 | } 381 | 382 | # Shift register right (arithmetic) by an immediate. 383 | :sra rd, rs1, #imm_12_8 is op_31_13=0b0000010000011101011 & imm_12_8 & rs1 & rd { 384 | rd = rs1 s>> imm_12_8; 385 | } 386 | 387 | # Shift register left (logical) by an immediate. 388 | :sll rd, rs1, #imm_12_8 is op_31_13=0b0000010000011110011 & imm_12_8 & rs1 & rd { 389 | rd = rs1 << imm_12_8; 390 | } 391 | 392 | # Couldn't get these to work in hardware. 393 | # TODO: Find hardware that supports these instructions and test them. 394 | :bset rd, rs1, rs2 is op_31_12=0x04880 & rs2 & rs1 & rd unimpl 395 | :bclr rd, rs1, rs2 is op_31_12=0x04882 & rs2 & rs1 & rd unimpl 396 | :btgl rd, rs1, rs2 is op_31_12=0x04884 & rs2 & rs1 & rd unimpl 397 | :btst rd, rs1, rs2 is op_31_12=0x04886 & rs2 & rs1 & rd unimpl 398 | 399 | # Couldn't get these to work in hardware. 400 | # TODO: Find hardware that supports these instructions and test them. 401 | :bset rd, rs1, #imm_12_8 is op_31_13=0b0000010010001001100 & imm_12_8 & rs1 & rd unimpl 402 | :bclr rd, rs1, #imm_12_8 is op_31_13=0b0000010010001001101 & imm_12_8 & rs1 & rd unimpl 403 | :btgl rd, rs1, #imm_12_8 is op_31_13=0b0000010010001001110 & imm_12_8 & rs1 & rd unimpl 404 | :btst rd, rs1, #imm_12_8 is op_31_13=0b0000010010001001111 & imm_12_8 & rs1 & rd unimpl 405 | 406 | # Couldn't get these to work in hardware. 407 | # TODO: Find hardware that supports these instructions and test them. 408 | :ror rd, rs1, rs2 is op_31_12=0x048c2 & rs2 & rs1 & rd unimpl 409 | :rol rd, rs1, rs2 is op_31_12=0x048c3 & rs2 & rs1 & rd unimpl 410 | 411 | # 32-bit NOP. 412 | :nop is op_31_0=0x05000000 {} 413 | 414 | :brk is op_31_0=0x05400000 unimpl 415 | :brk.j is op_31_0=0x05600000 unimpl 416 | 417 | # Halt the CPU? 418 | :halt is op_31_0=0x05800000 { 419 | halt(); 420 | } 421 | 422 | # Return from interrupt. 423 | # FIXME: Properly implement returning from an interrupt (this is just a placeholder to make decompilation work). 424 | :rti is op_31_0=0x05a00000 { 425 | return [pc]; 426 | } 427 | 428 | # Software interrupt? 429 | :swi #imm_15_0 is op_31_16=0x05c0 & imm_15_0 { 430 | swi(imm_15_0:2); 431 | } 432 | 433 | # Load byte from an offset relative to a register, zero extending. 434 | :lbu rs1, #simm_19_8(rd) is op_31_20=0x060 & simm_19_8 & rs1 & rd { 435 | rs1 = zext(*[DMEM]:1 (rd + simm_19_8)); 436 | } 437 | 438 | # Load half word from an offset relative to a register, zero extending. 439 | :lhu rs1, #simm_19_8(rd) is op_31_20=0x061 & simm_19_8 & rs1 & rd { 440 | rs1 = zext(*[DMEM]:2 (rd + simm_19_8)); 441 | } 442 | 443 | # Load byte from an offset relative to a register, sign extending. 444 | :lb rs1, #simm_19_8(rd) is op_31_20=0x062 & simm_19_8 & rs1 & rd { 445 | rs1 = sext(*[DMEM]:1 (rd + simm_19_8)); 446 | } 447 | 448 | # Load half word from an offset relative to a register, sign extending. 449 | :lh rs1, #simm_19_8(rd) is op_31_20=0x063 & simm_19_8 & rs1 & rd { 450 | rs1 = sext(*[DMEM]:2 (rd + simm_19_8)); 451 | } 452 | 453 | # Load word from an offset relative to a register. 454 | :lw rs1, #simm_19_8(rd) is op_31_20=0x064 & simm_19_8 & rs1 & rd { 455 | rs1 = *[DMEM](rd + simm_19_8); 456 | } 457 | 458 | # Store byte at an offset relative to a register. 459 | :sb rs1, #simm_19_8(rd) is op_31_20=0x065 & simm_19_8 & rs1 & rd { 460 | *[DMEM](rd + simm_19_8) = rs1:1; 461 | } 462 | 463 | # Store half word at an offset relative to a register. 464 | :sh rs1, #simm_19_8(rd) is op_31_20=0x066 & simm_19_8 & rs1 & rd { 465 | *[DMEM](rd + simm_19_8) = rs1:2; 466 | } 467 | 468 | # Store word at an offset relative to a register. 469 | :sw rs1, #simm_19_8(rd) is op_31_20=0x067 & simm_19_8 & rs1 & rd { 470 | *[DMEM](rd + simm_19_8) = rs1; 471 | } 472 | 473 | :lbu rs1, (rd+=#simm_19_8) is op_31_20=0x068 & simm_19_8 & rs1 & rd { 474 | rs1 = zext(*[DMEM]:1 (rd)); 475 | rd = rd + simm_19_8; 476 | } 477 | 478 | :lhu rs1, (rd+=#simm_19_8) is op_31_20=0x069 & simm_19_8 & rs1 & rd { 479 | rs1 = zext(*[DMEM]:2 (rd)); 480 | rd = rd + simm_19_8; 481 | } 482 | 483 | :lb rs1, (rd+=#simm_19_8) is op_31_20=0x06a & simm_19_8 & rs1 & rd { 484 | rs1 = sext(*[DMEM]:1 (rd)); 485 | rd = rd + simm_19_8; 486 | } 487 | 488 | :lh rs1, (rd+=#simm_19_8) is op_31_20=0x06b & simm_19_8 & rs1 & rd { 489 | rs1 = sext(*[DMEM]:2 (rd)); 490 | rd = rd + simm_19_8; 491 | } 492 | 493 | :lw rs1, (rd+=#simm_19_8) is op_31_20=0x06c & simm_19_8 & rs1 & rd { 494 | rs1 = *[DMEM](rd); 495 | rd = rd + simm_19_8; 496 | } 497 | 498 | :sb rs1, (rd+=#simm_19_8) is op_31_20=0x06d & simm_19_8 & rs1 & rd { 499 | *[DMEM](rd) = rs1:1; 500 | rd = rd + simm_19_8; 501 | } 502 | 503 | :sh rs1, (rd+=#simm_19_8) is op_31_20=0x06e & simm_19_8 & rs1 & rd { 504 | *[DMEM](rd) = rs1:2; 505 | rd = rd + simm_19_8; 506 | } 507 | 508 | :sw rs1, (rd+=#simm_19_8) is op_31_20=0x06f & simm_19_8 & rs1 & rd { 509 | *[DMEM](rd) = rs1; 510 | rd = rd + simm_19_8; 511 | } 512 | 513 | :rl rs1, rd is op_31_8=0x070000 & rs1 & rd unimpl 514 | :cw rs1, rd is op_31_8=0x070001 & rs1 & rd unimpl 515 | 516 | :ior rs1, #imm_12_8(rd) is op_31_13=0b0000011100000000010 & imm_12_8 & rs1 & rd { 517 | rs1 = ior(rd + imm_12_8); 518 | } 519 | 520 | :iow rs1, #imm_12_8(rd) is op_31_13=0b0000011100000000011 & imm_12_8 & rs1 & rd { 521 | iow(rd + imm_12_8, rs1); 522 | } 523 | 524 | # Move from dbg CSR to register. 525 | :mv rd, dbg is op_31_4=0x0700800 & rd & dbg { 526 | rd = dbg; 527 | } 528 | 529 | # Move from register to dbg CSR. 530 | :mv dbg, rd is op_31_4=0x0700801 & rd & dbg { 531 | dbg = rd; 532 | } 533 | 534 | :ieon is op_31_0=0x07008020 { 535 | ieon(); 536 | } 537 | 538 | :ieoff is op_31_0=0x07008021 { 539 | ieoff(); 540 | } 541 | 542 | # ADD a register with an immediate. 543 | :add rd, rs1, #simm_23_8 is op_31_24=0x08 & simm_23_8 & rs1 & rd { 544 | rd = rs1 + simm_23_8; 545 | } 546 | 547 | # SUB a register with an immediate. 548 | :sub rd, rs1, #simm_23_8 is op_31_24=0x09 & simm_23_8 & rs1 & rd { 549 | rd = rs1 - simm_23_8; 550 | } 551 | 552 | # Add with carry. 553 | # TODO: Implement carry. 554 | :addx rd, rs1, #simm_23_8 is op_31_24=0x0a & simm_23_8 & rs1 & rd { 555 | rd = rs1 + simm_23_8; 556 | } 557 | 558 | # Subtract with borrow. 559 | # TODO: Implement borrow. 560 | :subx rd, rs1, #simm_23_8 is op_31_24=0x0b & simm_23_8 & rs1 & rd { 561 | rd = rs1 - simm_23_8; 562 | } 563 | 564 | # AND a register with an immediate. 565 | :and rd, rs1, #imm_23_8 is op_31_24=0x0c & imm_23_8 & rs1 & rd { 566 | rd = rs1 & imm_23_8; 567 | } 568 | 569 | # OR a register with an immediate. 570 | :or rd, rs1, #imm_23_8 is op_31_24=0x0d & imm_23_8 & rs1 & rd { 571 | rd = rs1 | imm_23_8; 572 | } 573 | 574 | # XOR a register with an immediate. 575 | :xor rd, rs1, #imm_23_8 is op_31_24=0x0e & imm_23_8 & rs1 & rd { 576 | rd = rs1 ^ imm_23_8; 577 | } 578 | 579 | # Set the high 16 bits of a register, clearing the lower bits. 580 | :sethi rd, #imm_23_8 is op_31_24=0x0f & imm_23_8 & rs1=0 & rd { 581 | rd = imm_23_8 << 16; 582 | } 583 | 584 | :ble.d1 rs1, rd, #jump_dest is op_31_23=0b000100000 & simm_22_8 & rs1 & rd [ 585 | jump_dest = inst_start + simm_22_8 * 2; 586 | ] { 587 | local delayflag = (rs1 s<= rd); 588 | delayslot(2); 589 | if !delayflag goto inst_next; 590 | goto [jump_dest:4]; 591 | } 592 | 593 | :ble.d1 #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001000010 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 594 | calc_imm = (simm_21_18 << 5) | imm_4_0; 595 | jump_dest = inst_start + simm_17_9 * 2; 596 | ] { 597 | local delayflag = (calc_imm:4 s<= r_8_5); 598 | delayslot(2); 599 | if !delayflag goto inst_next; 600 | goto [jump_dest:4]; 601 | } 602 | 603 | # Branch if register less than or equal to immediate, signed, delayed by 1. 604 | :ble.d1 r_8_5, #calc_imm, #jump_dest is op_31_22=0b0001000011 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 605 | calc_imm = (simm_21_18 << 5) | imm_4_0; 606 | jump_dest = inst_start + simm_17_9 * 2; 607 | ] { 608 | local delayflag = (r_8_5 s<= calc_imm:4); 609 | delayslot(2); 610 | if !delayflag goto inst_next; 611 | goto [jump_dest:4]; 612 | } 613 | 614 | :bleu.d1 rs1, rd, #jump_dest is op_31_23=0b000100010 & simm_22_8 & rs1 & rd [ 615 | jump_dest = inst_start + simm_22_8 * 2; 616 | ] { 617 | local delayflag = (rs1 <= rd); 618 | delayslot(2); 619 | if !delayflag goto inst_next; 620 | goto [jump_dest:4]; 621 | } 622 | 623 | :bleu.d1 #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001000110 & imm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 624 | calc_imm = (imm_21_18 << 5) | imm_4_0; 625 | jump_dest = inst_start + simm_17_9 * 2; 626 | ] { 627 | local delayflag = (calc_imm:4 <= r_8_5); 628 | delayslot(2); 629 | if !delayflag goto inst_next; 630 | goto [jump_dest:4]; 631 | } 632 | 633 | # Branch if register less than or equal to immediate, signed, delayed by 1. 634 | :bleu.d1 r_8_5, #calc_imm, #jump_dest is op_31_22=0b0001000111 & imm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 635 | calc_imm = (imm_21_18 << 5) | imm_4_0; 636 | jump_dest = inst_start + simm_17_9 * 2; 637 | ] { 638 | local delayflag = (r_8_5 <= calc_imm:4); 639 | delayslot(2); 640 | if !delayflag goto inst_next; 641 | goto [jump_dest:4]; 642 | } 643 | 644 | :blt.d1 rs1, rd, #jump_dest is op_31_23=0b000100100 & simm_22_8 & rs1 & rd [ 645 | jump_dest = inst_start + simm_22_8 * 2; 646 | ] { 647 | local delayflag = (rs1 s< rd); 648 | delayslot(2); 649 | if !delayflag goto inst_next; 650 | goto [jump_dest:4]; 651 | } 652 | 653 | :blt.d1 #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001001010 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 654 | calc_imm = (simm_21_18 << 5) | imm_4_0; 655 | jump_dest = inst_start + simm_17_9 * 2; 656 | ] { 657 | local delayflag = (calc_imm:4 s< r_8_5); 658 | delayslot(2); 659 | if !delayflag goto inst_next; 660 | goto [jump_dest:4]; 661 | } 662 | 663 | # Branch if register less than immediate, signed, delayed by 1. 664 | :blt.d1 r_8_5, #calc_imm, #jump_dest is op_31_22=0b0001001011 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 665 | calc_imm = (simm_21_18 << 5) | imm_4_0; 666 | jump_dest = inst_start + simm_17_9 * 2; 667 | ] { 668 | local delayflag = (r_8_5 s< calc_imm:4); 669 | delayslot(2); 670 | if !delayflag goto inst_next; 671 | goto [jump_dest:4]; 672 | } 673 | 674 | # Branch if less-than, unsigned. 675 | :bltu.d1 rs1, rd, #jump_dest is op_31_23=0b000100110 & simm_22_8 & rs1 & rd [ 676 | jump_dest = inst_start + simm_22_8 * 2; 677 | ] { 678 | local delayflag = (rs1 < rd); 679 | delayslot(2); 680 | if !delayflag goto inst_next; 681 | goto [jump_dest:4]; 682 | } 683 | 684 | :bltu.d1 #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001001110 & imm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 685 | calc_imm = (imm_21_18 << 5) | imm_4_0; 686 | jump_dest = inst_start + simm_17_9 * 2; 687 | ] { 688 | local delayflag = (calc_imm:4 < r_8_5); 689 | delayslot(2); 690 | if !delayflag goto inst_next; 691 | goto [jump_dest:4]; 692 | } 693 | 694 | :bltu.d1 r_8_5, #calc_imm, #jump_dest is op_31_22=0b0001001111 & imm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 695 | calc_imm = (imm_21_18 << 5) | imm_4_0; 696 | jump_dest = inst_start + simm_17_9 * 2; 697 | ] { 698 | local delayflag = (r_8_5 < calc_imm:4); 699 | delayslot(2); 700 | if !delayflag goto inst_next; 701 | goto [jump_dest:4]; 702 | } 703 | 704 | :beq.d1 rs1, rd, #jump_dest is op_31_23=0b000101000 & simm_22_8 & rs1 & rd [ 705 | jump_dest = inst_start + simm_22_8 * 2; 706 | ] { 707 | local delayflag = (rs1 == rd); 708 | delayslot(2); 709 | if !delayflag goto inst_next; 710 | goto [jump_dest:4]; 711 | } 712 | 713 | :beq.d1 #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001010010 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 714 | calc_imm = (simm_21_18 << 5) | imm_4_0; 715 | jump_dest = inst_start + simm_17_9 * 2; 716 | ] { 717 | local delayflag = (calc_imm:4 == r_8_5); 718 | delayslot(2); 719 | if !delayflag goto inst_next; 720 | goto [jump_dest:4]; 721 | } 722 | 723 | # FIXME: Handle nested loops. 724 | # FIXME: See j16.d2. 725 | :do.d2 #imm32_7_0, #loop_end is op_31_20=0x14c & imm_19_8 & imm32_7_0 [ 726 | loop_end = inst_start + imm_19_8; 727 | end_of_loop = 1; 728 | globalset(loop_end, end_of_loop); 729 | ] { 730 | delayslot(4); 731 | ls0 = inst_next; 732 | lc0 = imm32_7_0; 733 | le0 = loop_end; 734 | } 735 | 736 | # FIXME: Handle nested loops. 737 | # FIXME: See j16.d2. 738 | :do.d2 rd, #loop_end is op_31_20=0x14e & imm_19_8 & rd [ 739 | loop_end = inst_start + imm_19_8; 740 | end_of_loop = 1; 741 | globalset(loop_end, end_of_loop); 742 | ] { 743 | delayslot(4); 744 | ls0 = inst_next; 745 | lc0 = rd; 746 | le0 = loop_end; 747 | } 748 | 749 | :bne.d1 rs1, rd, #jump_dest is op_31_23=0b000101010 & simm_22_8 & rs1 & rd [ 750 | jump_dest = inst_start + simm_22_8 * 2; 751 | ] { 752 | local delayflag = (rs1 != rd); 753 | delayslot(2); 754 | if !delayflag goto inst_next; 755 | goto [jump_dest:4]; 756 | } 757 | 758 | :bne.d1 #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001010110 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 759 | calc_imm = (simm_21_18 << 5) | imm_4_0; 760 | jump_dest = inst_start + simm_17_9 * 2; 761 | ] { 762 | local delayflag = (calc_imm:4 != r_8_5); 763 | delayslot(2); 764 | if !delayflag goto inst_next; 765 | goto [jump_dest:4]; 766 | } 767 | 768 | # Unconditional relative jump. 769 | :j.d1 #jump_dest is op_31_21=0b00010110000 & simm_20_0 [ 770 | jump_dest = inst_start + simm_20_0 * 2; 771 | ] { 772 | delayslot(2); 773 | goto [jump_dest:4]; 774 | } 775 | 776 | # Unconditional relative jump with link. 777 | :jal.d1 #jump_dest is op_31_21=0b00010111000 & simm_20_0 [ 778 | jump_dest = inst_start + simm_20_0 * 2; 779 | ] { 780 | delayslot(2); 781 | r15 = inst_next; 782 | call [jump_dest:4]; 783 | } 784 | 785 | :ble rs1, rd, #jump_dest is op_31_23=0b000110000 & simm_22_8 & rs1 & rd [ 786 | jump_dest = inst_start + simm_22_8 * 2; 787 | ] { 788 | local flag = (rs1 s<= rd); 789 | if !flag goto inst_next; 790 | goto [jump_dest:4]; 791 | } 792 | 793 | :ble #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001100010 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 794 | calc_imm = (simm_21_18 << 5) | imm_4_0; 795 | jump_dest = inst_start + simm_17_9 * 2; 796 | ] { 797 | local flag = (calc_imm:4 s<= r_8_5); 798 | if !flag goto inst_next; 799 | goto [jump_dest:4]; 800 | } 801 | 802 | :ble r_8_5, #calc_imm, #jump_dest is op_31_22=0b0001100011 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 803 | calc_imm = (simm_21_18 << 5) | imm_4_0; 804 | jump_dest = inst_start + simm_17_9 * 2; 805 | ] { 806 | local flag = (r_8_5 s<= calc_imm:4); 807 | if !flag goto inst_next; 808 | goto [jump_dest:4]; 809 | } 810 | 811 | :bleu rs1, rd, #jump_dest is op_31_23=0b000110010 & simm_22_8 & rs1 & rd [ 812 | jump_dest = inst_start + simm_22_8 * 2; 813 | ] { 814 | local flag = (rs1 <= rd); 815 | if !flag goto inst_next; 816 | goto [jump_dest:4]; 817 | } 818 | 819 | :bleu #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001100110 & imm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 820 | calc_imm = (imm_21_18 << 5) | imm_4_0; 821 | jump_dest = inst_start + simm_17_9 * 2; 822 | ] { 823 | local flag = (calc_imm:4 <= r_8_5); 824 | if !flag goto inst_next; 825 | goto [jump_dest:4]; 826 | } 827 | 828 | :bleu r_8_5, #calc_imm, #jump_dest is op_31_22=0b0001100111 & imm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 829 | calc_imm = (imm_21_18 << 5) | imm_4_0; 830 | jump_dest = inst_start + simm_17_9 * 2; 831 | ] { 832 | local flag = (r_8_5 <= calc_imm:4); 833 | if !flag goto inst_next; 834 | goto [jump_dest:4]; 835 | } 836 | 837 | :blt rs1, rd, #jump_dest is op_31_23=0b000110100 & simm_22_8 & rs1 & rd [ 838 | jump_dest = inst_start + simm_22_8 * 2; 839 | ] { 840 | local flag = (rs1 s< rd); 841 | if !flag goto inst_next; 842 | goto [jump_dest:4]; 843 | } 844 | 845 | :blt #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001101010 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 846 | calc_imm = (simm_21_18 << 5) | imm_4_0; 847 | jump_dest = inst_start + simm_17_9 * 2; 848 | ] { 849 | local flag = (calc_imm:4 s< r_8_5); 850 | if !flag goto inst_next; 851 | goto [jump_dest:4]; 852 | } 853 | 854 | :blt r_8_5, #calc_imm, #jump_dest is op_31_22=0b0001101011 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 855 | calc_imm = (simm_21_18 << 5) | imm_4_0; 856 | jump_dest = inst_start + simm_17_9 * 2; 857 | ] { 858 | local flag = (r_8_5 s< calc_imm:4); 859 | if !flag goto inst_next; 860 | goto [jump_dest:4]; 861 | } 862 | 863 | # Branch if less-than, unsigned. 864 | :bltu rs1, rd, #jump_dest is op_31_23=0b000110110 & simm_22_8 & rs1 & rd [ 865 | jump_dest = inst_start + simm_22_8 * 2; 866 | ] { 867 | local flag = (rs1 < rd); 868 | if !flag goto inst_next; 869 | goto [jump_dest:4]; 870 | } 871 | 872 | :bltu #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001101110 & imm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 873 | calc_imm = (imm_21_18 << 5) | imm_4_0; 874 | jump_dest = inst_start + simm_17_9 * 2; 875 | ] { 876 | local flag = (calc_imm:4 < r_8_5); 877 | if !flag goto inst_next; 878 | goto [jump_dest:4]; 879 | } 880 | 881 | :bltu r_8_5, #calc_imm, #jump_dest is op_31_22=0b0001101111 & imm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 882 | calc_imm = (imm_21_18 << 5) | imm_4_0; 883 | jump_dest = inst_start + simm_17_9 * 2; 884 | ] { 885 | local flag = (r_8_5 < calc_imm:4); 886 | if !flag goto inst_next; 887 | goto [jump_dest:4]; 888 | } 889 | 890 | # Branch if registers are equal. 891 | :beq rs1, rd, #jump_dest is op_31_23=0b000111000 & simm_22_8 & rs1 & rd [ 892 | jump_dest = inst_start + simm_22_8 * 2; 893 | ] { 894 | if !(rs1 == rd) goto inst_next; 895 | goto [jump_dest:4]; 896 | } 897 | 898 | # Branch if immediate equal to register. 899 | :beq #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001110010 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 900 | calc_imm = (simm_21_18 << 5) | imm_4_0; 901 | jump_dest = inst_start + simm_17_9 * 2; 902 | ] { 903 | local flag = (calc_imm:4 == r_8_5); 904 | if !flag goto inst_next; 905 | goto [jump_dest:4]; 906 | } 907 | 908 | # FIXME: Handle nested loops. 909 | :do #imm32_7_0, #loop_end is op_31_20=0x1cc & imm_19_8 & imm32_7_0 [ 910 | loop_end = inst_start + imm_19_8; 911 | end_of_loop = 1; 912 | globalset(loop_end, end_of_loop); 913 | ] { 914 | ls0 = inst_next; 915 | lc0 = imm32_7_0; 916 | le0 = loop_end; 917 | } 918 | 919 | # FIXME: Handle nested loops. 920 | :do rd, #loop_end is op_31_20=0x1ce & imm_19_8 & rd [ 921 | loop_end = inst_start + imm_19_8; 922 | end_of_loop = 1; 923 | globalset(loop_end, end_of_loop); 924 | ] { 925 | ls0 = inst_next; 926 | lc0 = rd; 927 | le0 = loop_end; 928 | } 929 | 930 | # Branch if registers are not equal. 931 | :bne rs1, rd, #jump_dest is op_31_23=0b000111010 & simm_22_8 & rs1 & rd [ 932 | jump_dest = inst_start + simm_22_8 * 2; 933 | ] { 934 | if !(rs1 != rd) goto inst_next; 935 | goto [jump_dest:4]; 936 | } 937 | 938 | # Branch if immediate not equal to register. 939 | :bne #calc_imm, r_8_5, #jump_dest is op_31_22=0b0001110110 & simm_21_18 & simm_17_9 & r_8_5 & imm_4_0 [ 940 | calc_imm = (simm_21_18 << 5) | imm_4_0; 941 | jump_dest = inst_start + simm_17_9 * 2; 942 | ] { 943 | local flag = (calc_imm:4 != r_8_5); 944 | if !flag goto inst_next; 945 | goto [jump_dest:4]; 946 | } 947 | 948 | # Unconditional relative jump. 949 | :j #jump_dest is op_31_21=0b00011110000 & simm_20_0 [ 950 | jump_dest = inst_start + simm_20_0 * 2; 951 | ] { 952 | goto [jump_dest:4]; 953 | } 954 | 955 | # Unconditional relative jump with link. 956 | :jal #jump_dest is op_31_21=0b00011111000 & simm_20_0 [ 957 | jump_dest = inst_start + simm_20_0 * 2; 958 | ] { 959 | r15 = inst_next; 960 | call [jump_dest:4]; 961 | } 962 | 963 | # Unconditional absolute jump to register with link. 964 | :jal rd is op_31_4=0x1f80000 & rd { 965 | r15 = inst_next; 966 | call [rd]; 967 | } 968 | 969 | # Copy the (signed) max of the values of two registers into a register. 970 | :max rd, rs1, rs2 is op_31_12=0x20000 & rs2 & rs1 & rd { rd = rs1; if (rs1 s>= rs2) goto inst_next; rd = rs2; } 971 | 972 | # Copy the (signed) min of the values of two registers into a register. 973 | :min rd, rs1, rs2 is op_31_12=0x20001 & rs2 & rs1 & rd { rd = rs1; if (rs1 s<= rs2) goto inst_next; rd = rs2; } 974 | 975 | # ADD a register with a register and an immediate. 976 | :add rd, rs1, #imm is op_31_13=0b0010000000000000001 & imm_12_12 & rs2 & rs1 & rd [ 977 | imm = imm_12_12 + 1; 978 | ] { 979 | rd = rs1 + rs2 + imm; 980 | } 981 | 982 | # Max of two 16-bit integers in two registers. 983 | :maxd rd, rs1, rs2 is op_31_12=0x20005 & rs2 & rs1 & rd { 984 | local rs1_lo:2 = rs1:2; 985 | local rs1_hi:2 = rs1(2); 986 | local rs2_lo:2 = rs2:2; 987 | local rs2_hi:2 = rs2(2); 988 | 989 | # Find the signed maximum of the lower halves of rs1 and rs2. 990 | if (rs1_lo s> rs2_lo) goto ; 991 | rd = rs2 & 0xffff; 992 | goto ; 993 | 994 | rd = rs1 & 0xffff; 995 | 996 | 997 | # Find the signed maximum of the upper halves of rs1 and rs2. 998 | if (rs1_hi s> rs2_hi) goto ; 999 | rd = rd | (rs2 & 0xffff0000); 1000 | goto ; 1001 | 1002 | rd = rd | (rs1 & 0xffff0000); 1003 | 1004 | } 1005 | 1006 | # Min of two 16-bit integers in two registers. 1007 | :mind rd, rs1, rs2 is op_31_12=0x20007 & rs2 & rs1 & rd { 1008 | local rs1_lo:2 = rs1:2; 1009 | local rs1_hi:2 = rs1(2); 1010 | local rs2_lo:2 = rs2:2; 1011 | local rs2_hi:2 = rs2(2); 1012 | 1013 | # Find the signed minimum of the lower halves of rs1 and rs2. 1014 | if (rs1_lo s< rs2_lo) goto ; 1015 | rd = rs2 & 0xffff; 1016 | goto ; 1017 | 1018 | rd = rs1 & 0xffff; 1019 | 1020 | 1021 | # Find the signed minimum of the upper halves of rs1 and rs2. 1022 | if (rs1_hi s< rs2_hi) goto ; 1023 | rd = rd | (rs2 & 0xffff0000); 1024 | goto ; 1025 | 1026 | rd = rd | (rs1 & 0xffff0000); 1027 | 1028 | } 1029 | 1030 | :osl rd, rs1, rs2, #imm_16_12 is op_31_17=0b001000000000001 & imm_16_12 & rs2 & rs1 & rd unimpl 1031 | 1032 | :rnds rd, rs1, #imm_18_9 is op_31_19=0b0010000000001 & imm_18_9 & op_8_8=0 & rs1 & rd unimpl 1033 | :rndu rd, rs1, #imm_18_9 is op_31_19=0b0010000000001 & imm_18_9 & op_8_8=1 & rs1 & rd unimpl 1034 | 1035 | :fup rd, rs1, #imm_17_13, #imm_12_8 is op_31_18=0b00100000000100 & imm_17_13 & imm_12_8 & rs1 & rd unimpl 1036 | 1037 | :fxtu rd, rs1, #imm_18_14, #imm_13_9 is op_31_19=0b0010000000100 & imm_18_14 & imm_13_9 & op_8_8=0 & rs1 & rd unimpl 1038 | :fxts rd, rs1, #imm_18_14, #imm_13_9 is op_31_19=0b0010000000100 & imm_18_14 & imm_13_9 & op_8_8=1 & rs1 & rd unimpl 1039 | 1040 | :fup rd, #imm_11_4, #imm_21_17, #imm_16_12 is op_31_22=0b0010000000 & imm_21_17 & imm_16_12 & imm_11_4 & rd unimpl 1041 | 1042 | } 1043 | 1044 | 1045 | # Stand-alone 16-bit instructions (unbundled/unpaired only). 1046 | 1047 | with: bundle=0 { 1048 | 1049 | # 16-bit NOP. 1050 | :nop16 is op_15_0=0x8000 {} 1051 | 1052 | # AND an unsigned immediate with a register between r1 and r8 to a register between r1 and r8. 1053 | with: op_15_9=0b1000000 { 1054 | :and16 rn_r1_r8, rm_r1_r8_5_3, #mask is (op_8_6=1 | op_8_6=2 | op_8_6=3 | op_8_6=4) & op_8_6 & rm_r1_r8_5_3 & rn_r1_r8 [ mask = (1 << op_8_6) - 1; ] { rn_r1_r8 = rm_r1_r8_5_3 & mask; } 1055 | :and16 rn_r1_r8, rm_r1_r8_5_3, #mask is op_8_6=5 & rm_r1_r8_5_3 & rn_r1_r8 [ mask = 0xff; ] { rn_r1_r8 = rm_r1_r8_5_3 & mask; } 1056 | :and16 rn_r1_r8, rm_r1_r8_5_3, #mask is op_8_6=6 & rm_r1_r8_5_3 & rn_r1_r8 [ mask = 0xff00; ] { rn_r1_r8 = rm_r1_r8_5_3 & mask; } 1057 | :and16 rn_r1_r8, rm_r1_r8_5_3, #mask is op_8_6=7 & rm_r1_r8_5_3 & rn_r1_r8 [ mask = 0xffff; ] { rn_r1_r8 = rm_r1_r8_5_3 & mask; } 1058 | } 1059 | 1060 | # Shift register left (logical) by an immediate. 1061 | :sll16 rn_r1_r8, rm_r1_r8_5_3, #imm_8_6 is op_15_9=0b1000001 & imm_8_6 & rm_r1_r8_5_3 & rn_r1_r8 { 1062 | rn_r1_r8 = rm_r1_r8_5_3 << imm_8_6; 1063 | } 1064 | 1065 | # ADD two registers. 1066 | :add16 rn_r1_r8, rm_r1_r8_5_3, rm_r1_r8_8_6 is op_15_9=0b1000010 & rm_r1_r8_8_6 & rm_r1_r8_5_3 & rn_r1_r8 { rn_r1_r8 = rm_r1_r8_5_3 + rm_r1_r8_8_6; } 1067 | 1068 | # Add a signed immediate to a register. 1069 | :add16 rn, #simm_8_4 is op_15_9=0b1000011 & simm_8_4 & rn { 1070 | rn = rn + simm_8_4; 1071 | } 1072 | 1073 | # ADD two registers. 1074 | :add16 rn, rm is op_15_8=0x88 & rm & rn { rn = rn + rm; } 1075 | 1076 | # SUB two registers. 1077 | :sub16 rn, rm is op_15_8=0x89 & rm & rn { rn = rn - rm; } 1078 | 1079 | # AND two registers. 1080 | :and16 rn, rm is op_15_8=0x8a & rm & rn { rn = rn & rm; } 1081 | 1082 | # OR two registers. 1083 | :or16 rn, rm is op_15_8=0x8b & rm & rn { rn = rn | rm; } 1084 | 1085 | # XOR two registers. 1086 | :xor16 rn, rm is op_15_8=0x8c & rm & rn { rn = rn ^ rm; } 1087 | 1088 | # Count leading zeros. Starting from the most significant bit in rm, count the 1089 | # number of contiguous zero bits and store that count in rn. 1090 | :clz16 rn, rm is op_15_8=0x8d & rm & rn { 1091 | rn = 0; 1092 | if (rm & (1 << 31)) != 0 goto inst_next; 1093 | rn = rn + 1; 1094 | if (rm & (1 << 30)) != 0 goto inst_next; 1095 | rn = rn + 1; 1096 | if (rm & (1 << 29)) != 0 goto inst_next; 1097 | rn = rn + 1; 1098 | if (rm & (1 << 28)) != 0 goto inst_next; 1099 | rn = rn + 1; 1100 | if (rm & (1 << 27)) != 0 goto inst_next; 1101 | rn = rn + 1; 1102 | if (rm & (1 << 26)) != 0 goto inst_next; 1103 | rn = rn + 1; 1104 | if (rm & (1 << 25)) != 0 goto inst_next; 1105 | rn = rn + 1; 1106 | if (rm & (1 << 24)) != 0 goto inst_next; 1107 | rn = rn + 1; 1108 | if (rm & (1 << 23)) != 0 goto inst_next; 1109 | rn = rn + 1; 1110 | if (rm & (1 << 22)) != 0 goto inst_next; 1111 | rn = rn + 1; 1112 | if (rm & (1 << 21)) != 0 goto inst_next; 1113 | rn = rn + 1; 1114 | if (rm & (1 << 20)) != 0 goto inst_next; 1115 | rn = rn + 1; 1116 | if (rm & (1 << 19)) != 0 goto inst_next; 1117 | rn = rn + 1; 1118 | if (rm & (1 << 18)) != 0 goto inst_next; 1119 | rn = rn + 1; 1120 | if (rm & (1 << 17)) != 0 goto inst_next; 1121 | rn = rn + 1; 1122 | if (rm & (1 << 16)) != 0 goto inst_next; 1123 | rn = rn + 1; 1124 | if (rm & (1 << 15)) != 0 goto inst_next; 1125 | rn = rn + 1; 1126 | if (rm & (1 << 14)) != 0 goto inst_next; 1127 | rn = rn + 1; 1128 | if (rm & (1 << 13)) != 0 goto inst_next; 1129 | rn = rn + 1; 1130 | if (rm & (1 << 12)) != 0 goto inst_next; 1131 | rn = rn + 1; 1132 | if (rm & (1 << 11)) != 0 goto inst_next; 1133 | rn = rn + 1; 1134 | if (rm & (1 << 10)) != 0 goto inst_next; 1135 | rn = rn + 1; 1136 | if (rm & (1 << 9)) != 0 goto inst_next; 1137 | rn = rn + 1; 1138 | if (rm & (1 << 8)) != 0 goto inst_next; 1139 | rn = rn + 1; 1140 | if (rm & (1 << 7)) != 0 goto inst_next; 1141 | rn = rn + 1; 1142 | if (rm & (1 << 6)) != 0 goto inst_next; 1143 | rn = rn + 1; 1144 | if (rm & (1 << 5)) != 0 goto inst_next; 1145 | rn = rn + 1; 1146 | if (rm & (1 << 4)) != 0 goto inst_next; 1147 | rn = rn + 1; 1148 | if (rm & (1 << 3)) != 0 goto inst_next; 1149 | rn = rn + 1; 1150 | if (rm & (1 << 2)) != 0 goto inst_next; 1151 | rn = rn + 1; 1152 | if (rm & (1 << 1)) != 0 goto inst_next; 1153 | rn = rn + 1; 1154 | if (rm & (1 << 0)) != 0 goto inst_next; 1155 | rn = rn + 1; 1156 | } 1157 | 1158 | # Shift register right (arithmetic) by an immediate. 1159 | :sra16 rn, #imm_7_4 is op_15_8=0x90 & imm_7_4 & rn { 1160 | rn = rn s>> imm_7_4; 1161 | } 1162 | 1163 | # Shift register left by an immediate. 1164 | :sll16 rn, #imm_7_4 is op_15_8=0x91 & imm_7_4 & rn { 1165 | rn = rn << imm_7_4; 1166 | } 1167 | 1168 | # Add an unsigned immediate to the stack pointer. 1169 | :addsp16 r14, #offset is r14 & op_15_8=0x92 & imm_7_0 [ 1170 | offset = imm_7_0 * 4; 1171 | ] { 1172 | r14 = r14 + offset; 1173 | } 1174 | 1175 | # Move data from register to register. 1176 | :mv16 rn, rm is op_15_8=0x93 & rm & rn { 1177 | rn = rm; 1178 | } 1179 | 1180 | # Add an unsigned immediate to the stack pointer and store it in a register. 1181 | :add16 rn, r14, #offset is r14 & op_15_10=0b100101 & imm_9_4 & rn [ 1182 | offset = -0x100 + imm_9_4 * 4; 1183 | ] { 1184 | rn = r14 + offset; 1185 | } 1186 | 1187 | # Move immediate to register. 1188 | :mv16 rn, #simm_10_4 is op_15_11=0b10011 & simm_10_4 & rn { 1189 | rn = simm_10_4; 1190 | } 1191 | 1192 | :xtd16 rn_r1_r8, rm_r1_r8_5_3, #const is op_15_7=0b110000000 & imm_6_6 & rm_r1_r8_5_3 & rn_r1_r8 [ const = 8 + 8 * imm_6_6; ] unimpl 1193 | 1194 | :mv16 a0l, rn_r1_r8 is op_15_3=0b1100000010000 & rn_r1_r8 & a0l { a0l = rn_r1_r8; } 1195 | :mv16 a0h, rn_r1_r8 is op_15_3=0b1100000010001 & rn_r1_r8 & a0h { a0h = rn_r1_r8; } 1196 | :mv16 rn_r1_r8, a0l is op_15_3=0b1100000010010 & rn_r1_r8 & a0l { rn_r1_r8 = a0l; } 1197 | :mv16 rn_r1_r8, a0h is op_15_3=0b1100000010011 & rn_r1_r8 & a0h { rn_r1_r8 = a0h; } 1198 | 1199 | :mac16 rn, rm is op_15_8=0xc1 & rm & rn { a0 = a0 + (sext(rn) * sext(rm)); } 1200 | 1201 | :maxv16 rn, rm is op_15_8=0xc2 & rm & rn { local rm_shift = rm << 16; local lo:2 = rm_shift(2); local hi:2 = rm(2); rn = sext(lo); if (lo s>= hi) goto inst_next; rn = sext(hi); } 1202 | :minv16 rn, rm is op_15_8=0xc3 & rm & rn { local rm_shift = rm << 16; local lo:2 = rm_shift(2); local hi:2 = rm(2); rn = sext(lo); if (lo s<= hi) goto inst_next; rn = sext(hi); } 1203 | 1204 | :max16 rn, rm is op_15_8=0xc4 & rm & rn { if (rn s>= rm) goto inst_next; rn = rm; } 1205 | :min16 rn, rm is op_15_8=0xc5 & rm & rn { if (rn s<= rm) goto inst_next; rn = rm; } 1206 | 1207 | :maxd16 rn, rm is op_15_8=0xc6 & rm & rn unimpl 1208 | :mind16 rn, rm is op_15_8=0xc7 & rm & rn unimpl 1209 | 1210 | :mv16 csrn, rm_r1_r8_6_4 is op_15_7=0b110010000 & rm_r1_r8_6_4 & csrn { csrn = rm_r1_r8_6_4; } 1211 | :mv16 rn_r1_r8, csrm_6_3 is op_15_7=0b110010001 & csrm_6_3 & rn_r1_r8 { rn_r1_r8 = csrm_6_3; } 1212 | 1213 | :bset16 rn_r1_r8, #imm_6_3 is op_15_7=0b110010010 & imm_6_3 & rn_r1_r8 unimpl 1214 | :bclr16 rn_r1_r8, #imm_6_3 is op_15_7=0b110010011 & imm_6_3 & rn_r1_r8 unimpl 1215 | :btgl16 rn_r1_r8, #imm_6_3 is op_15_7=0b110010100 & imm_6_3 & rn_r1_r8 unimpl 1216 | 1217 | :rnds16 rn_r1_r8, rm_r1_r8_5_3, rm_r1_r8_8_6 is op_15_9=0b1100110 & rm_r1_r8_8_6 & rm_r1_r8_5_3 & rn_r1_r8 unimpl 1218 | :rndu16 rn_r1_r8, rm_r1_r8_5_3, rm_r1_r8_8_6 is op_15_9=0b1100111 & rm_r1_r8_8_6 & rm_r1_r8_5_3 & rn_r1_r8 unimpl 1219 | 1220 | :osl16 rn_r1_r8, rm_r1_r8_5_3, #imm_9_6 is op_15_10=0b110100 & imm_9_6 & rm_r1_r8_5_3 & rn_r1_r8 unimpl 1221 | 1222 | } 1223 | 1224 | 1225 | # 16-bit instructions that may either stand alone or be the second instruction in a bundle. 1226 | 1227 | with: (bundle=0 & op_15_15=1) | bundle=1 { 1228 | 1229 | # Another 16-bit NOP. 1230 | :nop16.l is op_14_0=0x2000 {} 1231 | 1232 | # Unconditional absolute jump to register 15 (link register), delayed by 2. 1233 | # FIXME: See below. 1234 | :j16.d2 rn is op_14_4=0x202 & rn & rn=15 { 1235 | delayslot(4); 1236 | return [rn]; 1237 | } 1238 | 1239 | # Unconditional absolute jump to register, delayed by 2. 1240 | # FIXME: The "delayslot(4)" statement only covers half of the possibilities 1241 | # (a 2-byte instruction followed by either a 2-byte or 4-byte instruction), 1242 | # and does not handle the case where a 4-byte instruction is followed by 1243 | # either a 2-byte or 4-byte instruction. 1244 | :j16.d2 rn is op_14_4=0x202 & rn { 1245 | delayslot(4); 1246 | goto [rn]; 1247 | } 1248 | 1249 | # Unconditional absolute jump to register 15 (link register). 1250 | :j16 rn is op_14_4=0x203 & rn & rn=15 { 1251 | return [rn]; 1252 | } 1253 | 1254 | # Unconditional absolute jump to register. 1255 | :j16 rn is op_14_4=0x203 & rn { 1256 | goto [rn]; 1257 | } 1258 | 1259 | # Unconditional relative jump by immediate, delayed by 1. 1260 | :j16.d1 #jump_dest is op_14_7=0b01000010 & simm_6_0 [ 1261 | jump_dest = inst_start + simm_6_0 * 2; 1262 | ] { 1263 | delayslot(2); 1264 | goto [jump_dest:4]; 1265 | } 1266 | 1267 | # Unconditional relative jump by immediate. 1268 | :j16 #jump_dest is op_14_7=0b01000011 & simm_6_0 [ 1269 | jump_dest = inst_start + simm_6_0 * 2; 1270 | ] { 1271 | goto [jump_dest:4]; 1272 | } 1273 | 1274 | # Load sign-extended half word relative to a register between r1 and r8. 1275 | :lh16 rn_r1_r8, #offset^(rm_r1_r8_5_3) is op_14_6=0b010001000 & rm_r1_r8_5_3 & rn_r1_r8 [ 1276 | offset = 0; 1277 | ] { 1278 | rn_r1_r8 = sext(*[DMEM]:2 (rm_r1_r8_5_3)); 1279 | } 1280 | 1281 | # Load zero-extended half word relative to a register between r1 and r8. 1282 | :lhu16 rn_r1_r8, #offset^(rm_r1_r8_5_3) is op_14_6=0b010001001 & rm_r1_r8_5_3 & rn_r1_r8 [ 1283 | offset = 0; 1284 | ] { 1285 | rn_r1_r8 = zext(*[DMEM]:2 (rm_r1_r8_5_3)); 1286 | } 1287 | 1288 | # Load sign-extended byte relative to a register between r1 and r8. 1289 | :lb16 rn_r1_r8, #offset^(rm_r1_r8_5_3) is op_14_6=0b010001010 & rm_r1_r8_5_3 & rn_r1_r8 [ 1290 | offset = 0; 1291 | ] { 1292 | rn_r1_r8 = sext(*[DMEM]:1 (rm_r1_r8_5_3)); 1293 | } 1294 | 1295 | # Load zero-extended byte relative to a register between r1 and r8. 1296 | :lbu16 rn_r1_r8, #offset^(rm_r1_r8_5_3) is op_14_6=0b010001011 & rm_r1_r8_5_3 & rn_r1_r8 [ 1297 | offset = 0; 1298 | ] { 1299 | rn_r1_r8 = zext(*[DMEM]:1 (rm_r1_r8_5_3)); 1300 | } 1301 | 1302 | # Store half word at an offset relative to a register between r1 and r8. 1303 | :sh16 rn, #offset^(rm_r1_r8_6_4) is op_14_7=0b01000110 & rm_r1_r8_6_4 & rn [ 1304 | offset = 0; 1305 | ] { 1306 | *[DMEM](rm_r1_r8_6_4 + offset) = rn:2; 1307 | } 1308 | 1309 | # Store byte at an offset relative to a register between r1 and r8. 1310 | :sb16 rn, #offset^(rm_r1_r8_6_4) is op_14_7=0b01000111 & rm_r1_r8_6_4 & rn [ 1311 | offset = 0; 1312 | ] { 1313 | *[DMEM](rm_r1_r8_6_4 + offset) = rn:1; 1314 | } 1315 | 1316 | # Load word from an offset relative to the stack pointer. 1317 | :lw16 rn, #offset^(r14) is r14 & op_14_9=0b010010 & imm_8_4 & rn [ 1318 | offset = -0x80 + imm_8_4 * 4; 1319 | ] { 1320 | rn = *[DMEM](r14 + offset); 1321 | } 1322 | 1323 | # Store word at an offset relative to the stack pointer. 1324 | :sw16 rn, #offset^(r14) is r14 & op_14_9=0b010011 & imm_8_4 & rn [ 1325 | offset = -0x80 + imm_8_4 * 4; 1326 | ] { 1327 | *[DMEM](r14 + offset) = rn; 1328 | } 1329 | 1330 | # Load word from an offset relative to a register between r1 and r8. 1331 | :lw16 rn, #offset^(rm_r1_r8_6_4) is op_14_10=0b01010 & imm_9_7 & rm_r1_r8_6_4 & rn [ 1332 | offset = imm_9_7 * 4; 1333 | ] { 1334 | rn = *[DMEM](rm_r1_r8_6_4 + offset); 1335 | } 1336 | 1337 | # Store word at an offset relative to a register between r1 and r8. 1338 | :sw16 rn, #offset^(rm_r1_r8_6_4) is op_14_10=0b01011 & imm_9_7 & rm_r1_r8_6_4 & rn [ 1339 | offset = imm_9_7 * 4; 1340 | ] { 1341 | *[DMEM](rm_r1_r8_6_4 + offset) = rn; 1342 | } 1343 | 1344 | # Load word from an address in a register between r1 and r8, then offset the address in that register. 1345 | # TODO: Confirm the semantics of this instruction on hardware. 1346 | :lw16 rn, (rm_r1_r8_6_4+=#offset) is op_14_10=0b01100 & simm_9_7 & rm_r1_r8_6_4 & rn [ 1347 | offset = simm_9_7 * 4; 1348 | ] { 1349 | rn = *[DMEM](rm_r1_r8_6_4); 1350 | rm_r1_r8_6_4 = rm_r1_r8_6_4 + offset; 1351 | } 1352 | 1353 | # Store word at an address in a register between r1 and r8, then offset the address in that register. 1354 | # TODO: Confirm the semantics of this instruction on hardware. 1355 | :sw16 rn, (rm_r1_r8_6_4+=#offset) is op_14_10=0b01101 & simm_9_7 & rm_r1_r8_6_4 & rn [ 1356 | offset = simm_9_7 * 4; 1357 | ] { 1358 | *[DMEM](rm_r1_r8_6_4) = rn; 1359 | rm_r1_r8_6_4 = rm_r1_r8_6_4 + offset; 1360 | } 1361 | 1362 | # Branch if register equal to zero, delayed by 1. 1363 | :beq16.d1 #zero, rn, #jump_dest is op_14_9=0b011100 & imm_8_4 & rn [ 1364 | zero = 0; 1365 | jump_dest = inst_start + imm_8_4 * 2; 1366 | ] { 1367 | local delayflag = (0 == rn); 1368 | delayslot(2); 1369 | if !delayflag goto inst_next; 1370 | goto [jump_dest:4]; 1371 | } 1372 | 1373 | # Branch if register not equal to zero, delayed by 1. 1374 | :bne16.d1 #zero, rn, #jump_dest is op_14_9=0b011101 & imm_8_4 & rn [ 1375 | zero = 0; 1376 | jump_dest = inst_start + imm_8_4 * 2; 1377 | ] { 1378 | local delayflag = (0 != rn); 1379 | delayslot(2); 1380 | if !delayflag goto inst_next; 1381 | goto [jump_dest:4]; 1382 | } 1383 | 1384 | # Branch if register equal to zero. 1385 | :beq16 #zero, rn, #jump_dest is op_14_9=0b011110 & imm_8_4 & rn [ 1386 | zero = 0; 1387 | jump_dest = inst_start + imm_8_4 * 2; 1388 | ] { 1389 | local flag = (0 == rn); 1390 | if !flag goto inst_next; 1391 | goto [jump_dest:4]; 1392 | } 1393 | 1394 | # Branch if register not equal to zero. 1395 | :bne16 #zero, rn, #jump_dest is op_14_9=0b011111 & imm_8_4 & rn [ 1396 | zero = 0; 1397 | jump_dest = inst_start + imm_8_4 * 2; 1398 | ] { 1399 | local flag = (0 != rn); 1400 | if !flag goto inst_next; 1401 | goto [jump_dest:4]; 1402 | } 1403 | 1404 | # Load sign-extended half word relative to a register between r1 and r8. 1405 | :lh16 rn_r1_r8, #offset^(rm_r1_r8_5_3) is op_14_9=0b110000 & simm_8_6 & rm_r1_r8_5_3 & rn_r1_r8 [ 1406 | offset = simm_8_6 * 2; 1407 | ] { 1408 | rn_r1_r8 = sext(*[DMEM]:2 (rm_r1_r8_5_3 + offset)); 1409 | } 1410 | 1411 | # Load zero-extended half word relative to a register between r1 and r8. 1412 | :lhu16 rn_r1_r8, #offset^(rm_r1_r8_5_3) is op_14_9=0b110001 & simm_8_6 & rm_r1_r8_5_3 & rn_r1_r8 [ 1413 | offset = simm_8_6 * 2; 1414 | ] { 1415 | rn_r1_r8 = zext(*[DMEM]:2 (rm_r1_r8_5_3 + offset)); 1416 | } 1417 | 1418 | # Store half word at an offset relative to a register between r1 and r8. 1419 | :sh16 rn, #offset^(rm_r1_r8_6_4) is op_14_10=0b11001 & simm_9_7 & rm_r1_r8_6_4 & rn [ 1420 | offset = simm_9_7 * 2; 1421 | ] { 1422 | *[DMEM](rm_r1_r8_6_4 + offset) = rn:2; 1423 | } 1424 | 1425 | # Store half word at an address in a register between r1 and r8, then offset the address in that register. 1426 | # TODO: Confirm the semantics of this instruction on hardware. 1427 | :sh16 rm_6_3, (rn_r1_r8+=#offset) is op_14_10=0b11010 & simm_9_7 & rm_6_3 & rn_r1_r8 [ 1428 | offset = simm_9_7 * 2; 1429 | ] { 1430 | *[DMEM](rn_r1_r8) = rm_6_3:2; 1431 | rn_r1_r8 = rn_r1_r8 + offset; 1432 | } 1433 | 1434 | # Load sign-extended half word relative to a register between r1 and r8, then offset the address in that register. 1435 | # TODO: Confirm the semantics of this instruction on hardware. 1436 | :lh16 rn_r1_r8, (rm_r1_r8_5_3+=#offset) is op_14_9=0b110110 & simm_8_6 & rm_r1_r8_5_3 & rn_r1_r8 [ 1437 | offset = simm_8_6 * 2; 1438 | ] { 1439 | rn_r1_r8 = sext(*[DMEM]:2 (rm_r1_r8_5_3)); 1440 | rm_r1_r8_5_3 = rm_r1_r8_5_3 + offset; 1441 | } 1442 | 1443 | # Load zero-extended half word relative to a register between r1 and r8, then offset the address in that register. 1444 | # TODO: Confirm the semantics of this instruction on hardware. 1445 | :lhu16 rn_r1_r8, (rm_r1_r8_5_3+=#offset) is op_14_9=0b110111 & simm_8_6 & rm_r1_r8_5_3 & rn_r1_r8 [ 1446 | offset = simm_8_6 * 2; 1447 | ] { 1448 | rn_r1_r8 = zext(*[DMEM]:2 (rm_r1_r8_5_3)); 1449 | rm_r1_r8_5_3 = rm_r1_r8_5_3 + offset; 1450 | } 1451 | 1452 | # Move data from register to register. 1453 | :mv16.l rn, rm is op_14_8=0x70 & rm & rn { 1454 | rn = rm; 1455 | } 1456 | 1457 | # Store byte at an address in a register between r1 and r8, then offset the address in that register. 1458 | # TODO: Confirm the semantics of this instruction on hardware. 1459 | :sb16 rm_6_3, (rn_r1_r8+=#offset) is op_14_10=0b11110 & simm_9_7 & rm_6_3 & rn_r1_r8 [ 1460 | offset = simm_9_7 * 1; 1461 | ] { 1462 | *[DMEM](rn_r1_r8) = rm_6_3:1; 1463 | rn_r1_r8 = rn_r1_r8 + offset; 1464 | } 1465 | 1466 | # Load sign-extended byte relative to a register between r1 and r8, then offset the address in that register. 1467 | # TODO: Confirm the semantics of this instruction on hardware. 1468 | :lb16 rn_r1_r8, (rm_r1_r8_5_3+=#offset) is op_14_9=0b111110 & simm_8_6 & rm_r1_r8_5_3 & rn_r1_r8 [ 1469 | offset = simm_8_6 * 1; 1470 | ] { 1471 | rn_r1_r8 = sext(*[DMEM]:1 (rm_r1_r8_5_3)); 1472 | rm_r1_r8_5_3 = rm_r1_r8_5_3 + offset; 1473 | } 1474 | 1475 | # Load zero-extended byte relative to a register between r1 and r8, then offset the address in that register. 1476 | # TODO: Confirm the semantics of this instruction on hardware. 1477 | :lbu16 rn_r1_r8, (rm_r1_r8_5_3+=#offset) is op_14_9=0b111111 & simm_8_6 & rm_r1_r8_5_3 & rn_r1_r8 [ 1478 | offset = simm_8_6 * 1; 1479 | ] { 1480 | rn_r1_r8 = zext(*[DMEM]:1 (rm_r1_r8_5_3)); 1481 | rm_r1_r8_5_3 = rm_r1_r8_5_3 + offset; 1482 | } 1483 | 1484 | } 1485 | 1486 | 1487 | # 16-bit instruction bundles/pairs, prefix instructions. 1488 | 1489 | with: bundle=0 { 1490 | 1491 | # 16-bit NOP. 1492 | :nop16 is op_15_0=0x4000 [ bundle = 1; globalset(inst_next, bundle); ] {} 1493 | 1494 | :mv16 rn_odd, rm_6_3 is op_15_7=0b010010011 & rm_6_3 & rn_odd [ 1495 | bundle = 1; 1496 | globalset(inst_next, bundle); 1497 | ] { 1498 | rn_odd = rm_6_3; 1499 | } 1500 | 1501 | # Add stack pointer to immediate and store in register. 1502 | :add16 rn_even, r14, #calc_imm is r14 & op_15_9=0b0100101 & imm_8_3 & rn_even [ 1503 | calc_imm = -0x100 | (imm_8_3 << 2); 1504 | bundle = 1; 1505 | globalset(inst_next, bundle); 1506 | ] { 1507 | rn_even = r14 + calc_imm:4; 1508 | } 1509 | 1510 | } 1511 | 1512 | 1513 | # 16-bit instruction bundles/pairs, postfix instructions. 1514 | 1515 | with: bundle=1 { 1516 | 1517 | } 1518 | 1519 | 1520 | } 1521 | --------------------------------------------------------------------------------