├── 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 |
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 |
--------------------------------------------------------------------------------